feat(worterbuch): implement tap to select

This commit is contained in:
2025-12-01 16:25:18 +01:00
parent 1cc09bb1c0
commit 74e814c4b8
3 changed files with 77 additions and 56 deletions

View File

@@ -0,0 +1,36 @@
//
// SelectableTextView.swift
// WorterBuch
//
// Created by Oliver Hnát on 01.12.2025.
//
import SwiftUI
import UIKit
struct SelectableTextView: UIViewRepresentable {
let text: String
let font: UIFont
let textColor: UIColor
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.isEditable = false
textView.isSelectable = true
textView.isScrollEnabled = false
textView.backgroundColor = .clear
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
textView.textContainer.maximumNumberOfLines = 2
textView.textContainer.lineBreakMode = .byTruncatingTail
textView.dataDetectorTypes = []
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
textView.text = text
textView.font = font
textView.textColor = textColor
}
}

View File

@@ -12,36 +12,49 @@ struct VocabularyFieldCell: View {
let drawing: PKDrawing
let text: String
let onTap: () -> Void
let onLongPress: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 4) {
// Handwriting preview
if !drawing.bounds.isEmpty {
Image(uiImage: drawing.image(from: drawing.bounds, scale: 2.0))
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 60)
.frame(maxWidth: .infinity)
.background(Color(.systemGray6))
} else {
Rectangle()
.fill(Color(.systemGray6))
.frame(height: 60)
.overlay(
Text("Tap to write")
.font(.caption)
.foregroundColor(.secondary)
)
// Handwriting preview - tappable to edit
Group {
if !drawing.bounds.isEmpty {
Image(uiImage: drawing.image(from: drawing.bounds, scale: 2.0))
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 60)
.frame(maxWidth: .infinity)
.background(Color(.systemGray6))
} else {
Rectangle()
.fill(Color(.systemGray6))
.frame(height: 60)
.overlay(
Text("Tap to write")
.font(.caption)
.foregroundColor(.secondary)
)
}
}
.contentShape(Rectangle())
.onTapGesture {
onTap()
}
// Transcribed text
Text(text.isEmpty ? " " : text.lowercased())
.font(.body)
.foregroundColor(.primary)
.lineLimit(2)
// Transcribed text - selectable but not editable
if !text.isEmpty {
SelectableTextView(
text: text.lowercased(),
font: .preferredFont(forTextStyle: .body),
textColor: .label
)
.frame(maxWidth: .infinity, alignment: .leading)
.frame(height: 40)
} else {
Text(" ")
.font(.body)
.frame(maxWidth: .infinity, alignment: .leading)
.frame(height: 40)
}
}
.padding(8)
.background(Color(.systemBackground))
@@ -50,12 +63,5 @@ struct VocabularyFieldCell: View {
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray.opacity(0.2), lineWidth: 1)
)
.contentShape(Rectangle())
.onTapGesture {
onTap()
}
.onLongPressGesture {
onLongPress()
}
}
}

View File

@@ -85,13 +85,11 @@ struct VocabularyGridView: View {
entry: entry,
onSelectField: { fieldType in
openFieldEditor(for: entry, fieldType: fieldType)
},
onLongPress: { fieldType in
showDefinition(for: entry, fieldType: fieldType)
}
)
.listRowInsets(EdgeInsets(top: 6, leading: 12, bottom: 6, trailing: 12))
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
Button(role: .destructive) {
deleteEntry(entry)
@@ -102,6 +100,7 @@ struct VocabularyGridView: View {
}
}
.listStyle(.plain)
.environment(\.defaultMinListRowHeight, 0)
}
.navigationTitle("Wörterbuch")
.toolbar {
@@ -201,28 +200,11 @@ struct VocabularyGridView: View {
print("Error saving context: \(nsError), \(nsError.userInfo)")
}
}
private func showDefinition(for entry: VocabularyEntry, fieldType: FieldType) {
let text: String
switch fieldType {
case .germanWord:
text = entry.germanWordText ?? ""
case .germanExplanation:
text = entry.germanExplanationText ?? ""
case .englishTranslation:
text = entry.englishTranslationText ?? ""
}
if !text.isEmpty {
DictionaryHelper.showDefinition(for: text)
}
}
}
struct VocabularyEntryRow: View {
@ObservedObject var entry: VocabularyEntry
let onSelectField: (FieldType) -> Void
let onLongPress: (FieldType) -> Void
var body: some View {
HStack(spacing: 12) {
@@ -230,8 +212,7 @@ struct VocabularyEntryRow: View {
VocabularyFieldCell(
drawing: entry.germanWordPKDrawing,
text: entry.germanWordText ?? "",
onTap: { onSelectField(.germanWord) },
onLongPress: { onLongPress(.germanWord) }
onTap: { onSelectField(.germanWord) }
)
.frame(maxWidth: .infinity)
@@ -239,8 +220,7 @@ struct VocabularyEntryRow: View {
VocabularyFieldCell(
drawing: entry.germanExplanationPKDrawing,
text: entry.germanExplanationText ?? "",
onTap: { onSelectField(.germanExplanation) },
onLongPress: { onLongPress(.germanExplanation) }
onTap: { onSelectField(.germanExplanation) }
)
.frame(maxWidth: .infinity)
@@ -248,8 +228,7 @@ struct VocabularyEntryRow: View {
VocabularyFieldCell(
drawing: entry.englishTranslationPKDrawing,
text: entry.englishTranslationText ?? "",
onTap: { onSelectField(.englishTranslation) },
onLongPress: { onLongPress(.englishTranslation) }
onTap: { onSelectField(.englishTranslation) }
)
.frame(maxWidth: .infinity)
}