Deleting last of the accounts
This commit is contained in:
parent
77fbe141a8
commit
482eecfd34
|
@ -8,7 +8,7 @@ import Foundation
|
|||
|
||||
public extension PixelfedClient {
|
||||
func readInstanceInformation() async throws -> Instance {
|
||||
let request = try Self.request(for: baseURL, target: Pixelfed.Instances.instance)
|
||||
let request = try Self.request(for: baseURL, target: Pixelfed.Instances.instance, timeoutInterval: 5)
|
||||
return try await downloadJson(Instance.self, request: request)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ public enum PixelfedClientError: Swift.Error {
|
|||
}
|
||||
|
||||
public protocol PixelfedClientProtocol {
|
||||
static func request(for baseURL: URL, target: TargetType, withBearerToken token: String?) throws -> URLRequest
|
||||
static func request(for baseURL: URL, target: TargetType, withBearerToken token: String?, timeoutInterval: Double?) throws -> URLRequest
|
||||
}
|
||||
|
||||
public extension PixelfedClientProtocol {
|
||||
static func request(for baseURL: URL, target: TargetType, withBearerToken token: String? = nil) throws -> URLRequest {
|
||||
static func request(for baseURL: URL, target: TargetType, withBearerToken token: String? = nil, timeoutInterval: Double? = nil) throws -> URLRequest {
|
||||
|
||||
var urlComponents = URLComponents(url: baseURL.appendingPathComponent(target.path), resolvingAgainstBaseURL: false)
|
||||
urlComponents?.queryItems = target.queryItems?.map { URLQueryItem(name: $0.0, value: $0.1) }
|
||||
|
@ -25,6 +25,10 @@ public extension PixelfedClientProtocol {
|
|||
|
||||
var request = URLRequest(url: url)
|
||||
|
||||
if let timeoutInterval {
|
||||
request.timeoutInterval = timeoutInterval
|
||||
}
|
||||
|
||||
target.headers?.forEach { header in
|
||||
request.setValue(header.1, forHTTPHeaderField: header.0)
|
||||
}
|
||||
|
|
|
@ -1035,7 +1035,7 @@
|
|||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 27;
|
||||
CURRENT_PROJECT_VERSION = 28;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = B2U9FEKYP8;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
|
@ -1072,7 +1072,7 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 27;
|
||||
CURRENT_PROJECT_VERSION = 28;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Vernissage/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = B2U9FEKYP8;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
|
|
|
@ -34,9 +34,9 @@ class ApplicationSettingsHandler {
|
|||
}
|
||||
}
|
||||
|
||||
func setAccountAsDefault(accountData: AccountData) {
|
||||
func setAccountAsDefault(accountData: AccountData?) {
|
||||
let defaultSettings = self.getDefaultSettings()
|
||||
defaultSettings.currentAccount = accountData.id
|
||||
defaultSettings.currentAccount = accountData?.id
|
||||
CoreDataHandler.shared.save()
|
||||
}
|
||||
|
||||
|
|
|
@ -70,4 +70,14 @@ public class ApplicationState: ObservableObject {
|
|||
self.statusCharactersReservedPerUrl = ApplicationState.defaults.statusCharactersReservedPerUrl
|
||||
}
|
||||
}
|
||||
|
||||
public func clearApplicationState() {
|
||||
self.account = nil
|
||||
self.lastSeenStatusId = nil
|
||||
self.amountOfNewStatuses = 0
|
||||
|
||||
self.statusMaxCharacters = ApplicationState.defaults.statusMaxCharacters
|
||||
self.statusMaxMediaAttachments = ApplicationState.defaults.statusMaxMediaAttachments
|
||||
self.statusCharactersReservedPerUrl = ApplicationState.defaults.statusCharactersReservedPerUrl
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ public class Client: ObservableObject {
|
|||
|
||||
self.pixelfedClient = PixelfedClient(baseURL: account.serverUrl).getAuthenticated(token: accessToken)
|
||||
}
|
||||
|
||||
func clearAccount() {
|
||||
self.pixelfedClient = nil
|
||||
}
|
||||
}
|
||||
|
||||
extension Client {
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public class AccountModel: ObservableObject {
|
||||
public class AccountModel: ObservableObject, Identifiable {
|
||||
public let id: String
|
||||
public let accessToken: String?
|
||||
public let refreshToken: String?
|
||||
public let acct: String
|
||||
|
@ -20,7 +21,6 @@ public class AccountModel: ObservableObject {
|
|||
public let followersCount: Int32
|
||||
public let followingCount: Int32
|
||||
public let header: URL?
|
||||
public let id: String
|
||||
public let locked: Bool
|
||||
public let note: String?
|
||||
public let serverUrl: URL
|
||||
|
@ -53,3 +53,9 @@ public class AccountModel: ObservableObject {
|
|||
self.lastSeenStatusId = accountData.lastSeenStatusId
|
||||
}
|
||||
}
|
||||
|
||||
extension AccountModel: Equatable {
|
||||
public static func == (lhs: AccountModel, rhs: AccountModel) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,11 @@ struct VernissageApp: App {
|
|||
.onChange(of: applicationState.tintColor) { newValue in
|
||||
self.tintColor = newValue.color()
|
||||
}
|
||||
.onChange(of: applicationState.account) { newValue in
|
||||
if newValue == nil {
|
||||
self.applicationViewMode = .signIn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ struct ComposeView: View {
|
|||
.padding(.horizontal, 8)
|
||||
|
||||
|
||||
TextField("Type what's on your mind", text: $text, axis: .vertical)
|
||||
TextField(self.placeholder(), text: $text, axis: .vertical)
|
||||
.padding(.horizontal, 8)
|
||||
.lineLimit(2...12)
|
||||
.focused($focusedField, equals: .content)
|
||||
|
@ -310,14 +310,31 @@ struct ComposeView: View {
|
|||
Image(systemName: self.place == nil ? "mappin.square" : "mappin.square.fill")
|
||||
}
|
||||
|
||||
Button {
|
||||
self.text.append("#")
|
||||
} label: {
|
||||
Image(systemName: "number")
|
||||
}
|
||||
|
||||
Button {
|
||||
self.text.append("@")
|
||||
} label: {
|
||||
Image(systemName: "at")
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("\(self.applicationState.statusMaxCharacters - text.string.utf16.count)")
|
||||
.foregroundColor(.lightGrayColor)
|
||||
}
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
|
||||
private func placeholder() -> String {
|
||||
self.statusViewModel == nil ? "Attach photography and type what's on your mind" : "Type what's on your mind"
|
||||
}
|
||||
|
||||
private func isPublishButtonDisabled() -> Bool {
|
||||
// Publish always disabled when there is not status text.
|
||||
if self.text.isEmpty {
|
||||
|
|
|
@ -47,7 +47,7 @@ struct SettingsView: View {
|
|||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Close", role: .cancel) {
|
||||
dismiss()
|
||||
self.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,11 @@ struct SettingsView: View {
|
|||
// Change theme of current modal screen (unformtunatelly it's not changed autmatically.
|
||||
self.theme = self.applicationState.theme.colorScheme() ?? self.getSystemColorScheme()
|
||||
}
|
||||
.onChange(of: applicationState.account) { newValue in
|
||||
if newValue == nil {
|
||||
self.dismiss()
|
||||
}
|
||||
}
|
||||
.onChange(of: tipsStore.status) { status in
|
||||
if status == .successful {
|
||||
withAnimation(.spring()) {
|
||||
|
|
|
@ -8,8 +8,15 @@ import SwiftUI
|
|||
|
||||
struct AccountsSectionView: View {
|
||||
@EnvironmentObject var applicationState: ApplicationState
|
||||
@EnvironmentObject var client: Client
|
||||
|
||||
@State private var accounts: [AccountData] = []
|
||||
@State private var accounts: [AccountModel]
|
||||
private var dbAccounts: [AccountData]
|
||||
|
||||
init() {
|
||||
self.dbAccounts = AccountDataHandler.shared.getAccountsData()
|
||||
self.accounts = self.dbAccounts.map({ AccountModel(accountData: $0) })
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Section("Accounts") {
|
||||
|
@ -25,7 +32,7 @@ struct AccountsSectionView: View {
|
|||
.foregroundColor(self.applicationState.tintColor.color())
|
||||
}
|
||||
}
|
||||
.deleteDisabled(self.applicationState.account?.id == account.id)
|
||||
.deleteDisabled(self.deleteDisabled(for: account))
|
||||
}
|
||||
.onDelete(perform: delete)
|
||||
|
||||
|
@ -37,15 +44,39 @@ struct AccountsSectionView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.task {
|
||||
self.accounts = AccountDataHandler.shared.getAccountsData()
|
||||
}
|
||||
}
|
||||
|
||||
func delete(at offsets: IndexSet) {
|
||||
private func deleteDisabled(for account: AccountModel) -> Bool {
|
||||
self.applicationState.account?.id == account.id && self.accounts.count > 1
|
||||
}
|
||||
|
||||
private func delete(at offsets: IndexSet) {
|
||||
let accountsToDelete = offsets.map { self.accounts[$0] }
|
||||
var shouldClearApplicationState = false
|
||||
|
||||
// Delete from database.
|
||||
for account in accountsToDelete {
|
||||
AccountDataHandler.shared.remove(accountData: account)
|
||||
// Check if we are deleting active user.
|
||||
if account.id == self.applicationState.account?.id {
|
||||
shouldClearApplicationState = true
|
||||
}
|
||||
|
||||
if let dbAccount = self.dbAccounts.first(where: {$0.id == account.id }) {
|
||||
AccountDataHandler.shared.remove(accountData: dbAccount)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete from local state.
|
||||
self.accounts.remove(atOffsets: offsets)
|
||||
|
||||
// When we are deleting active user then we have to switch to sing in view.
|
||||
if shouldClearApplicationState {
|
||||
// We have to do this after animation of deleting row is ended.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
ApplicationSettingsHandler.shared.setAccountAsDefault(accountData: nil)
|
||||
self.applicationState.clearApplicationState()
|
||||
self.client.clearAccount()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import SwiftUI
|
|||
import StoreKit
|
||||
|
||||
struct SupportView: View {
|
||||
|
||||
@EnvironmentObject var tipsStore: TipsStore
|
||||
|
||||
var body: some View {
|
||||
|
|
Loading…
Reference in New Issue