feat(worterbuch): implement tap to select
This commit is contained in:
36
WorterBuch/SelectableTextView.swift
Normal file
36
WorterBuch/SelectableTextView.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user