Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

profile settings #322

Open
wants to merge 4 commits into
base: matrixcore
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion NioKit/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public class NioAccountStore: ObservableObject {
// MARK: - logout

public func logout(account: NioAccount) async throws {
let userID = await account.userID.FQMXID!
let userID = account.userID.FQMXID!
accounts.removeValue(forKey: userID)

try await account.logout()
Expand Down
2 changes: 1 addition & 1 deletion NioUIKit/Menu/MenuOwnAccountView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct MenuOwnAccountView: View {
VStack(alignment: .leading) {
ForEach(accounts, id: \.userID) { account in
NavigationLink(destination: {
Text("Account")
ProfileSettingsContainerView(account: account)
}) {
MenuAccountPickerAccountView(account: account)
}
Expand Down
176 changes: 176 additions & 0 deletions NioUIKit/ProfileSettings/ProfileSettingsContainerView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//
// ProfileSettingsContainerView.swift
// NioUIKit_iOS
//
// Created by Finn Behrens on 30.03.22.
//

import MatrixClient
import MatrixCore
import NioKit
import SwiftUI

struct ProfileSettingsContainerView: View {
@ObservedObject var account: MatrixAccount
@EnvironmentObject var store: NioAccountStore

@Environment(\.managedObjectContext) var moc
@Environment(\.dismiss) private var dismiss

@State var capabilities = MatrixCapabilities()

@State var task: Task<Void, Never>?

var body: some View {
List {
Section(header: Text("USER SETTINGS")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The heading should upper case this by itself I believe. Also if you're targeting iOS 15 (not sure) you can simply pass the string. Same comment for all the headers :)

Suggested change
Section(header: Text("USER SETTINGS")) {
Section("User Settings") {

// TODO: Profile Picture

// Display Name
HStack {
Text("Display Name")
Spacer(minLength: 20)

TextField("Display Name", text: $account.wrappedDisplayName)
.multilineTextAlignment(.trailing)
.disabled(!self.capabilities.capabilities.canSetDisplayName)
}

// Password
Button("Change password", role: .destructive) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't mark this as destructive myself, if something bad is going to happen it should show an alert explaining this instead, otherwise changing password should probably feel like a safe operation to the user.

print("TODO: implement change password")
}
.disabled(!self.capabilities.capabilities.canChangePassword)
}

Section(header: Text("SECURITY")) {
NavigationLink("Security") {
ProfileSettingsSecurityContainerView()
.environmentObject(account)
}
}

ProfileSettingsDangerZone()
}
.environmentObject(account)
.navigationTitle(account.displayName ?? account.userID ?? "Settings")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem {
Button(action: {
Copy link
Member

@pixlwave pixlwave Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the label is simply text label, it's probably neater to

Button("Save") {
    // do stuff
}

print("saving...")
Task(priority: .userInitiated) {
let changes = account.changedValues()

let nioAccount = store.accounts[account.userID!]!

if let displayName = changes["displayName"] as? String {
NioAccountStore.logger.debug("Changing displayName to \(displayName)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to actually log the new displayname? Always seems like a good habit to me to avoid logging personal data where possible. (Unless Logger redacts this string interpolation by default, in which case ignore me as I haven't used it in a while).


do {
try await nioAccount.matrixCore.client.setDisplayName(displayName, userID: account.userID!)
} catch {
NioAccountStore.logger.fault("Failed to save displayName to matrix account")
}
}
do {
try moc.save()
} catch {
NioAccountStore.logger.fault("Failed to save changed account to CoreData")
}

// TODO: save to CoreData
self.moc.undoManager = nil
self.dismiss()
}
}) {
Text("Save")
}
.disabled(!account.hasChanges)
}
}
.onAppear {
self.moc.undoManager = UndoManager()
self.probeServer()
}
.onDisappear {
self.task?.cancel()
print("discarding")
self.moc.undoManager?.undo()
self.moc.undoManager = nil
}
}

private func probeServer() {
task = Task(priority: .high) {
let nioAccount = store.accounts[account.userID!]

do {
let capabilities = try await nioAccount?.matrixCore.client.getCapabilities()
if let capabilities = capabilities {
self.capabilities = capabilities
}
} catch {
NioAccountStore.logger.fault("Failed to get server capabilities")
}
}
}
}

struct ProfileSettingsDangerZone: View {
@EnvironmentObject var account: MatrixAccount
@EnvironmentObject var store: NioAccountStore

@Environment(\.dismiss) private var dismiss

@State private var showSignOutDialog: Bool = false
@State private var showDeactivateDialog: Bool = false

var body: some View {
Section(header: Text("DANGER ZONE")) {
Button("Sign Out") {
showSignOutDialog = true
}
.disabled(showSignOutDialog)
.confirmationDialog("Are you sure you want to sign out?", isPresented: $showSignOutDialog, titleVisibility: .visible) {
Button("Sign out", role: .destructive) {
print("TODO: implement sign out")
Task(priority: .userInitiated) {
do {
try await self.store.logout(accountName: account.userID!)
} catch {
NioAccountStore.logger.fault("Failed to log out: \(error.localizedDescription)")
}
}
// TODO:
}
}

Button("Deactivate my account", role: .destructive) {
showDeactivateDialog = true
}
.disabled(showDeactivateDialog)
.confirmationDialog("Are you sure you want to disable your account? This cannot be undone", isPresented: $showDeactivateDialog, titleVisibility: .visible) {
Text("This cannot be undone")
.font(.headline)
.foregroundColor(.red)
Button("Deactivate", role: .destructive) {
print("TODO: deactivate account")
// TODO:
}
}
}
}
}

struct ProfileSettingsContainerView_Previews: PreviewProvider {
static let account: MatrixAccount = MatrixStore.createAmir(context: MatrixStore.preview.viewContext)

static var previews: some View {
Group {
NavigationView {
ProfileSettingsContainerView(account: ProfileSettingsContainerView_Previews.account)
}
}
}
}
Loading