Skip to content

Commit

Permalink
Rewrite the Account Settings view in SwiftUI
Browse files Browse the repository at this point in the history
  • Loading branch information
lissine0 committed Nov 2, 2024
1 parent 45e3f9c commit 97f200f
Show file tree
Hide file tree
Showing 15 changed files with 644 additions and 1,339 deletions.
425 changes: 425 additions & 0 deletions Monal/Classes/AccountSettings.swift

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Monal/Classes/DataLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ extern NSString* const kMessageTypeFiletransfer;
-(NSNumber*) enabledAccountCnts;
-(NSArray*) enabledAccountList;
-(BOOL) isAccountEnabled:(NSNumber*) accountID;
-(BOOL) disableAccountForAccountID:(NSNumber*) accountID;
-(BOOL) enableAccountForAccountID:(NSNumber*) accountID;
-(BOOL) doesAccountExistUser:(NSString*) user andDomain:(NSString *) domain;
-(NSNumber* _Nullable) accountIDForUser:(NSString*) user andDomain:(NSString *) domain;

Expand Down
14 changes: 14 additions & 0 deletions Monal/Classes/DataLayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,20 @@ -(BOOL) isAccountEnabled:(NSNumber*) accountID
}];
}

-(BOOL) disableAccountForAccountID:(NSNumber*) accountID
{
return [self.db boolReadTransaction:^{
return [self.db executeNonQuery:@"UPDATE account SET enabled=0 WHERE account_id=?;" andArguments:@[accountID]];
}];
}

-(BOOL) enableAccountForAccountID:(NSNumber*) accountID
{
return [self.db boolReadTransaction:^{
return [self.db executeNonQuery:@"UPDATE account SET enabled=1 WHERE account_id=?;" andArguments:@[accountID]];
}];
}

-(NSNumber*) accountIDForUser:(NSString*) user andDomain:(NSString*) domain
{
if(!user && !domain)
Expand Down
148 changes: 148 additions & 0 deletions Monal/Classes/LoginCredentials.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//
// LoginCredentials.swift
// Monal
//
// Created by lissine on 2/11/2024.
// Copyright © 2024 monal-im.org. All rights reserved.
//

import SAMKeychain

struct LoginCredentials: View {
@Environment(\.presentationMode) var presentationMode
let accountID: NSNumber?
let jid: String
let resource: String
@State private var password: String
@State private var hardcodedServer: String
@State private var hardcodedPort: String
@State private var allowPlainAuth: Bool
@State private var forceDirectTLS: Bool

init(accountID: NSNumber?) {
self.accountID = accountID
guard accountID != nil,
let settings = DataLayer.sharedInstance().details(forAccount: accountID!) else {
self.jid = ""
self.resource = ""
self.hardcodedServer = ""
self.hardcodedPort = "5222"
self.allowPlainAuth = false
self.forceDirectTLS = false
self.password = ""
return
}

self.jid = "\(settings["username"]!)@\(settings["domain"]!)"
self.resource = settings["resource"] as? String ?? ""
_hardcodedServer = State(initialValue: settings["server"] as? String ?? "")
_hardcodedPort = State(initialValue: "\(settings["other_port"] ?? 5222)")
_allowPlainAuth = State(initialValue: settings["plain_activated"] as? Bool ?? false)
_forceDirectTLS = State(initialValue: settings["directTLS"] as? Bool ?? false)
_password = State(initialValue: SAMKeychain.password(forService: kMonalKeychainName, account: self.accountID!.stringValue) ?? "")
}

var body: some View {
Form {
Section(header: Text("")) {
HStack {
Text("XMPP ID")
Spacer()
Text(self.jid)
}
HStack {
Text("Password")
Spacer()
#if IS_QUICKSY
TextField("Password", text: $password)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
#else
SecureField("Password", text: $password)
#endif
}
}

Section(header: Text("Advanced")) {
HStack {
Text("Server")
Spacer()
TextField("Optional Hardcoded Hostname", text: $hardcodedServer)
.textInputAutocapitalization(.never)
.disableAutocorrection(true)
}

if !hardcodedServer.isEmpty {
HStack {
Text("Port")
Spacer()
TextField("Optional Hardcoded Port", text: $hardcodedPort)
.keyboardType(.numberPad)
.onDisappear {
hardcodedPort = "5222"
}
}

Toggle(isOn: $forceDirectTLS) {
Text("Always use direct TLS, not STARTTLS")
}
.multilineTextAlignment(.leading)
.onDisappear {
forceDirectTLS = false
}
}

Toggle(isOn: $allowPlainAuth) {
Text("Allow MITM-prone PLAIN authentication")
}
// The plain auth setting is read only, to prevent downgrades. TODO: allow upgrading this setting using the SCRAM preload list
.disabled(true)
.multilineTextAlignment(.leading)

HStack {
Text("Resource")
Spacer()
Text(self.resource)
}
}

}
.multilineTextAlignment(.trailing)
.navigationTitle("Login Credetials")
.navigationBarBackButtonHidden()
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Abort") {
self.presentationMode.wrappedValue.dismiss()
}
}
ToolbarItem(placement: .confirmationAction) {
Button("Done") {
guard accountID != nil else {
self.presentationMode.wrappedValue.dismiss()
return
}

var settings = DataLayer.sharedInstance().details(forAccount: accountID!) as! [String: Any]
settings["plain_activated"] = self.allowPlainAuth
settings["directTLS"] = self.forceDirectTLS
settings["server"] = self.hardcodedServer
settings["other_port"] = self.hardcodedPort
// Save the updated settings in the DB
DataLayer.sharedInstance().updateAccoun(with: settings)
// Save the password in the Keychain
if !self.password.isEmpty {
MLXMPPManager.sharedInstance().updatePassword(self.password, forAccount: self.accountID!)
}
self.presentationMode.wrappedValue.dismiss()

// Disconnect and reconnect so the new credentials / settings take effect
MLXMPPManager.sharedInstance().disconnectAccount(self.accountID!, withExplicitLogout: true)
MLXMPPManager.sharedInstance().connectAccount(self.accountID!)
}
// the jid can be empty if this view was somehow accessed while accountID is nil
.disabled(password.isEmpty || jid.isEmpty)
}
}
}
}
1 change: 1 addition & 0 deletions Monal/Classes/MLConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ static inline NSString* _Nonnull LocalizationNotNeeded(NSString* _Nonnull s)

#define kMonalRefresh @"kMonalRefresh"
#define kMonalContactRefresh @"kMonalContactRefresh"
#define kMonalAccountSettingsRefresh @"kMonalAccountSettingsRefresh"
#define kMonalXmppUserSoftWareVersionRefresh @"kMonalXmppUserSoftWareVersionRefresh"
#define kMonalBlockListRefresh @"kMonalBlockListRefresh"
#define kMonalContactRemoved @"kMonalContactRemoved"
Expand Down
16 changes: 0 additions & 16 deletions Monal/Classes/MLMAMPrefTableViewController.h

This file was deleted.

110 changes: 0 additions & 110 deletions Monal/Classes/MLMAMPrefTableViewController.m

This file was deleted.

31 changes: 31 additions & 0 deletions Monal/Classes/MLPubSubProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ @implementation MLPubSubProcessor
[[MLNotificationQueue currentQueue] postNotificationName:kMonalContactRefresh object:account userInfo:@{
@"contact": [MLContact createContactFromJid:jid andAccountID:account.accountID]
}];
if ([jid isEqualToString:account.connectionProperties.identity.jid])
{
[[MLNotificationQueue currentQueue] postNotificationName:kMonalAccountSettingsRefresh object:account userInfo:@{
@"accountID": account.accountID
}];
}
DDLogInfo(@"Avatar of '%@' fetched and updated successfully", jid);
}
else
Expand All @@ -184,6 +190,10 @@ @implementation MLPubSubProcessor
NSMutableDictionary* accountDic = [[NSMutableDictionary alloc] initWithDictionary:[[DataLayer sharedInstance] detailsForAccount:account.accountID] copyItems:YES];
accountDic[kRosterName] = [data[itemId] findFirst:@"{http://jabber.org/protocol/nick}nick#"];
[[DataLayer sharedInstance] updateAccounWithDictionary:accountDic];
//TODO: post a notification here so the view can refresh
[[MLNotificationQueue currentQueue] postNotificationName:kMonalAccountSettingsRefresh object:account userInfo:@{
@"accountID": account.accountID
}];
}
else //roster name of contact
{
Expand Down Expand Up @@ -211,6 +221,14 @@ @implementation MLPubSubProcessor
NSMutableDictionary* accountDic = [[NSMutableDictionary alloc] initWithDictionary:[[DataLayer sharedInstance] detailsForAccount:account.accountID] copyItems:NO];
accountDic[kRosterName] = @"";
[[DataLayer sharedInstance] updateAccounWithDictionary:accountDic];

//delete cache to make sure the image will be regenerated
[[MLImageManager sharedInstance] purgeCacheForContact:account.connectionProperties.identity.jid andAccount:account.accountID];
//TODO: post a notification here so the view can refresh
[[MLNotificationQueue currentQueue] postNotificationName:kMonalAccountSettingsRefresh object:account userInfo:@{
@"accountID": account.accountID
}];

}
else
{
Expand Down Expand Up @@ -777,6 +795,13 @@ @implementation MLPubSubProcessor
return;
}
DDLogDebug(@"Removed avatar from pep");

//delete cache to make sure the image will be regenerated
[[MLImageManager sharedInstance] purgeCacheForContact:account.connectionProperties.identity.jid andAccount:account.accountID];
//post notification
[[MLNotificationQueue currentQueue] postNotificationName:kMonalAccountSettingsRefresh object:account userInfo:@{
@"accountID": account.accountID
}];
$$

$$class_handler(avatarMetadataPublished, $$ID(xmpp*, account), $$BOOL(success), $_ID(XMPPIQ*, errorIq), $_ID(NSString*, errorReason))
Expand All @@ -787,6 +812,12 @@ @implementation MLPubSubProcessor
return;
}
DDLogDebug(@"Published avatar metadata to pep");
//delete cache to make sure the image will be regenerated
[[MLImageManager sharedInstance] purgeCacheForContact:account.connectionProperties.identity.jid andAccount:account.accountID];

//[[MLNotificationQueue currentQueue] postNotificationName:kMonalAccountSettingsRefresh object:account userInfo:@{
// @"accountID": account.accountID
//}];
$$

$$class_handler(avatarDataPublished, $$ID(xmpp*, account), $$BOOL(success), $_ID(XMPPIQ*, errorIq), $_ID(NSString*, errorReason), $$ID(NSString*, imageHash), $$UINTEGER(imageBytesLen))
Expand Down
Loading

0 comments on commit 97f200f

Please sign in to comment.