Compare commits

...

2 Commits

Author SHA1 Message Date
Shadowfacts 863867c522
Add logging in to additional accounts and switching accounts via Preferences
See #16
2020-01-18 22:45:06 -05:00
Shadowfacts 08c84688cf
Change recommended instance selector to store categories as strings
instead of enum

Additional categories can be added, which would cause a crash when
decoding.
As the category isn't used for anything, storing it as an enum value is
not necessary.
2020-01-18 22:42:20 -05:00
7 changed files with 84 additions and 36 deletions

View File

@ -51,7 +51,7 @@ public extension InstanceSelector {
public let description: String public let description: String
public let proxiedThumbnailURL: URL public let proxiedThumbnailURL: URL
public let language: String public let language: String
public let category: Category public let category: String
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case domain case domain
@ -62,20 +62,3 @@ public extension InstanceSelector {
} }
} }
} }
public extension InstanceSelector {
enum Category: String, Codable {
// source: https://source.joinmastodon.org/mastodon/joinmastodon/blob/master/src/Wizard.js#L108
case general
case regional
case art
case journalism
case activism
case lgbt
case games
case tech
case adult
case furry
case food
}
}

View File

@ -7,8 +7,9 @@
// //
import Foundation import Foundation
import Combine
class LocalData { class LocalData: ObservableObject {
static let shared = LocalData() static let shared = LocalData()
@ -52,6 +53,7 @@ class LocalData {
} }
} }
set { set {
objectWillChange.send()
let array = newValue.map { (info) in let array = newValue.map { (info) in
return [ return [
"instanceURL": info.instanceURL.absoluteString, "instanceURL": info.instanceURL.absoluteString,
@ -71,6 +73,7 @@ class LocalData {
return defaults.string(forKey: mostRecentAccountKey) return defaults.string(forKey: mostRecentAccountKey)
} }
set { set {
objectWillChange.send()
defaults.set(newValue, forKey: mostRecentAccountKey) defaults.set(newValue, forKey: mostRecentAccountKey)
} }
} }

View File

@ -13,8 +13,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow? var window: UIWindow?
// let mastodonController = MastodonController.shared
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
@ -111,6 +109,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
DraftsManager.save() DraftsManager.save()
} }
func activateAccount(_ account: LocalData.UserAccountInfo) {
LocalData.shared.mostRecentAccount = account.accessToken
window!.windowScene!.session.mastodonController = MastodonController.getForAccount(account)
showAppUI()
}
func showAppUI() { func showAppUI() {
let mastodonController = window!.windowScene!.session.mastodonController! let mastodonController = window!.windowScene!.session.mastodonController!
mastodonController.getOwnAccount() mastodonController.getOwnAccount()
@ -138,8 +142,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
extension SceneDelegate: OnboardingViewControllerDelegate { extension SceneDelegate: OnboardingViewControllerDelegate {
func didFinishOnboarding(account: LocalData.UserAccountInfo) { func didFinishOnboarding(account: LocalData.UserAccountInfo) {
LocalData.shared.mostRecentAccount = account.accessToken activateAccount(account)
window!.windowScene!.session.mastodonController = MastodonController.getForAccount(account)
showAppUI()
} }
} }

View File

@ -12,7 +12,7 @@ import SwiftUI
class PreferencesNavigationController: UINavigationController { class PreferencesNavigationController: UINavigationController {
init(mastodonController: MastodonController) { init(mastodonController: MastodonController) {
let view = PreferencesView(currentAccount: mastodonController.accountInfo!) let view = PreferencesView()
let hostingController = UIHostingController(rootView: view) let hostingController = UIHostingController(rootView: view)
super.init(rootViewController: hostingController) super.init(rootViewController: hostingController)
hostingController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(donePressed)) hostingController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(donePressed))
@ -22,6 +22,13 @@ class PreferencesNavigationController: UINavigationController {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(showAddAccount), name: .addAccount, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(activateAccount(_:)), name: .activateAccount, object: nil)
}
override func viewWillDisappear(_ animated: Bool) { override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
@ -33,4 +40,34 @@ class PreferencesNavigationController: UINavigationController {
dismiss(animated: true) dismiss(animated: true)
} }
@objc func showAddAccount() {
let onboardingController = OnboardingViewController()
onboardingController.onboardingDelegate = self
onboardingController.instanceSelector.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelAddAccount))
show(onboardingController, sender: self)
}
@objc func cancelAddAccount() {
dismiss(animated: true)
}
@objc func activateAccount(_ notification: Notification) {
let account = notification.userInfo!["account"] as! LocalData.UserAccountInfo
let sceneDelegate = self.view.window!.windowScene!.delegate as! SceneDelegate
dismiss(animated: true) {
sceneDelegate.activateAccount(account)
}
}
}
extension Notification.Name {
static let addAccount = Notification.Name("Tusker.addAccount")
static let activateAccount = Notification.Name("Tusker.activateAccount")
}
extension PreferencesNavigationController: OnboardingViewControllerDelegate {
func didFinishOnboarding(account: LocalData.UserAccountInfo) {
LocalData.shared.mostRecentAccount = account.accessToken
}
} }

View File

@ -8,7 +8,7 @@
import SwiftUI import SwiftUI
struct PreferencesView: View { struct PreferencesView: View {
var currentAccount: LocalData.UserAccountInfo @ObservedObject var localData = LocalData.shared
@State private var showingLogoutConfirmation = false @State private var showingLogoutConfirmation = false
var body: some View { var body: some View {
@ -16,14 +16,37 @@ struct PreferencesView : View {
// NavigationView { // NavigationView {
List { List {
Section { Section {
ForEach(localData.accounts, id: \.accessToken) { (account) in
Button(action: {
NotificationCenter.default.post(name: .activateAccount, object: nil, userInfo: ["account": account])
}) {
HStack {
Text(account.username)
.foregroundColor(.primary)
Spacer()
if account.accessToken == self.localData.mostRecentAccount {
Image(systemName: "checkmark")
.renderingMode(.template)
.foregroundColor(.secondary)
}
}
}
}
Button(action: {
NotificationCenter.default.post(name: .addAccount, object: nil)
}) {
Text("Add Account...")
}
if localData.mostRecentAccount != nil {
Button(action: { Button(action: {
self.showingLogoutConfirmation = true self.showingLogoutConfirmation = true
}) { }) {
Text("Logout") Text("Logout from current")
}.alert(isPresented: $showingLogoutConfirmation) { }.alert(isPresented: $showingLogoutConfirmation) {
Alert(title: Text("Are you sure you want to logout?"), message: nil, primaryButton: .destructive(Text("Logout"), action: self.logoutPressed), secondaryButton: .cancel()) Alert(title: Text("Are you sure you want to logout?"), message: nil, primaryButton: .destructive(Text("Logout"), action: self.logoutPressed), secondaryButton: .cancel())
} }
} }
}
Section { Section {
NavigationLink(destination: AppearancePrefsView()) { NavigationLink(destination: AppearancePrefsView()) {
@ -50,7 +73,8 @@ struct PreferencesView : View {
} }
func logoutPressed() { func logoutPressed() {
LocalData.shared.removeAccount(currentAccount) // LocalData.shared.removeAccount(currentAccount)
localData.removeAccount(localData.getMostRecentAccount()!)
NotificationCenter.default.post(name: .userLoggedOut, object: nil) NotificationCenter.default.post(name: .userLoggedOut, object: nil)
} }
} }
@ -58,8 +82,7 @@ struct PreferencesView : View {
#if DEBUG #if DEBUG
struct PreferencesView_Previews : PreviewProvider { struct PreferencesView_Previews : PreviewProvider {
static var previews: some View { static var previews: some View {
let account = LocalData.UserAccountInfo(instanceURL: URL(string: "https://mastodon.social")!, clientID: "clientID", clientSecret: "clientSecret", username: "example", accessToken: "accessToken") return PreferencesView()
return PreferencesView(currentAccount: account)
} }
} }
#endif #endif

View File

@ -128,7 +128,7 @@ class ProfileTableViewController: EnhancedTableViewController {
} }
@objc func updateUIForPreferences() { @objc func updateUIForPreferences() {
guard let account = mastodonController.cache.account(for: accountID) else { fatalError("Missing cached account \(accountID!)") } guard let accountID = accountID, let account = mastodonController.cache.account(for: accountID) else { return }
navigationItem.title = account.realDisplayName navigationItem.title = account.realDisplayName
} }

View File

@ -36,7 +36,7 @@ class InstanceTableViewCell: UITableViewCell {
self.instance = nil self.instance = nil
domainLabel.text = instance.domain domainLabel.text = instance.domain
adultLabel.isHidden = instance.category != .adult adultLabel.isHidden = instance.category != "adult"
descriptionTextView.setTextFromHtml(instance.description) descriptionTextView.setTextFromHtml(instance.description)
updateThumbnail(url: instance.proxiedThumbnailURL) updateThumbnail(url: instance.proxiedThumbnailURL)
} }