From 2229b602de7eb877d61f56b16da6e2ab55ffee93 Mon Sep 17 00:00:00 2001 From: david-swift Date: Thu, 21 Mar 2024 14:32:13 +0100 Subject: [PATCH] Design update - Use new dialog widgets - Use navigation views --- Package.swift | 2 +- Sources/Flashcards.swift | 36 +--------- Sources/Model/FlashcardsView.swift | 33 ++-------- Sources/Model/Localized.yml | 12 ++-- Sources/View/ContentView.swift | 61 +++++++++-------- Sources/View/DeleteView.swift | 6 +- Sources/View/EditView.swift | 20 ++---- Sources/View/SetOverview.swift | 95 +++++++++++++++++++-------- Sources/View/ToolbarView.swift | 56 +++++----------- io.github.david_swift.Flashcards.json | 2 +- 10 files changed, 137 insertions(+), 186 deletions(-) diff --git a/Package.swift b/Package.swift index d477410..512d300 100644 --- a/Package.swift +++ b/Package.swift @@ -9,7 +9,7 @@ import PackageDescription let package = Package( name: "Flashcards", dependencies: [ - .package(url: "https://github.com/AparokshaUI/Adwaita", branch: "0.2.3"), + .package(url: "https://github.com/AparokshaUI/Adwaita", branch: "main"), .package(url: "https://github.com/AparokshaUI/Localized", from: "0.2.2") ], targets: [ diff --git a/Sources/Flashcards.swift b/Sources/Flashcards.swift index 0c932c7..f753791 100644 --- a/Sources/Flashcards.swift +++ b/Sources/Flashcards.swift @@ -11,49 +11,15 @@ struct Flashcards: App { @State("sets", folder: "io.github.david_swift.Flashcards", forceUpdates: true) private var sets: [FlashcardsSet] = [] - @State private var copied = Signal() let id = "io.github.david_swift.Flashcards" var app: GTUIApp! var scene: Scene { Window(id: "main") { window in - ContentView(copied: $copied, sets: $sets, app: app, window: window) + ContentView(sets: $sets, app: app, window: window) } .title("Memorize") .quitShortcut() - .overlay { - AboutWindow(id: "about", appName: "Memorize", developer: "david-swift", version: "0.1.5") - .icon(.custom(name: "io.github.david_swift.Flashcards")) - .website(.init(string: "https://github.com/david-swift/Memorize")) - .issues(.init(string: "https://github.com/david-swift/Memorize/issues")) - for (index, set) in sets.enumerated() { - // Import flashcards and add to a set. - Window(id: "import-\(set.id)", open: 0) { window in - ImportView( - set: .init { set } set: { sets[safe: index] = $0 }, - window: window - ) - } - .defaultSize(width: 500, height: 500) - .keyboardShortcut("Escape") { $0.close() } - - // Export a set. - Window(id: "export-\(set.id)", open: 0) { window in - ExportView(copied: $copied, set: set, window: window) - } - .title(Loc.export(title: set.name)) - .defaultSize(width: 500, height: 500) - .keyboardShortcut("Escape") { $0.close() } - - // Delete a set. - Window(id: "delete-\(set.id)", open: 0) { window in - DeleteView(set: set, window: window) { sets = sets.filter { $0.id != set.id } } - } - .defaultSize(width: 450, height: 350) - .resizable(false) - .keyboardShortcut("Escape") { $0.close() } - } - } } } diff --git a/Sources/Model/FlashcardsView.swift b/Sources/Model/FlashcardsView.swift index 2d4eb45..d996413 100644 --- a/Sources/Model/FlashcardsView.swift +++ b/Sources/Model/FlashcardsView.swift @@ -5,16 +5,13 @@ import Adwaita -enum FlashcardsView: ViewSwitcherOption, Codable { +enum FlashcardsView: CustomStringConvertible { - case overview - case study - case test + case study(set: String) + case test(set: String) - var title: String { + var description: String { switch self { - case .overview: - Loc.overview case .study: Loc.studySwitcher case .test: @@ -22,26 +19,4 @@ enum FlashcardsView: ViewSwitcherOption, Codable { } } - var icon: Icon { - switch self { - case .overview: - return .default(icon: .viewReveal) - case .study: - return .default(icon: .mediaPlaybackStart) - case .test: - return .default(icon: .findLocation) - } - } - - init?(title: String) { - switch title { - case Loc.studySwitcher: - self = .study - case Loc.test: - self = .test - default: - self = .overview - } - } - } diff --git a/Sources/Model/Localized.yml b/Sources/Model/Localized.yml index ee8fe63..d7c084c 100644 --- a/Sources/Model/Localized.yml +++ b/Sources/Model/Localized.yml @@ -588,12 +588,6 @@ semicolon: it: Punto e virgola pt_BR: Ponto e vírgula -editSetDescription: - en: Edit the set's content and title - de: Bearbeite den Inhalt und Titel des Sets - it: Modifica il contenuto e il titolo del Set - pt_BR: Editar conteúdo e título do set - createSet: en: Create Set de: Set erstellen @@ -604,3 +598,9 @@ copied: en: Contents copied to clipboard de: Inhalte wurden kopiert it: Contenuto copiato negli appunti + +flashcards(count): + en(count == "1"): 1 flashcard + en: (count) flashcards + de(count == "1"): 1 Karteikarte + de: (count) Karteikarten diff --git a/Sources/View/ContentView.swift b/Sources/View/ContentView.swift index ce8cbc1..02880a0 100644 --- a/Sources/View/ContentView.swift +++ b/Sources/View/ContentView.swift @@ -9,12 +9,10 @@ import Foundation struct ContentView: WindowView { - @Binding var copied: Signal @Binding var sets: [FlashcardsSet] @State("selected-set") private var selectedSet = "" - @State("flashcards-view") - private var flashcardsView: FlashcardsView = .overview + @State private var flashcardsView: NavigationStack = .init() @State private var filter: String? @State private var editMode = false @State("width") @@ -27,23 +25,28 @@ struct ContentView: WindowView { var window: GTUIApplicationWindow var view: Body { - OverlaySplitView(visible: .constant(flashcardsView == .overview && !editMode && !sets.isEmpty)) { - sidebar - } content: { - content - .topToolbar(visible: !editMode || flashcardsView != .overview) { - ToolbarView( - flashcardsView: $flashcardsView, - sets: $sets, - selectedSet: $selectedSet, - filter: $filter, - app: app, - window: window, - addSet: addSet - ).content + NavigationView($flashcardsView, Loc.overview) { view in + Bin() + .child { + switch view { + case let .study(set): + ViewStack(element: set) { _ in + StudyView(set: binding(id: set)) + } + case let .test(set): + TestView(set: binding(id: set)) + } } + .topToolbar { + HeaderBar.empty() + } + } initialView: { + OverlaySplitView(visible: .constant(true)) { + sidebar + } content: { + content + } } - .toast(Loc.copied, signal: copied) } var sidebar: View { @@ -64,12 +67,11 @@ struct ContentView: WindowView { SearchEntry() .placeholderText(Loc.filterSets) .text(.init { filter ?? "" } set: { filter = $0 }) - .focused(.constant(!editMode && flashcardsView == .overview)) + .focused(.constant(filter != nil)) .padding(5, .horizontal.add(.bottom)) } .topToolbar { ToolbarView( - flashcardsView: $flashcardsView, sets: $sets, selectedSet: $selectedSet, filter: $filter, @@ -83,15 +85,8 @@ struct ContentView: WindowView { @ViewBuilder var content: Body { if let index = sets.firstIndex(where: { $0.id == selectedSet }), let set = sets[safe: index] { let binding = Binding { sets[safe: index] ?? .init() } set: { sets[safe: index] = $0 } - switch flashcardsView { - case .overview: - SetOverview(set: binding, editMode: $editMode, app: app, window: window) - case .study: - ViewStack(element: set) { _ in - StudyView(set: binding) - } - case .test: - TestView(set: binding) + SetOverview(set: binding, editMode: $editMode, flashcardsView: $flashcardsView, app: app, window: window) { + sets = sets.filter { $0.id != set.id } } } else if !sets.isEmpty { StatusPage( @@ -129,4 +124,12 @@ struct ContentView: WindowView { selectedSet = newSet.id } + func binding(id: String) -> Binding { + .init { + sets.first { $0.id == id } ?? .init() + } set: { newValue in + sets[safe: sets.firstIndex { $0.id == id }] = newValue + } + } + } diff --git a/Sources/View/DeleteView.swift b/Sources/View/DeleteView.swift index e7d24a4..3e1e279 100644 --- a/Sources/View/DeleteView.swift +++ b/Sources/View/DeleteView.swift @@ -8,8 +8,8 @@ import Adwaita struct DeleteView: View { var set: FlashcardsSet - var window: GTUIWindow var delete: () -> Void + var close: () -> Void var view: Body { ScrollView { @@ -19,12 +19,12 @@ struct DeleteView: View { .topToolbar { HeaderBar(titleButtons: false) { Button(Loc.cancel) { - window.close() + close() } } end: { Button(Loc.delete) { + close() delete() - window.close() } .style("destructive-action") } diff --git a/Sources/View/EditView.swift b/Sources/View/EditView.swift index b475e49..58e54b6 100644 --- a/Sources/View/EditView.swift +++ b/Sources/View/EditView.swift @@ -11,6 +11,7 @@ struct EditView: View { @Binding var editMode: Bool @State private var expanded = false @State private var focusedFront: String? + @State private var importFlashcards = false var app: GTUIApp var window: GTUIWindow @@ -27,20 +28,6 @@ struct EditView: View { .vexpand() .topToolbar { HeaderBar(titleButtons: false) { - ViewStack(element: set) { _ in - HStack { - Button(icon: .default(icon: .userTrash)) { - app.addWindow("delete-\(set.id)", parent: window) - editMode = false - } - .tooltip(Loc.deleteSet) - Button(icon: .custom(name: "io.github.david_swift.Flashcards.share-symbolic")) { - app.addWindow("export-\(set.id)", parent: window) - } - .padding(10, .horizontal) - .tooltip(Loc.exportSet) - } - } } end: { Button(Loc.done) { editMode = false @@ -133,7 +120,10 @@ struct EditView: View { ) { appendFlashcard() } secondary: { - app.addWindow("import-\(set.id)", parent: window) + importFlashcards = true + } + .dialog(visible: $importFlashcards, width: 400, height: 500) { + ImportView(set: $set, window: window) } } diff --git a/Sources/View/SetOverview.swift b/Sources/View/SetOverview.swift index 02eed6c..250bb3a 100644 --- a/Sources/View/SetOverview.swift +++ b/Sources/View/SetOverview.swift @@ -7,49 +7,71 @@ import Adwaita struct SetOverview: View { - @State("tutorial") - private var tutorial = true @Binding var set: FlashcardsSet @Binding var editMode: Bool + @Binding var flashcardsView: NavigationStack + @State private var export = false + @State private var deleteState = false + @State private var copied = Signal() var app: GTUIApp var window: GTUIWindow + var delete: () -> Void var view: Body { ViewStack(element: set) { _ in - if editMode { - VStack { - EditView(set: $set, editMode: $editMode, app: app, window: window) + title + .centerMinSize() + cards + .frame(minHeight: 270) + .valign(.center) + buttons + .centerMinSize() + } + .topToolbar { + HeaderBar { + HStack { + Button(icon: .default(icon: .userTrash)) { + deleteState = true + } + .tooltip(Loc.deleteSet) + Button(icon: .custom(name: "io.github.david_swift.Flashcards.share-symbolic")) { + export = true + } + .tooltip(Loc.exportSet) } - } else { - ScrollView { - title - cards + .modifyContent(VStack.self) { $0.spacing(5) } + } end: { + Button(icon: .default(icon: .documentEdit)) { + editMode = true } + .tooltip(Loc.editSet) } + .titleWidget { } + } + .dialog(visible: $deleteState, title: Loc.deleteTitle(title: set.name), id: "delete", height: 350) { + DeleteView(set: set) { + delete() + } close: { + deleteState = false + } + } + .dialog(visible: $export, title: Loc.export(title: set.name), id: "export", width: 400, height: 400) { + ExportView(copied: $copied, set: set, window: window) } + .dialog(visible: $editMode, id: "edit", width: 700, height: 550) { + EditView(set: $set, editMode: $editMode, app: app, window: window) + } + .toast(Loc.copied, signal: copied) } var title: View { - HStack { - Text(set.name) - .style("title-1") - .padding() - Button(icon: .default(icon: .documentEdit)) { - editMode = true - } - .style("circular") - .tooltip(Loc.editSet) - .padding() - .popover(visible: $tutorial) { - Text(Loc.editSetDescription) - .wrap() - .padding(10, .vertical) - .frame(maxWidth: 150) - Button(Loc.editSet) { - editMode = true - tutorial = false - } + VStack { + HStack { + Text(set.name) + .style("title-1") + .padding() } + Text(Loc.flashcards(count: set.flashcards.count)) } .halign(.center) } @@ -61,7 +83,22 @@ struct SetOverview: View { } .transition(.crossfade) } - .centerMinSize() + } + + var buttons: View { + HStack { + Button(Loc.studySwitcher, icon: .default(icon: .mediaPlaybackStart)) { + flashcardsView.push(.study(set: set.id)) + } + .style("pill") + Button(Loc.test, icon: .default(icon: .emblemDocuments)) { + flashcardsView.push(.test(set: set.id)) + } + .style("pill") + } + .halign(.center) + .modifyContent(VStack.self) { $0.spacing(20) } + .padding(20) } } diff --git a/Sources/View/ToolbarView.swift b/Sources/View/ToolbarView.swift index 809db8b..23029bb 100644 --- a/Sources/View/ToolbarView.swift +++ b/Sources/View/ToolbarView.swift @@ -7,10 +7,10 @@ import Adwaita struct ToolbarView: View { - @Binding var flashcardsView: FlashcardsView @Binding var sets: [FlashcardsSet] @Binding var selectedSet: String @Binding var filter: String? + @State private var about = false var app: GTUIApp var window: GTUIApplicationWindow var addSet: () -> Void @@ -22,31 +22,21 @@ struct ToolbarView: View { } .tooltip(Loc.addSet) } end: { - if flashcardsView == .overview && !sets.isEmpty { - menu - } + menu } .headerBarTitle { Text(Loc.sets) .style("heading") } - } - - @ViewBuilder var content: Body { - HeaderBar.end { - if flashcardsView != .overview || sets.isEmpty { - menu - } - } - .headerBarTitle { - if sets.contains(where: { $0.id == selectedSet }) { - ViewSwitcher(selection: $flashcardsView) - .wideDesign() - .transition(.crossfade) - } else { - [] - } - } + .aboutDialog( + visible: $about, + app: "Memorize", + developer: "david-swift", + version: "0.1.6", + icon: .custom(name: "io.github.david_swift.Flashcards"), + website: .init(string: "https://github.com/david-swift/Memorize"), + issues: .init(string: "https://github.com/david-swift/Memorize/issues") + ) } var menu: View { @@ -62,7 +52,7 @@ struct ToolbarView: View { viewMenu MenuSection { MenuButton(Loc.about, window: false) { - app.addWindow("about", parent: window) + about = true } } } @@ -72,24 +62,14 @@ struct ToolbarView: View { var viewMenu: MenuSection { .init { - Submenu(Loc.viewMenu) { - for (index, view) in FlashcardsView.allCases.enumerated() { - MenuButton(view.title) { - flashcardsView = view - } - .keyboardShortcut("\(index + 1)".alt()) - } - } - if flashcardsView == .overview { - MenuButton(Loc.filter) { - if filter != nil { - filter = nil - } else { - filter = "" - } + MenuButton(Loc.filter) { + if filter != nil { + filter = nil + } else { + filter = "" } - .keyboardShortcut("f".ctrl()) } + .keyboardShortcut("f".ctrl()) } } diff --git a/io.github.david_swift.Flashcards.json b/io.github.david_swift.Flashcards.json index 0a59733..37b6459 100644 --- a/io.github.david_swift.Flashcards.json +++ b/io.github.david_swift.Flashcards.json @@ -1,7 +1,7 @@ { "app-id": "io.github.david_swift.Flashcards", "runtime": "org.gnome.Platform", - "runtime-version": "45", + "runtime-version": "46", "sdk": "org.gnome.Sdk", "sdk-extensions": [ "org.freedesktop.Sdk.Extension.swift5"