From fdc403d39f92220ddc0d311adb56cff877564367 Mon Sep 17 00:00:00 2001 From: Matte23 Date: Tue, 15 Dec 2020 09:23:36 +0100 Subject: [PATCH] Add TabView --- .../circolapp.xcodeproj/project.pbxproj | 30 +++++++- .../circolapp/View/CircularList.swift | 49 +++++++++++++ .../circolapp/View/ContentView.swift | 56 +++++---------- .../circolapp/View/FavouritesList.swift | 49 +++++++++++++ .../circolapp/View/RemindersList.swift | 49 +++++++++++++ .../{ => ViewModel}/CircularViewModel.swift | 37 +--------- .../ViewModel/FavouritesViewModel.swift | 69 +++++++++++++++++++ .../ViewModel/RemindersViewModel.swift | 69 +++++++++++++++++++ 8 files changed, 334 insertions(+), 74 deletions(-) create mode 100644 ios/circolapp/circolapp/View/CircularList.swift create mode 100644 ios/circolapp/circolapp/View/FavouritesList.swift create mode 100644 ios/circolapp/circolapp/View/RemindersList.swift rename ios/circolapp/circolapp/{ => ViewModel}/CircularViewModel.swift (65%) create mode 100644 ios/circolapp/circolapp/ViewModel/FavouritesViewModel.swift create mode 100644 ios/circolapp/circolapp/ViewModel/RemindersViewModel.swift diff --git a/ios/circolapp/circolapp.xcodeproj/project.pbxproj b/ios/circolapp/circolapp.xcodeproj/project.pbxproj index 31774fa..0e9aa50 100644 --- a/ios/circolapp/circolapp.xcodeproj/project.pbxproj +++ b/ios/circolapp/circolapp.xcodeproj/project.pbxproj @@ -10,6 +10,11 @@ 9512D3C1257AB4F60023C3A1 /* NewReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9512D3C0257AB4F60023C3A1 /* NewReminderView.swift */; }; 952DEDDF2576F8DC001DF85D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952DEDDE2576F8DC001DF85D /* SceneDelegate.swift */; }; 9547205B2573B688005AA401 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 9547205A2573B688005AA401 /* Settings.bundle */; }; + 954AF8F62588A5C300666D0C /* CircularList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954AF8F52588A5C300666D0C /* CircularList.swift */; }; + 954AF8F82588A5CF00666D0C /* FavouritesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954AF8F72588A5CF00666D0C /* FavouritesList.swift */; }; + 954AF8FA2588A5DD00666D0C /* RemindersList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954AF8F92588A5DD00666D0C /* RemindersList.swift */; }; + 954AF8FD2588A61000666D0C /* FavouritesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954AF8FC2588A61000666D0C /* FavouritesViewModel.swift */; }; + 954AF8FF2588A61B00666D0C /* RemindersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954AF8FE2588A61B00666D0C /* RemindersViewModel.swift */; }; 954E68352574E3890034EBA8 /* iOSServerApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954E68342574E3890034EBA8 /* iOSServerApi.swift */; }; 954E683D2574ED9E0034EBA8 /* UserDefaultsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954E683C2574ED9E0034EBA8 /* UserDefaultsExtensions.swift */; }; 9553DB09257173ED006AE167 /* iOSRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9553DB08257173ED006AE167 /* iOSRepository.swift */; }; @@ -49,6 +54,11 @@ 952C5954255C57650018C010 /* shared.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = shared.framework; path = "../../shared/build/xcode-frameworks/shared.framework"; sourceTree = ""; }; 952DEDDE2576F8DC001DF85D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 9547205A2573B688005AA401 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; + 954AF8F52588A5C300666D0C /* CircularList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularList.swift; sourceTree = ""; }; + 954AF8F72588A5CF00666D0C /* FavouritesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavouritesList.swift; sourceTree = ""; }; + 954AF8F92588A5DD00666D0C /* RemindersList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersList.swift; sourceTree = ""; }; + 954AF8FC2588A61000666D0C /* FavouritesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavouritesViewModel.swift; sourceTree = ""; }; + 954AF8FE2588A61B00666D0C /* RemindersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemindersViewModel.swift; sourceTree = ""; }; 954E68342574E3890034EBA8 /* iOSServerApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSServerApi.swift; sourceTree = ""; }; 954E683C2574ED9E0034EBA8 /* UserDefaultsExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsExtensions.swift; sourceTree = ""; }; 9553DB08257173ED006AE167 /* iOSRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSRepository.swift; sourceTree = ""; }; @@ -99,6 +109,16 @@ name = Frameworks; sourceTree = ""; }; + 954AF8FB2588A5F100666D0C /* ViewModel */ = { + isa = PBXGroup; + children = ( + 95C46A50255D3A34007A75E5 /* CircularViewModel.swift */, + 954AF8FC2588A61000666D0C /* FavouritesViewModel.swift */, + 954AF8FE2588A61B00666D0C /* RemindersViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; 95906F45257505770060F5D0 /* View */ = { isa = PBXGroup; children = ( @@ -109,6 +129,9 @@ 955B7A0D257D098C0091B1F9 /* SearchBar.swift */, 955B7A0F257D10A70091B1F9 /* ViewControllerResolver.swift */, 9554BDB7257E498F00D8925B /* OnboardingView.swift */, + 954AF8F52588A5C300666D0C /* CircularList.swift */, + 954AF8F72588A5CF00666D0C /* FavouritesList.swift */, + 954AF8F92588A5DD00666D0C /* RemindersList.swift */, ); path = View; sourceTree = ""; @@ -146,9 +169,9 @@ 959B531E25764726009AD895 /* circolapp.entitlements */, 95906F46257506050060F5D0 /* Model */, 95906F45257505770060F5D0 /* View */, + 954AF8FB2588A5F100666D0C /* ViewModel */, 95CA31AF255C1EDE00AC095B /* AppDelegate.swift */, 952DEDDE2576F8DC001DF85D /* SceneDelegate.swift */, - 95C46A50255D3A34007A75E5 /* CircularViewModel.swift */, 954E683C2574ED9E0034EBA8 /* UserDefaultsExtensions.swift */, 95CA31B8255C1EE000AC095B /* Info.plist */, 95906F4C257510370060F5D0 /* GoogleService-Info.plist */, @@ -285,10 +308,15 @@ files = ( 9553DB09257173ED006AE167 /* iOSRepository.swift in Sources */, 95CA31C0255C28C300AC095B /* CircularView.swift in Sources */, + 954AF8FF2588A61B00666D0C /* RemindersViewModel.swift in Sources */, 952DEDDF2576F8DC001DF85D /* SceneDelegate.swift in Sources */, + 954AF8FA2588A5DD00666D0C /* RemindersList.swift in Sources */, 95CA31B2255C1EDE00AC095B /* ContentView.swift in Sources */, 955B7A10257D10A70091B1F9 /* ViewControllerResolver.swift in Sources */, 954E68352574E3890034EBA8 /* iOSServerApi.swift in Sources */, + 954AF8F82588A5CF00666D0C /* FavouritesList.swift in Sources */, + 954AF8F62588A5C300666D0C /* CircularList.swift in Sources */, + 954AF8FD2588A61000666D0C /* FavouritesViewModel.swift in Sources */, 95CA31B0255C1EDE00AC095B /* AppDelegate.swift in Sources */, 95BC3BF82572BCF900F24400 /* AttachmentView.swift in Sources */, 9512D3C1257AB4F60023C3A1 /* NewReminderView.swift in Sources */, diff --git a/ios/circolapp/circolapp/View/CircularList.swift b/ios/circolapp/circolapp/View/CircularList.swift new file mode 100644 index 0000000..bc49d5f --- /dev/null +++ b/ios/circolapp/circolapp/View/CircularList.swift @@ -0,0 +1,49 @@ +/* + * Circolapp + * Copyright (C) 2019-2020 Matteo Schiff + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import SwiftUI + +struct CircularList: View { + @ObservedObject var circularViewModel = CircularViewModel(repository: iOSRepository.getCircularRepository()) + @ObservedObject var searchBar: SearchBar = SearchBar(placeholder: "Search circulars") + + var body: some View { + NavigationView { + List(circularViewModel.circulars, id: \.id) { circular in + CircularView(circular: circular) + } + .navigationBarTitle(Text("Circulars"), displayMode: .large) + .addSearchBar(self.searchBar) + .onReceive(searchBar.$text) {query in + self.circularViewModel.search(query: query) + } + .onAppear { + self.circularViewModel.startObservingCirculars() + } + .onDisappear(perform: { + self.circularViewModel.stopObserving() + }) + } + } +} + +struct CircularList_Previews: PreviewProvider { + static var previews: some View { + CircularList() + } +} diff --git a/ios/circolapp/circolapp/View/ContentView.swift b/ios/circolapp/circolapp/View/ContentView.swift index 67c8508..dd44d9c 100644 --- a/ios/circolapp/circolapp/View/ContentView.swift +++ b/ios/circolapp/circolapp/View/ContentView.swift @@ -21,52 +21,32 @@ import UIKit import Shared struct ContentView: View { - @ObservedObject var circularViewModel = CircularViewModel(repository: iOSRepository.getCircularRepository()) - @ObservedObject var searchBar: SearchBar = SearchBar(placeholder: "Search circulars") @State var showOnboarding = !UserDefaults.standard.bool(forKey: "skipOnboarding") var body: some View { - NavigationView { - List(circularViewModel.circulars, id: \.id) { circular in - CircularView(circular: circular) - } - .navigationBarTitle(Text("Circulars"), displayMode: .large) - .addSearchBar(self.searchBar) - .onReceive(searchBar.$text) {query in - self.circularViewModel.search(query: query) - } - .onAppear { - self.circularViewModel.startObservingCirculars() - } - .onDisappear(perform: { - self.circularViewModel.stopObserving() - }) + TabView { + CircularList() + .tabItem { + Image(systemName: "folder.fill") + Text("Circulars") + } + + FavouritesList() + .tabItem { + Image(systemName: "book.fill") + Text("Favourites") + } + + RemindersList() + .tabItem { + Image(systemName: "alarm.fill") + Text("Reminders") + } }.sheet(isPresented: self.$showOnboarding, onDismiss: { UserDefaults.standard.set(true, forKey: "skipOnboarding") }) { OnboardingView() } - - Divider() - HStack(spacing: 50) { - Button(action: { - self.circularViewModel.startObservingCirculars() - }) { - Image(systemName: "folder") - } - - Button(action: { - self.circularViewModel.startObservingFavourites() - }) { - Image(systemName: "book") - } - - Button(action: { - self.circularViewModel.startObservingReminders() - }) { - Image(systemName: "alarm") - } - }.frame(height: 50.0) } } diff --git a/ios/circolapp/circolapp/View/FavouritesList.swift b/ios/circolapp/circolapp/View/FavouritesList.swift new file mode 100644 index 0000000..e36596e --- /dev/null +++ b/ios/circolapp/circolapp/View/FavouritesList.swift @@ -0,0 +1,49 @@ +/* + * Circolapp + * Copyright (C) 2019-2020 Matteo Schiff + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import SwiftUI + +struct FavouritesList: View { + @ObservedObject var favouritesViewModel = FavouritesViewModel(repository: iOSRepository.getCircularRepository()) + @ObservedObject var searchBar: SearchBar = SearchBar(placeholder: "Search circulars") + + var body: some View { + NavigationView { + List(favouritesViewModel.circulars, id: \.id) { circular in + CircularView(circular: circular) + } + .navigationBarTitle(Text("Favourites"), displayMode: .large) + .addSearchBar(self.searchBar) + .onReceive(searchBar.$text) {query in + self.favouritesViewModel.search(query: query) + } + .onAppear { + self.favouritesViewModel.startObservingFavourites() + } + .onDisappear(perform: { + self.favouritesViewModel.stopObserving() + }) + } + } +} + +struct FavouritesList_Previews: PreviewProvider { + static var previews: some View { + FavouritesList() + } +} diff --git a/ios/circolapp/circolapp/View/RemindersList.swift b/ios/circolapp/circolapp/View/RemindersList.swift new file mode 100644 index 0000000..5d7b75c --- /dev/null +++ b/ios/circolapp/circolapp/View/RemindersList.swift @@ -0,0 +1,49 @@ +/* + * Circolapp + * Copyright (C) 2019-2020 Matteo Schiff + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import SwiftUI + +struct RemindersList: View { + @ObservedObject var remindersViewModel = RemindersViewModel(repository: iOSRepository.getCircularRepository()) + @ObservedObject var searchBar: SearchBar = SearchBar(placeholder: "Search circulars") + + var body: some View { + NavigationView { + List(remindersViewModel.circulars, id: \.id) { circular in + CircularView(circular: circular) + } + .navigationBarTitle(Text("Reminders"), displayMode: .large) + .addSearchBar(self.searchBar) + .onReceive(searchBar.$text) {query in + self.remindersViewModel.search(query: query) + } + .onAppear { + self.remindersViewModel.startObservingReminders() + } + .onDisappear(perform: { + self.remindersViewModel.stopObserving() + }) + } + } +} + +struct RemindersList_Previews: PreviewProvider { + static var previews: some View { + RemindersList() + } +} diff --git a/ios/circolapp/circolapp/CircularViewModel.swift b/ios/circolapp/circolapp/ViewModel/CircularViewModel.swift similarity index 65% rename from ios/circolapp/circolapp/CircularViewModel.swift rename to ios/circolapp/circolapp/ViewModel/CircularViewModel.swift index f699dd9..0cffa19 100644 --- a/ios/circolapp/circolapp/CircularViewModel.swift +++ b/ios/circolapp/circolapp/ViewModel/CircularViewModel.swift @@ -25,7 +25,6 @@ class CircularViewModel: ObservableObject { private var circularWatcher: Ktor_ioCloseable? = nil private var userDefaultsObserver: NSKeyValueObservation? = nil private var schoolID = 0 - private var category: Category = .all private let repository: CircularRepository private let key = "school" @@ -59,29 +58,12 @@ class CircularViewModel: ObservableObject { } func startObservingCirculars() { - category = .all stopObserving() circularWatcher = repository.circularDao.getCFlowCirculars(school: Int32(schoolID)).watch { circulars in self.circulars = circulars as! Array; } } - func startObservingFavourites() { - category = .favourites - stopObserving() - circularWatcher = repository.circularDao.getFavouritesC(school: Int32(schoolID)).watch { circulars in - self.circulars = circulars as! Array; - } - } - - func startObservingReminders() { - category = .reminders - stopObserving() - circularWatcher = repository.circularDao.getCFlowReminders(school: Int32(schoolID)).watch { circulars in - self.circulars = circulars as! Array; - } - } - func stopObserving() { circularWatcher?.close() } @@ -90,23 +72,8 @@ class CircularViewModel: ObservableObject { let wrappedQuery = "%" + query + "%" stopObserving() - switch category { - case .all: - circularWatcher = repository.circularDao.searchCircularsC(query: wrappedQuery, school: Int32(schoolID)).watch { circulars in - self.circulars = circulars as! Array; - } - case .favourites: - circularWatcher = repository.circularDao.searchFavouritesC(query: wrappedQuery, school: Int32(schoolID)).watch { circulars in - self.circulars = circulars as! Array; - } - case .reminders: - circularWatcher = repository.circularDao.searchRemindersC(query: wrappedQuery, school: Int32(schoolID)).watch { circulars in - self.circulars = circulars as! Array; - } + circularWatcher = repository.circularDao.searchCircularsC(query: wrappedQuery, school: Int32(schoolID)).watch { circulars in + self.circulars = circulars as! Array; } } } - -enum Category { - case all, favourites, reminders -} diff --git a/ios/circolapp/circolapp/ViewModel/FavouritesViewModel.swift b/ios/circolapp/circolapp/ViewModel/FavouritesViewModel.swift new file mode 100644 index 0000000..6b8d01e --- /dev/null +++ b/ios/circolapp/circolapp/ViewModel/FavouritesViewModel.swift @@ -0,0 +1,69 @@ +/* + * Circolapp + * Copyright (C) 2019-2020 Matteo Schiff + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import Foundation +import Shared + +class FavouritesViewModel: ObservableObject { + @Published var circulars = Array() + + private var circularWatcher: Ktor_ioCloseable? = nil + private var userDefaultsObserver: NSKeyValueObservation? = nil + private var schoolID = 0 + + private let repository: CircularRepository + private let key = "school" + + init(repository: CircularRepository) { + self.repository = repository + + schoolID = UserDefaults.standard.integer(forKey: key) + + userDefaultsObserver = UserDefaults.standard.observe(\.school, options: [.initial, .new], changeHandler: { (defaults, change) in + self.schoolID = change.newValue ?? 0 + + if (self.circularWatcher != nil) { + self.startObservingFavourites() + } + }) + } + + deinit { + userDefaultsObserver?.invalidate() + } + + func startObservingFavourites() { + stopObserving() + circularWatcher = repository.circularDao.getFavouritesC(school: Int32(schoolID)).watch { circulars in + self.circulars = circulars as! Array; + } + } + + func stopObserving() { + circularWatcher?.close() + } + + func search(query: String) { + let wrappedQuery = "%" + query + "%" + + stopObserving() + circularWatcher = repository.circularDao.searchFavouritesC(query: wrappedQuery, school: Int32(schoolID)).watch { circulars in + self.circulars = circulars as! Array; + } + } +} diff --git a/ios/circolapp/circolapp/ViewModel/RemindersViewModel.swift b/ios/circolapp/circolapp/ViewModel/RemindersViewModel.swift new file mode 100644 index 0000000..b888d9a --- /dev/null +++ b/ios/circolapp/circolapp/ViewModel/RemindersViewModel.swift @@ -0,0 +1,69 @@ +/* + * Circolapp + * Copyright (C) 2019-2020 Matteo Schiff + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import Foundation +import Shared + +class RemindersViewModel: ObservableObject { + @Published var circulars = Array() + + private var circularWatcher: Ktor_ioCloseable? = nil + private var userDefaultsObserver: NSKeyValueObservation? = nil + private var schoolID = 0 + + private let repository: CircularRepository + private let key = "school" + + init(repository: CircularRepository) { + self.repository = repository + + schoolID = UserDefaults.standard.integer(forKey: key) + + userDefaultsObserver = UserDefaults.standard.observe(\.school, options: [.initial, .new], changeHandler: { (defaults, change) in + self.schoolID = change.newValue ?? 0 + + if (self.circularWatcher != nil) { + self.startObservingReminders() + } + }) + } + + deinit { + userDefaultsObserver?.invalidate() + } + + func startObservingReminders() { + stopObserving() + circularWatcher = repository.circularDao.getCFlowReminders(school: Int32(schoolID)).watch { circulars in + self.circulars = circulars as! Array; + } + } + + func stopObserving() { + circularWatcher?.close() + } + + func search(query: String) { + let wrappedQuery = "%" + query + "%" + + stopObserving() + circularWatcher = repository.circularDao.searchRemindersC(query: wrappedQuery, school: Int32(schoolID)).watch { circulars in + self.circulars = circulars as! Array; + } + } +}