From bf6f55bc119fe5a9acba05aa1b0578a8a67adb21 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Mon, 29 Apr 2024 18:52:21 +0200 Subject: [PATCH 01/23] --- 899 --- 6.3.0b5 From 4d06a68b7aff2ef3c4484c7730cb9bb4fe4bd239 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Mon, 29 Apr 2024 21:37:39 +0200 Subject: [PATCH 02/23] Nicer output when creating a release --- .github/workflows/beta.build-push.yml | 8 ++--- .github/workflows/develop-push.yml | 40 ++++++++++++------------- .github/workflows/stable.build-push.yml | 34 ++++++++++----------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/.github/workflows/beta.build-push.yml b/.github/workflows/beta.build-push.yml index 5a9a93f77e..3ecabc36b4 100644 --- a/.github/workflows/beta.build-push.yml +++ b/.github/workflows/beta.build-push.yml @@ -75,22 +75,22 @@ jobs: chmod +x ./scripts/updateLocalization.sh chmod +x ./scripts/xliff_extractor.py ./scripts/updateLocalization.sh BUILDSERVER - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: monal-catalyst path: Monal/build/app/Monal.zip if-no-files-found: error - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: monal-ios path: Monal/build/ipa/Monal.ipa if-no-files-found: error - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: monal-catalyst-dsym path: Monal/build/macos_Monal.xcarchive/dSYMs if-no-files-found: error - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: monal-ios-dsym path: Monal/build/ios_Monal.xcarchive/dSYMs diff --git a/.github/workflows/develop-push.yml b/.github/workflows/develop-push.yml index 19f1cf75a6..a4304da77e 100644 --- a/.github/workflows/develop-push.yml +++ b/.github/workflows/develop-push.yml @@ -64,23 +64,23 @@ jobs: run: xcrun notarytool submit ./Monal/build/app/Monal.alpha.zip --wait --team-id S8D843U34Y --key "/Users/ci/appstoreconnect/apiKey.p8" --key-id "$(cat /Users/ci/appstoreconnect/apiKeyId.txt)" --issuer "$(cat /Users/ci/appstoreconnect/apiIssuerId.txt)" - name: Update monal homebrew alpha repo run: scripts/updateAlphaHomebrew.sh - #- uses: actions/upload-artifact@v3 - # with: - # name: monal-catalyst - # path: "Monal/build/app/Monal.alpha.tar" - # if-no-files-found: error - #- uses: actions/upload-artifact@v3 - # with: - # name: monal-ios - # path: "Monal/build/ipa/Monal.alpha.ipa" - # if-no-files-found: error - #- uses: actions/upload-artifact@v3 - # with: - # name: monal-catalyst-dsym - # path: Monal/build/macos_Monal.xcarchive/dSYMs - # if-no-files-found: error - #- uses: actions/upload-artifact@v3 - # with: - # name: monal-ios-dsym - # path: Monal/build/ios_Monal.xcarchive/dSYMs - # if-no-files-found: error + - uses: actions/upload-artifact@v4 + with: + name: monal-catalyst + path: "Monal/build/app/Monal.alpha.tar" + if-no-files-found: error + - uses: actions/upload-artifact@v4 + with: + name: monal-ios + path: "Monal/build/ipa/Monal.alpha.ipa" + if-no-files-found: error + - uses: actions/upload-artifact@v4 + with: + name: monal-catalyst-dsym + path: Monal/build/macos_Monal.xcarchive/dSYMs + if-no-files-found: error + - uses: actions/upload-artifact@v4 + with: + name: monal-ios-dsym + path: Monal/build/ios_Monal.xcarchive/dSYMs + if-no-files-found: error diff --git a/.github/workflows/stable.build-push.yml b/.github/workflows/stable.build-push.yml index fc380aa429..251e3234cb 100644 --- a/.github/workflows/stable.build-push.yml +++ b/.github/workflows/stable.build-push.yml @@ -76,41 +76,41 @@ jobs: - name: Extract version number and changelog from newest merge commit id: releasenotes run: | - buildNumber=$(git tag --sort="v:refname" |grep "Build_iOS" | tail -n1 | sed 's/Build_iOS_//g') + buildNumber=$(git tag --sort="v:refname" | grep "Build_iOS" | tail -n1 | sed 's/Build_iOS_//g') echo "tag=Build_iOS_$buildNumber" >> "$GITHUB_OUTPUT" - echo "name=$(git log -n 1 --merges --pretty=format:%s)" >> "$GITHUB_OUTPUT" + echo "name=$(git log -n 1 --merges --pretty=format:%s | sed -E 's/^\s*([^\s]+)\s+\(([^\s]+)\)$/\1 (Build '$buildNumber', PR \2)/g')" >> "$GITHUB_OUTPUT" echo "notes=$(git log -n 1 --merges --pretty=format:%b)" >> "$GITHUB_OUTPUT" - name: Release uses: softprops/action-gh-release@v2 with: - name: Release ${{ steps.releasenotes.outputs.name }} - tag_name: ${{ steps.releasenotes.outputs.tag }} + name: "Release ${{ steps.releasenotes.outputs.name }}" + tag_name: "${{ steps.releasenotes.outputs.tag }}" target_commitish: stable generate_release_notes: false - body: ${{ steps.releasenotes.outputs.notes }} + body: "${{ steps.releasenotes.outputs.notes }}" files: | ./Monal/build/ipa/Monal.ipa ./Monal/build/app/Monal.zip fail_on_unmatched_files: true token: ${{ secrets.GITHUB_TOKEN }} draft: false - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: monal-catalyst-pkg path: Monal/build/app/Monal.pkg if-no-files-found: error - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: monal-ios path: Monal/build/ipa/Monal.ipa if-no-files-found: error - - uses: actions/upload-artifact@v3 - with: - name: monal-catalyst-dsym - path: Monal/build/macos_Monal.xcarchive/dSYMs - if-no-files-found: error - - uses: actions/upload-artifact@v3 - with: - name: monal-ios-dsym - path: Monal/build/ios_Monal.xcarchive/dSYMs - if-no-files-found: error + # - uses: actions/upload-artifact@v4 + # with: + # name: monal-catalyst-dsym + # path: Monal/build/macos_Monal.xcarchive/dSYMs + # if-no-files-found: error + # - uses: actions/upload-artifact@v4 + # with: + # name: monal-ios-dsym + # path: Monal/build/ios_Monal.xcarchive/dSYMs + # if-no-files-found: error From 8acf65b48bef6b554b34c75e529fcd8651817e0b Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Tue, 30 Apr 2024 03:15:42 +0200 Subject: [PATCH 03/23] Fix flickering of default background image (Tie_My_Boat) --- Monal/localization/Base.lproj/Main.storyboard | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Monal/localization/Base.lproj/Main.storyboard b/Monal/localization/Base.lproj/Main.storyboard index 16e176ab65..dd2ae0e236 100644 --- a/Monal/localization/Base.lproj/Main.storyboard +++ b/Monal/localization/Base.lproj/Main.storyboard @@ -216,9 +216,8 @@ - + - @@ -2537,7 +2536,6 @@ - @@ -2547,9 +2545,6 @@ - - - From f9f882e2f2330baa83fb2b504507ec4fde1fe4a9 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Tue, 30 Apr 2024 04:00:55 +0200 Subject: [PATCH 04/23] fixup_workflow --- .github/workflows/develop-push.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/develop-push.yml b/.github/workflows/develop-push.yml index a4304da77e..c1588fe561 100644 --- a/.github/workflows/develop-push.yml +++ b/.github/workflows/develop-push.yml @@ -74,13 +74,13 @@ jobs: name: monal-ios path: "Monal/build/ipa/Monal.alpha.ipa" if-no-files-found: error - - uses: actions/upload-artifact@v4 - with: - name: monal-catalyst-dsym - path: Monal/build/macos_Monal.xcarchive/dSYMs - if-no-files-found: error - - uses: actions/upload-artifact@v4 - with: - name: monal-ios-dsym - path: Monal/build/ios_Monal.xcarchive/dSYMs - if-no-files-found: error + # - uses: actions/upload-artifact@v4 + # with: + # name: monal-catalyst-dsym + # path: Monal/build/macos_Monal.xcarchive/dSYMs + # if-no-files-found: error + # - uses: actions/upload-artifact@v4 + # with: + # name: monal-ios-dsym + # path: Monal/build/ios_Monal.xcarchive/dSYMs + # if-no-files-found: error From 8c6e45f6f76777ce4d3f3eb07fd3300a1dc8b7e1 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Tue, 30 Apr 2024 18:49:58 +0200 Subject: [PATCH 05/23] Add filtering entitlement to macos alpha builds --- Monal/Alpha.Monal.macos.entitlements | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Monal/Alpha.Monal.macos.entitlements b/Monal/Alpha.Monal.macos.entitlements index ee88dc993e..f8560de197 100644 --- a/Monal/Alpha.Monal.macos.entitlements +++ b/Monal/Alpha.Monal.macos.entitlements @@ -4,6 +4,8 @@ aps-environment production + com.apple.developer.usernotifications.filtering + com.apple.developer.usernotifications.communication com.apple.security.app-sandbox From 6a334147d31e39612826080bf6fc7b4110a72ad9 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Wed, 1 May 2024 19:50:42 +0200 Subject: [PATCH 06/23] Fix debug view appearance on macOS --- Monal/Classes/DebugView.swift | 81 ++++++++++++------- Monal/Classes/MLSettingsTableViewController.m | 2 +- Monal/Classes/SwiftuiHelpers.swift | 18 ++--- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/Monal/Classes/DebugView.swift b/Monal/Classes/DebugView.swift index ea12caff8a..6f5d4cb7d9 100644 --- a/Monal/Classes/DebugView.swift +++ b/Monal/Classes/DebugView.swift @@ -71,6 +71,12 @@ struct LogFilesView: View { } } } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .applyClosure { view in + if #available(iOS 15, *) { + view.background(.interpolatedWindowBackground) + } + } .alert(isPresented: $showingDBExportFailedAlert) { Alert(title: Text("Database Export Failed"), message: Text("Failed to export the database, please check the logfile for errors and try again."), dismissButton: .default(Text("Close"))) } @@ -115,44 +121,56 @@ struct UDPConfigView: View { Text("UDP Logging UI not supported on iOS < 16").foregroundColor(.red) } } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .applyClosure { view in + if #available(iOS 15, *) { + view.background(.interpolatedWindowBackground) + } + } } } struct CrashTestingView: View { var body: some View { - VStack(alignment:.leading, spacing: 25) { - Text("This allows you to forcefully crash the app using several different methods to test the crash handling.") - - Group { - Button("Try to call unknown handler method") { - DispatchQueue.global(qos: .default).async(execute: { + VStack(alignment:.leading, spacing: 25) { + Text("This allows you to forcefully crash the app using several different methods to test the crash handling.") + + Group { + Button("Try to call unknown handler method") { + DispatchQueue.global(qos: .default).async(execute: { + HelperTools.flushLogs(withTimeout: 0.100) + let handler = MLHandler(delegate: self, handlerName: "IDontKnowThis", andBoundArguments: [:]) + handler.call(withArguments: nil) + }) + } + Button("Bad Access Crash") { HelperTools.flushLogs(withTimeout: 0.100) - let handler = MLHandler(delegate: self, handlerName: "IDontKnowThis", andBoundArguments: [:]) - handler.call(withArguments: nil) - }) - } - Button("Bad Access Crash") { - HelperTools.flushLogs(withTimeout: 0.100) - let delegate: AnyClass? = NSClassFromString("MonalAppDelegate") - print(delegate.unsafelyUnwrapped.audiovisualTypes()) - - } - Button("Assertion Crash") { - HelperTools.flushLogs(withTimeout: 0.100) - assert(false) - } - Button("Fatal Error Crash") { - HelperTools.flushLogs(withTimeout: 0.100) - fatalError("fatalError_example") - } - Button("Nil Crash") { - HelperTools.flushLogs(withTimeout: 0.100) - let crasher:Int? = nil - print(crasher!) + let delegate: AnyClass? = NSClassFromString("MonalAppDelegate") + print(delegate.unsafelyUnwrapped.audiovisualTypes()) + + } + Button("Assertion Crash") { + HelperTools.flushLogs(withTimeout: 0.100) + assert(false) + } + Button("Fatal Error Crash") { + HelperTools.flushLogs(withTimeout: 0.100) + fatalError("fatalError_example") + } + Button("Nil Crash") { + HelperTools.flushLogs(withTimeout: 0.100) + let crasher:Int? = nil + print(crasher!) + } + }.foregroundColor(.red) + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .applyClosure { view in + if #available(iOS 15, *) { + view.background(.interpolatedWindowBackground) } - }.foregroundColor(.red) - Spacer() - } + } } } @@ -177,6 +195,7 @@ struct DebugView: View { Text("Crash Testing") } } + .frame(maxWidth: .infinity, maxHeight: .infinity) .padding() .addLoadingOverlay(overlay) .onChange(of: isReconnecting) { _ in diff --git a/Monal/Classes/MLSettingsTableViewController.m b/Monal/Classes/MLSettingsTableViewController.m index e022cb5047..f67b0e4b80 100644 --- a/Monal/Classes/MLSettingsTableViewController.m +++ b/Monal/Classes/MLSettingsTableViewController.m @@ -376,7 +376,7 @@ -(void)tableView:(UITableView*) tableView didSelectRowAtIndexPath:(NSIndexPath*) case LogRow: #endif case SettingsAboutRowsCntORLogRow:{ - UIViewController* logView = [[SwiftuiInterface new] makeViewWithName:@"logView"]; + UIViewController* logView = [[SwiftuiInterface new] makeViewWithName:@"DebugView"]; [self showDetailViewController:logView sender:self]; break; } diff --git a/Monal/Classes/SwiftuiHelpers.swift b/Monal/Classes/SwiftuiHelpers.swift index 3e60317783..8a58e4547d 100644 --- a/Monal/Classes/SwiftuiHelpers.swift +++ b/Monal/Classes/SwiftuiHelpers.swift @@ -24,16 +24,12 @@ let monalGreen = Color(UIColor(red:128.0/255, green:203.0/255, blue:182.0/255, a let monalDarkGreen = Color(UIColor(red:20.0/255, green:138.0/255, blue:103.0/255, alpha:1.0)); //see https://stackoverflow.com/a/62207329/3528174 -public extension Color { -#if os(macOS) - static let background = Color(NSColor.windowBackgroundColor) - static let secondaryBackground = Color(NSColor.underPageBackgroundColor) - static let tertiaryBackground = Color(NSColor.controlBackgroundColor) -#else - static let background = Color(UIColor.systemBackground) - static let secondaryBackground = Color(UIColor.secondarySystemBackground) - static let tertiaryBackground = Color(UIColor.tertiarySystemBackground) -#endif +//and https://www.hackingwithswift.com/forums/100-days-of-swiftui/extending-shapestyle-for-adding-colors-instead-of-extending-color/12324 +public extension ShapeStyle where Self == Color { + static var interpolatedWindowBackground: Color { Color(UIColor { $0.userInterfaceStyle == .dark ? UIColor.systemBackground : UIColor.secondarySystemBackground }) } + static var background: Color { Color(UIColor.systemBackground) } + static var secondaryBackground: Color { Color(UIColor.secondarySystemBackground) } + static var tertiaryBackground: Color { Color(UIColor.tertiarySystemBackground) } } extension Binding { @@ -483,7 +479,7 @@ class SwiftuiInterface : NSObject { switch(name) { // TODO names are currently taken from the segue identifier, an enum would be nice once everything is ported to SwiftUI case "NotificationSettings": host.rootView = AnyView(UIKitWorkaround(NotificationSettings(delegate:delegate))) - case "logView": + case "DebugView": host.rootView = AnyView(UIKitWorkaround(DebugView())) case "WelcomeLogIn": host.rootView = AnyView(AddTopLevelNavigation(withDelegate:delegate, to:WelcomeLogIn(delegate:delegate))) From 42bcdc0e365f57768cfc54b9b02e64c11fed8cd7 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Wed, 1 May 2024 21:38:23 +0200 Subject: [PATCH 07/23] Make keyboard auto-appear configurable --- Monal/Classes/MLResizingTextView.m | 4 +++- Monal/Classes/MLXMPPManager.m | 8 ++++++++ Monal/Classes/PrivacySettings.swift | 18 +++++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Monal/Classes/MLResizingTextView.m b/Monal/Classes/MLResizingTextView.m index 8b0a2288bf..9513833591 100644 --- a/Monal/Classes/MLResizingTextView.m +++ b/Monal/Classes/MLResizingTextView.m @@ -7,6 +7,7 @@ // #import "MLResizingTextView.h" +#import "HelperTools.h" @implementation MLResizingTextView @@ -17,7 +18,8 @@ - (void) layoutSubviews if (!CGSizeEqualToSize(self.bounds.size, [self intrinsicContentSize])) { [self invalidateIntrinsicContentSize]; } - [self becomeFirstResponder]; + if([[HelperTools defaultsDB] boolForKey: @"showKeyboardOnChatOpen"]) + [self becomeFirstResponder]; } - (CGSize)intrinsicContentSize diff --git a/Monal/Classes/MLXMPPManager.m b/Monal/Classes/MLXMPPManager.m index 5b4a347d0c..d383c971ed 100644 --- a/Monal/Classes/MLXMPPManager.m +++ b/Monal/Classes/MLXMPPManager.m @@ -141,6 +141,14 @@ -(void) defaultSettings //anti spam/privacy setting, but default to yes (current behavior, conversations behavior etc.) [self upgradeBoolUserSettingsIfUnset:@"allowNonRosterContacts" toDefault:YES]; [self upgradeBoolUserSettingsIfUnset:@"allowCallsFromNonRosterContacts" toDefault:YES]; + + //mac catalyst will not show a soft-keyboard when setting focus, ios will + //--> only automatically set focus on macos and make this configurable +#if TARGET_OS_MACCATALYST + [self upgradeBoolUserSettingsIfUnset:@"showKeyboardOnChatOpen" toDefault:YES]; +#else + [self upgradeBoolUserSettingsIfUnset:@"showKeyboardOnChatOpen" toDefault:NO]; +#endif } -(void) upgradeFloatUserSettingsToInteger:(NSString*) settingsName diff --git a/Monal/Classes/PrivacySettings.swift b/Monal/Classes/PrivacySettings.swift index a7fb6754b2..7354ae552b 100644 --- a/Monal/Classes/PrivacySettings.swift +++ b/Monal/Classes/PrivacySettings.swift @@ -75,6 +75,9 @@ class PrivacyDefaultDB: ObservableObject { @defaultsDB("ImageUploadQuality") var imageUploadQuality : Float + + @defaultsDB("showKeyboardOnChatOpen") + var showKeyboardOnChatOpen: Bool } @@ -161,12 +164,17 @@ struct PublishingScreen: View { var body: some View { Form { - Toggle("Send last interaction time", isOn: $privacyDefaultDB.sendLastUserInteraction) - Toggle("Send typing notifications", isOn: $privacyDefaultDB.sendLastChatState) - Toggle("Send message received state", isOn: $privacyDefaultDB.sendReceivedMarkers) - Toggle("Send message displayed state", isOn: $privacyDefaultDB.sendDisplayedMarkers) + Section(header: Text("Publishing")) { + Toggle("Send last interaction time", isOn: $privacyDefaultDB.sendLastUserInteraction) + Toggle("Send typing notifications", isOn: $privacyDefaultDB.sendLastChatState) + Toggle("Send message received state", isOn: $privacyDefaultDB.sendReceivedMarkers) + Toggle("Send message displayed state", isOn: $privacyDefaultDB.sendDisplayedMarkers) + } + Section(header: Text("Appearance")) { + Toggle("Autofocus text input on chat open", isOn: $privacyDefaultDB.showKeyboardOnChatOpen) + } } - .navigationBarTitle("Publishing", displayMode: .inline) + .navigationBarTitle("Publishing & appearance", displayMode: .inline) } } From 5f6ee3cbfc72d93e51d7ac3f4fc0e47d44fc1c1a Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 00:07:28 +0200 Subject: [PATCH 08/23] Better error propagation in MLFiletransfer --- Monal/Classes/MLFileTransferDataCell.m | 2 +- Monal/Classes/MLFiletransfer.h | 2 +- Monal/Classes/MLFiletransfer.m | 47 +++++++++++++++++--------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Monal/Classes/MLFileTransferDataCell.m b/Monal/Classes/MLFileTransferDataCell.m index 7bfc50b9af..60866e23f7 100644 --- a/Monal/Classes/MLFileTransferDataCell.m +++ b/Monal/Classes/MLFileTransferDataCell.m @@ -34,7 +34,7 @@ -(void)awakeFromNib -(void)layoutSubviews { - if([MLFiletransfer isFileforHistoryIdInTransfer:self.messageDBId]) + if([MLFiletransfer isFileForHistoryIdInTransfer:self.messageDBId]) { [self.loadingView setHidden:NO]; [self.loadingView startAnimating]; diff --git a/Monal/Classes/MLFiletransfer.h b/Monal/Classes/MLFiletransfer.h index e49e990800..391a6b2cb0 100644 --- a/Monal/Classes/MLFiletransfer.h +++ b/Monal/Classes/MLFiletransfer.h @@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN +(void) uploadFile:(NSURL*) fileUrl onAccount:(xmpp*) account withEncryption:(BOOL) encrypted andCompletion:(void (^)(NSString* _Nullable url, NSString* _Nullable mimeType, NSNumber* _Nullable size, NSError* _Nullable error)) completion; +(void) uploadUIImage:(UIImage*) image onAccount:(xmpp*) account withEncryption:(BOOL) encrypted andCompletion:(void (^)(NSString* _Nullable url, NSString* _Nullable mimeType, NSNumber* _Nullable size, NSError* _Nullable error)) completion; +(void) hardlinkFileForMessage:(MLMessage*) msg; -+(BOOL) isFileforHistoryIdInTransfer:(NSNumber*) historyId; ++(BOOL) isFileForHistoryIdInTransfer:(NSNumber*) historyId; +(NSString*) getMimeTypeOfOriginalFile:(NSString*) file; @end diff --git a/Monal/Classes/MLFiletransfer.m b/Monal/Classes/MLFiletransfer.m index 6527f8ee0e..174f6a4234 100644 --- a/Monal/Classes/MLFiletransfer.m +++ b/Monal/Classes/MLFiletransfer.m @@ -67,7 +67,7 @@ +(void) checkMimeTypeAndSizeForHistoryID:(NSNumber*) historyId } //make sure we don't check or download this twice @synchronized(_currentlyTransfering) { - if([_currentlyTransfering containsObject:historyId]) + if([self isFileForHistoryIdInTransfer:historyId]) { DDLogDebug(@"Already checking/downloading this content, ignoring"); return; @@ -81,7 +81,15 @@ +(void) checkMimeTypeAndSizeForHistoryID:(NSNumber*) historyId request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; NSURLSession* session = [NSURLSession sharedSession]; - [[session dataTaskWithRequest:request completionHandler:^(NSData* _Nullable data __unused, NSURLResponse* _Nullable response, NSError* _Nullable error __unused) { + [[session dataTaskWithRequest:request completionHandler:^(NSData* _Nullable data __unused, NSURLResponse* _Nullable response, NSError* _Nullable error) { + if(error != nil) + { + DDLogError(@"Failed to fetch headers of %@ at %@: %@", msg, url, error); + //check done, remove from "currently checking/downloading list" and set error + [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:[NSString stringWithFormat:NSLocalizedString(@"Failed to fetch download metadata: %@", @""), error] forMessageId:msg.messageId]; + [self markAsComplete:historyId]; + return; + } NSDictionary* headers = ((NSHTTPURLResponse*)response).allHeaderFields; NSString* mimeType = [[headers objectForKey:@"Content-Type"] lowercaseString]; NSNumber* contentLength = [headers objectForKey:@"Content-Length"] ? [NSNumber numberWithInt:([[headers objectForKey:@"Content-Length"] intValue])] : @(-1); @@ -154,7 +162,7 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f //make sure we don't check or download this twice (but only do this if the download is not forced anyway) @synchronized(_currentlyTransfering) { - if(!forceDownload && [_currentlyTransfering containsObject:historyId]) + if(!forceDownload && [self isFileForHistoryIdInTransfer:historyId]) { DDLogDebug(@"Already checking/downloading this content, ignoring"); return; @@ -167,7 +175,7 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f NSURLComponents* urlComponents = [NSURLComponents componentsWithString:msg.messageText]; if(!urlComponents) { - DDLogError(@"url components decoding failed"); + DDLogError(@"url components decoding failed for %@", msg); [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:NSLocalizedString(@"Failed to decode download link", @"") forMessageId:msg.messageId]; [self markAsComplete:historyId]; return; @@ -179,8 +187,8 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f NSURLSessionDownloadTask* task = [session downloadTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSURL* _Nullable location, NSURLResponse* _Nullable response, NSError* _Nullable error) { if(error) { - DDLogError(@"File download failed: %@", error); - [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:NSLocalizedString(@"Failed to download file", @"") forMessageId:msg.messageId]; + DDLogError(@"File download for %@ failed: %@", msg, error); + [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:[NSString stringWithFormat:NSLocalizedString(@"Failed to download file: %@", @""), error] forMessageId:msg.messageId]; [self markAsComplete:historyId]; return; } @@ -206,7 +214,7 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f DDLogInfo(@"Decrypting encrypted filetransfer stored at '%@'...", location); if(urlComponents.fragment.length < 88) { - DDLogError(@"File download failed: %@", error); + DDLogError(@"File download for %@ failed: %@", msg, error); [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:NSLocalizedString(@"Failed to decode encrypted link", @"") forMessageId:msg.messageId]; [self markAsComplete:historyId]; return; @@ -223,7 +231,7 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f NSData* decryptedData = [AESGcm decrypt:encryptedData withKey:key andIv:iv withAuth:nil]; if(decryptedData == nil) { - DDLogError(@"File download decryption failed"); + DDLogError(@"File download decryption failed for %@", msg); [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:NSLocalizedString(@"Failed to decrypt download", @"") forMessageId:msg.messageId]; [self markAsComplete:historyId]; return; @@ -231,7 +239,7 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f [decryptedData writeToFile:cacheFile options:NSDataWritingAtomic error:&error]; if(error) { - DDLogError(@"File download failed: %@", error); + DDLogError(@"File download for %@ failed: %@", msg, error); [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:NSLocalizedString(@"Failed to write decrypted download into cache directory", @"") forMessageId:msg.messageId]; [self markAsComplete:historyId]; return; @@ -241,7 +249,7 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f } else { - DDLogError(@"Failed to decrypt file (iv, key, data length checks failed)"); + DDLogError(@"Failed to decrypt file (iv, key, data length checks failed) for %@", msg); [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:NSLocalizedString(@"Failed to decrypt filetransfer", @"") forMessageId:msg.messageId]; [self markAsComplete:historyId]; return; @@ -255,8 +263,8 @@ +(void) downloadFileForHistoryID:(NSNumber*) historyId andForceDownload:(BOOL) f error = [HelperTools hardLinkOrCopyFile:[location path] to:cacheFile]; if(error) { - DDLogError(@"File download failed: %@", error); - [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:NSLocalizedString(@"Failed to copy downloaded file into cache directory", @"") forMessageId:msg.messageId]; + DDLogError(@"File download for %@ failed: %@", msg, error); + [self setErrorType:NSLocalizedString(@"Download error", @"") andErrorText:[NSString stringWithFormat:NSLocalizedString(@"Failed to copy downloaded file into cache directory: %@", @""), error] forMessageId:msg.messageId]; [self markAsComplete:historyId]; return; } @@ -818,7 +826,7 @@ +(void) setErrorType:(NSString*) errorType andErrorText:(NSString*) errorText fo //make sure we don't upload the same tmpfile twice (should never happen anyways) @synchronized(_currentlyTransfering) { - if([_currentlyTransfering containsObject:file]) + if([self isFileAtPathInTransfer:file]) { error = [NSError errorWithDomain:@"MonalError" code:0 userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Already uploading this content, ignoring", @"")}]; DDLogError(@"Already uploading this content, ignoring %@", file); @@ -875,7 +883,7 @@ +(void) setErrorType:(NSString*) errorType andErrorText:(NSString*) errorText fo @"data":fileData, @"fileName":userFacingFilename, @"contentType":sendMimeType - } andCompletion:^(NSString *url, NSError *error) { + } andCompletion:^(NSString* url, NSError* error) { if(error) { [_fileManager removeItemAtPath:file error:nil]; //remove temporary file @@ -914,7 +922,7 @@ +(void) setErrorType:(NSString*) errorType andErrorText:(NSString*) errorText fo [_fileManager moveItemAtPath:file toPath:cacheFile error:&error]; if(error) { - NSError* error = [NSError errorWithDomain:@"MonalError" code:0 userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Failed to uploaded file to file cache directory", @"")}]; + NSError* error = [NSError errorWithDomain:@"MonalError" code:0 userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"Failed to move uploaded file to file cache directory", @"")}]; [_fileManager removeItemAtPath:file error:nil]; //remove temporary file [self markAsComplete:file]; DDLogError(@"File upload failed: %@", error); @@ -947,10 +955,17 @@ +(void) markAsComplete:(id) obj [[NSNotificationCenter defaultCenter] postNotificationName:kMonalFiletransfersIdle object:self]; } -+(BOOL) isFileforHistoryIdInTransfer:(NSNumber*) historyId ++(BOOL) isFileForHistoryIdInTransfer:(NSNumber*) historyId { if([_currentlyTransfering containsObject:historyId]) return YES; return NO; } + ++(BOOL) isFileAtPathInTransfer:(NSString*) path +{ + if([_currentlyTransfering containsObject:path]) + return YES; + return NO; +} @end From 5238c48337bc8394ae018c34cf97167e311dac9a Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 00:08:01 +0200 Subject: [PATCH 09/23] Clean up Privacy Settings code --- Monal/Classes/PrivacySettings.swift | 53 +++++++++++++++++------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/Monal/Classes/PrivacySettings.swift b/Monal/Classes/PrivacySettings.swift index 7354ae552b..a67faaa546 100644 --- a/Monal/Classes/PrivacySettings.swift +++ b/Monal/Classes/PrivacySettings.swift @@ -219,40 +219,49 @@ struct MLAutoDownloadFiletransferSettingView: View { Text("Adjust the maximum file size for auto-downloads over WiFi") .foregroundColor(.secondary) .font(.footnote) - Slider(value: $privacyDefaultDB.autodownloadFiletransfersWifiMaxSize.bytecount(mappedTo: 1024*1024), - in: 1.0...100.0, - step: 1.0, - minimumValueLabel: Text("1 MiB"), - maximumValueLabel: Text("100 MiB"), - label: {Text("Load over wifi")} + Slider( + value: $privacyDefaultDB.autodownloadFiletransfersWifiMaxSize.bytecount(mappedTo: 1024*1024), + in: 1.0...100.0, + step: 1.0, + minimumValueLabel: Text("1 MiB"), + maximumValueLabel: Text("100 MiB"), + label: { + Text("Load over wifi") + } ) - Text("Load over WiFi upto : \(UInt(privacyDefaultDB.autodownloadFiletransfersWifiMaxSize/(1024*1024))) MiB") + Text("Load over WiFi up to: \(UInt(privacyDefaultDB.autodownloadFiletransfersWifiMaxSize/(1024*1024))) MiB") } Text("Adjust the maximum file size for auto-downloads over cellular network") .foregroundColor(.secondary) .font(.footnote) - Slider(value: $privacyDefaultDB.autodownloadFiletransfersMobileMaxSize.bytecount(mappedTo: 1024*1024), - in: 0.0...100.0, - step: 1.0, - minimumValueLabel: Text("1 MiB"), - maximumValueLabel: Text("100 MiB"), - label: {Text("Load over Cellular")} + Slider( + value: $privacyDefaultDB.autodownloadFiletransfersMobileMaxSize.bytecount(mappedTo: 1024*1024), + in: 0.0...100.0, + step: 1.0, + minimumValueLabel: Text("1 MiB"), + maximumValueLabel: Text("100 MiB"), + label: { + Text("Load over Cellular") + } ) - Text("Load over cellular upto : \(Int(privacyDefaultDB.autodownloadFiletransfersMobileMaxSize/(1024*1024))) MiB") + Text("Load over cellular up to: \(Int(privacyDefaultDB.autodownloadFiletransfersMobileMaxSize/(1024*1024))) MiB") Section(header: Text("Upload Settings")) { Text("Adjust the quality of images uploaded") .foregroundColor(.secondary) .font(.footnote) - Slider(value: $privacyDefaultDB.imageUploadQuality, - in: 0.33...1.0, - step: 0.01, - minimumValueLabel: Text("33%"), - maximumValueLabel: Text("100%"), - label: {Text("Upload Settings") - }) - Text("Image Upload Quality : \(String(format: "%.0f%%", privacyDefaultDB.imageUploadQuality*100))") + Slider( + value: $privacyDefaultDB.imageUploadQuality, + in: 0.33...1.0, + step: 0.01, + minimumValueLabel: Text("33%"), + maximumValueLabel: Text("100%"), + label: { + Text("Upload Settings") + } + ) + Text("Image Upload Quality: \(String(format: "%.0f%%", privacyDefaultDB.imageUploadQuality*100))") } } } From f6a55e0bb03f465b1031dffb0f6cfa0330f32289 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 03:20:15 +0200 Subject: [PATCH 10/23] Fix detection of omemo keys in group-type mucs, fixes #1051 --- Monal/Classes/chatViewController.m | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Monal/Classes/chatViewController.m b/Monal/Classes/chatViewController.m index 1ed71c276e..01264ac896 100644 --- a/Monal/Classes/chatViewController.m +++ b/Monal/Classes/chatViewController.m @@ -815,7 +815,22 @@ -(void) viewDidAppear:(BOOL)animated #ifndef DISABLE_OMEMO if(self.xmppAccount) { - BOOL omemoDeviceForContactFound = [self.xmppAccount.omemo knownDevicesForAddressName:self.contact.contactJid].count > 0; + BOOL omemoDeviceForContactFound = NO; + if(!self.contact.isGroup) + omemoDeviceForContactFound = [self.xmppAccount.omemo knownDevicesForAddressName:self.contact.contactJid].count > 0; + else + { + omemoDeviceForContactFound = NO; + for(NSDictionary* participant in [[DataLayer sharedInstance] getMembersAndParticipantsOfMuc:self.contact.contactJid forAccountId:self.xmppAccount.accountNo]) + { + if(participant[@"participant_jid"]) + omemoDeviceForContactFound |= [self.xmppAccount.omemo knownDevicesForAddressName:participant[@"participant_jid"]].count > 0; + else if(participant[@"member_jid"]) + omemoDeviceForContactFound |= [self.xmppAccount.omemo knownDevicesForAddressName:participant[@"member_jid"]].count > 0; + if(omemoDeviceForContactFound) + break; + } + } if(!omemoDeviceForContactFound && self.contact.isEncrypted && [[DataLayer sharedInstance] isAccountEnabled:self.xmppAccount.accountNo]) { if(!self.contact.isGroup && [[HelperTools splitJid:self.contact.contactJid][@"host"] isEqualToString:@"cheogram.com"]) From cb5d6ce89cd6560d4279a515612b0efe7589290f Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 00:08:59 +0200 Subject: [PATCH 11/23] Add workflows to only update translations --- .github/workflows/update-translations.yml | 33 +++++++++++++++++++++++ scripts/updateLocalization.sh | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 .github/workflows/update-translations.yml diff --git a/.github/workflows/update-translations.yml b/.github/workflows/update-translations.yml new file mode 100644 index 0000000000..a628f9ec12 --- /dev/null +++ b/.github/workflows/update-translations.yml @@ -0,0 +1,33 @@ +# build a new beta release and push it to apple +name: update-translations + +# Controls when the action will run. +on: + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + updateTranslations: + # The type of runner that the job will run on + runs-on: self-hosted + env: + APP_NAME: "Monal" + APP_DIR: "Monal.app" + BUILD_TYPE: "Beta" + EXPORT_OPTIONS_CATALYST_APPSTORE: "../scripts/exportOptions/Stable_Catalyst_ExportOptions.plist" + EXPORT_OPTIONS_CATALYST_APP_EXPORT: "../scripts/exportOptions/Beta_Catalyst_ExportOptions.plist" + EXPORT_OPTIONS_IOS: "../scripts/exportOptions/Beta_iOS_ExportOptions.plist" + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - uses: actions/checkout@v4 + with: + clean: true + submodules: true + - name: Checkout submodules + run: git submodule update -f --init --remote + - name: Update translations + run: | + chmod +x ./scripts/updateLocalization.sh + chmod +x ./scripts/xliff_extractor.py + ./scripts/updateLocalization.sh BUILDSERVER diff --git a/scripts/updateLocalization.sh b/scripts/updateLocalization.sh index d5ad34b588..459a5fd9dc 100755 --- a/scripts/updateLocalization.sh +++ b/scripts/updateLocalization.sh @@ -65,8 +65,10 @@ pullCurrentState "$@" # update strings to remove everything that's now unused (that includes swiftui strings we'll readd below) cp .bartycrouch.toml .bartycrouch.toml.orig sed 's/additive = true/additive = false/g' .bartycrouch.toml > .bartycrouch.toml.new +rm .bartycrouch.toml mv .bartycrouch.toml.new .bartycrouch.toml runBartycrouch +rm .bartycrouch.toml mv .bartycrouch.toml.orig .bartycrouch.toml # now restore original state for all languages but our base one (otherwise every swiftui translation will be deleted) From 0daadbe81c28e64539266ecbc172b8f6962421fc Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 01:59:12 +0200 Subject: [PATCH 12/23] Rework swift localizable strings extraction This won't extract all strings, since setting SWIFT_EMIT_LOC_STRINGS=YES which would extract all strings as opposed to only `Text()` strings makes xcode compile the whole project for extraction which fails with the WebRTC lib not being found. --- .github/workflows/develop-push.yml | 5 +++ Monal/Classes/xmpp.m | 1 - scripts/build.sh | 2 +- scripts/updateLocalization.sh | 58 +++++++++++++++++++++++++----- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/.github/workflows/develop-push.yml b/.github/workflows/develop-push.yml index c1588fe561..63c62120ca 100644 --- a/.github/workflows/develop-push.yml +++ b/.github/workflows/develop-push.yml @@ -84,3 +84,8 @@ jobs: # name: monal-ios-dsym # path: Monal/build/ios_Monal.xcarchive/dSYMs # if-no-files-found: error + # - name: Update translations + # run: | + # chmod +x ./scripts/updateLocalization.sh + # chmod +x ./scripts/xliff_extractor.py + # ./scripts/updateLocalization.sh NOCOMMIT diff --git a/Monal/Classes/xmpp.m b/Monal/Classes/xmpp.m index 55d4e3ca86..ec53c2b94d 100644 --- a/Monal/Classes/xmpp.m +++ b/Monal/Classes/xmpp.m @@ -47,7 +47,6 @@ #import "AESGcm.h" @import AVFoundation; -@import WebRTC; #define STATE_VERSION 15 #define CONNECT_TIMEOUT 7.0 diff --git a/scripts/build.sh b/scripts/build.sh index 1d2823dff4..9bcb101369 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -102,7 +102,7 @@ xcrun xcodebuild \ -configuration $BUILD_TYPE \ -archivePath "build/ios_$APP_NAME.xcarchive" \ -allowProvisioningUpdates \ - clean archive + archive echo "" echo "*************************" diff --git a/scripts/updateLocalization.sh b/scripts/updateLocalization.sh index 459a5fd9dc..8460bc0c36 100755 --- a/scripts/updateLocalization.sh +++ b/scripts/updateLocalization.sh @@ -9,7 +9,12 @@ if ! which bartycrouch > /dev/null; then echo "ERROR: BartyCrouch not installed, download it from https://github.com/Flinesoft/BartyCrouch" exit 1 fi - + +SWIFT_EMIT_LOC_STRINGS=NO +if [ "$2" != "" ]; then + SWIFT_EMIT_LOC_STRINGS="$2" +fi + function pullCurrentState { #subshell to not leak from "cd $folder" ( @@ -58,10 +63,30 @@ function runBartycrouch { bartycrouch lint -x -w } +echo "" +echo "***************************************" +echo "* Initializing submodules *" +echo "***************************************" git submodule deinit --all -f git submodule update --init --recursive --remote pullCurrentState "$@" +echo "" +echo "*******************************************" +echo "* Building rust packages & bridge *" +echo "*******************************************" +bash ../rust/build-rust.sh + +echo "" +echo "***************************************" +echo "* Installing macOS & iOS Pods *" +echo "***************************************" +pod install --repo-update + +echo "" +echo "***************************************" +echo "* Removing unused strings *" +echo "***************************************" # update strings to remove everything that's now unused (that includes swiftui strings we'll readd below) cp .bartycrouch.toml .bartycrouch.toml.orig sed 's/additive = true/additive = false/g' .bartycrouch.toml > .bartycrouch.toml.new @@ -70,23 +95,26 @@ mv .bartycrouch.toml.new .bartycrouch.toml runBartycrouch rm .bartycrouch.toml mv .bartycrouch.toml.orig .bartycrouch.toml - # now restore original state for all languages but our base one (otherwise every swiftui translation will be deleted) mv "localization/external/Base.lproj/Localizable.strings" "localization/external/Base.lproj/Localizable.strings.updated" pullCurrentState "$@" mv "localization/external/Base.lproj/Localizable.strings.updated" "localization/external/Base.lproj/Localizable.strings" -# extract xliff file (has to be run multiple times, even if no error occured, don't ask me why) -# we use grep here to test for a dummy string to detect if our run succeeded +echo "" +echo "***************************************" +echo "* Extracting xliff files *" +echo "***************************************" if [ -e localization.tmp ]; then rm -rf localization.tmp fi +# extract xliff file (has to be run multiple times, even if no error occured, don't ask me why) +# we use grep here to test for a dummy string to detect if our run succeeded dummy="DON'T TRANSLATE: $(head /dev/urandom | LC_ALL=C tr -dc A-Za-z0-9 | head -c 8)" -echo "\nlet swiftuiTranslationRandomDummyString = Text(\"$dummy\")" >> Classes/SwiftuiHelpers.swift +#echo "\nlet swiftuiTranslationRandomDummyString = Text(\"$dummy\")" >> Classes/SwiftuiHelpers.swift x=$((1)) while [[ $x -lt 16 ]]; do echo "STARTING RUN $x..." - while ! xcrun xcodebuild -exportLocalizations -localizationPath localization.tmp -exportLanguage base SWIFT_EMIT_LOC_STRINGS=NO; do + while ! xcrun xcodebuild -workspace "Monal.xcworkspace" -scheme "Monal" -sdk iphoneos -configuration "Beta" -allowProvisioningUpdates -exportLocalizations -localizationPath localization.tmp -exportLanguage base SWIFT_EMIT_LOC_STRINGS=$SWIFT_EMIT_LOC_STRINGS; do echo "ERROR, TRYING AGAIN..." done echo "RUN $x SUCCEEDED, EXTRACTING STRINGS FROM XLIFF!" @@ -94,20 +122,27 @@ while [[ $x -lt 16 ]]; do ../scripts/xliff_extractor.py -x "localization.tmp/base.xcloc/Localized Contents/base.xliff" x=$((x+1)) done -rm -rf *A\ Document\ Being\ Saved\ By\ xcodebuild* if ! grep -q "$dummy" "localization/external/Base.lproj/Localizable.strings"; then echo "Could not extract dummy string after $x runs!" - exit 1 + #exit 1 fi awk "!/$dummy/" "localization/external/Base.lproj/Localizable.strings" > "localization/external/Base.lproj/Localizable.strings.new" mv "localization/external/Base.lproj/Localizable.strings.new" "localization/external/Base.lproj/Localizable.strings" +rm -rf *A\ Document\ Being\ Saved\ By\ xcodebuild* +echo "" +echo "*********************************************************" +echo "* Using batrycrouch to update all languages *" +echo "*********************************************************" runBartycrouch - if [ -e localization.tmp ]; then rm -rf localization.tmp fi +echo "" +echo "*******************************************" +echo "* Showing results as git diff *" +echo "*******************************************" for folder in "localization/external" "shareSheet-iOS/localization/external"; do #subshell to not leak from "cd $folder" ( @@ -125,6 +160,11 @@ for folder in "localization/external" "shareSheet-iOS/localization/external"; do ) done +echo "" +echo "***************************************" +echo "* Cleaning up submodules *" +echo "***************************************" git submodule deinit --all -f git submodule update --init --recursive + exit 0 From fad2b7672b1d89da7e97a58fb2777b87e8bd43a2 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 05:50:58 +0200 Subject: [PATCH 13/23] Make Toggle() translatable Without setting SWIFT_EMIT_LOC_STRINGS=YES, only Text() views are translatable. But we can't set SWIFT_EMIT_LOC_STRINGS=YES, because this tries to compile the whole project and always fails when importing the WebRTC lib. Switching from cocoapods to SPM for the WebRTC lib makes the project compile (even for extracting localizable strings), but crash early when starting the app (even before main.m is reached). This seems to be a dylib loading issue. --- Monal/Classes/AddContactMenu.swift | 4 +- Monal/Classes/ContactDetails.swift | 11 +++--- Monal/Classes/DebugView.swift | 4 +- Monal/Classes/PrivacySettings.swift | 60 +++++++++++++++++++++-------- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/Monal/Classes/AddContactMenu.swift b/Monal/Classes/AddContactMenu.swift index fc63decb89..92ea6e2592 100644 --- a/Monal/Classes/AddContactMenu.swift +++ b/Monal/Classes/AddContactMenu.swift @@ -198,9 +198,9 @@ struct AddContactMenu: View { } if(scannedFingerprints != nil && scannedFingerprints!.count > 0) { Section(header: Text("A contact was scanned through the QR code scanner")) { - Toggle(isOn: $importScannedFingerprints, label: { + Toggle(isOn: $importScannedFingerprints) { Text("Import and trust OMEMO fingerprints from QR code") - }) + } } } Section { diff --git a/Monal/Classes/ContactDetails.swift b/Monal/Classes/ContactDetails.swift index 1f3af26879..a4fdd48f8b 100644 --- a/Monal/Classes/ContactDetails.swift +++ b/Monal/Classes/ContactDetails.swift @@ -140,15 +140,14 @@ struct ContactDetails: View { .addClearButton(isEditing: isEditingNickname, text: $contact.nickNameView) } - Toggle("Pin Chat", isOn: Binding(get: { + Toggle(isOn: Binding(get: { contact.isPinned }, set: { contact.obj.togglePinnedChat($0) - })) -// Button(contact.isPinned ? "Unpin Chat" : "Pin Chat") { -// contact.obj.togglePinnedChat(!contact.isPinned); -// } - + })) { + Text("Pin Chat") + } + if(contact.obj.isGroup && contact.obj.mucType == "group") { NavigationLink(destination: LazyClosureView(MemberList(mucContact:contact))) { Text("Group Members") diff --git a/Monal/Classes/DebugView.swift b/Monal/Classes/DebugView.swift index 6f5d4cb7d9..7fe70c6121 100644 --- a/Monal/Classes/DebugView.swift +++ b/Monal/Classes/DebugView.swift @@ -100,7 +100,9 @@ struct UDPConfigView: View { Text("The UDP logger allows you to livestream the log to the configured IP. Please use a secure key when streaming over the internet!\n[Learn how to receive the log stream](https://github.com/monal-im/Monal/wiki/Introduction-to-Monal-Logging#stream-the-log).") Form { Section(header: Text("UDP Logger Configuration")) { - Toggle("Enable", isOn: $defaultDB.udpLoggerEnabled) + Toggle(isOn: $defaultDB.udpLoggerEnabled) { + Text("Enable") + } LabeledContent("Logserver IP:") { TextField("Logserver IP", text: $defaultDB.udpLoggerHostname, prompt: Text("Required")) } diff --git a/Monal/Classes/PrivacySettings.swift b/Monal/Classes/PrivacySettings.swift index a67faaa546..88bf69bda4 100644 --- a/Monal/Classes/PrivacySettings.swift +++ b/Monal/Classes/PrivacySettings.swift @@ -152,8 +152,12 @@ struct PrivacyScreen: View { Text(getNotificationPrivacyOption(option)).tag(option.rawValue) } } - Toggle("Enable encryption by default for new chats", isOn: $privacyDefaultDB.omemoDefaultOn) - Toggle("Autodelete all messages after 3 days", isOn: $privacyDefaultDB.autodeleteAllMessagesAfter3Days) + Toggle(isOn: $privacyDefaultDB.omemoDefaultOn) { + Text("Enable encryption by default for new chats") + } + Toggle(isOn: $privacyDefaultDB.autodeleteAllMessagesAfter3Days) { + Text("Autodelete all messages after 3 days") + } } .navigationBarTitle("Privacy & security", displayMode: .inline) } @@ -165,13 +169,23 @@ struct PublishingScreen: View { var body: some View { Form { Section(header: Text("Publishing")) { - Toggle("Send last interaction time", isOn: $privacyDefaultDB.sendLastUserInteraction) - Toggle("Send typing notifications", isOn: $privacyDefaultDB.sendLastChatState) - Toggle("Send message received state", isOn: $privacyDefaultDB.sendReceivedMarkers) - Toggle("Send message displayed state", isOn: $privacyDefaultDB.sendDisplayedMarkers) + Toggle(isOn: $privacyDefaultDB.sendLastUserInteraction) { + Text("Send last interaction time") + } + Toggle(isOn: $privacyDefaultDB.sendLastChatState) { + Text("Send typing notifications") + } + Toggle(isOn: $privacyDefaultDB.sendReceivedMarkers) { + Text("Send message received state") + } + Toggle(isOn: $privacyDefaultDB.sendDisplayedMarkers) { + Text("Send message displayed state") + } } Section(header: Text("Appearance")) { - Toggle("Autofocus text input on chat open", isOn: $privacyDefaultDB.showKeyboardOnChatOpen) + Toggle(isOn: $privacyDefaultDB.showKeyboardOnChatOpen) { + Text("Autofocus text input on chat open") + } } } .navigationBarTitle("Publishing & appearance", displayMode: .inline) @@ -183,8 +197,12 @@ struct PreviewsScreen: View { var body: some View { Form { - Toggle("Show inline geo location", isOn: $privacyDefaultDB.showGeoLocation) - Toggle("Show URL previews", isOn: $privacyDefaultDB.showURLPreview) + Toggle(isOn: $privacyDefaultDB.showGeoLocation) { + Text("Show inline geo location") + } + Toggle(isOn: $privacyDefaultDB.showURLPreview) { + Text("Show URL previews") + } } .navigationBarTitle("Previews", displayMode: .inline) } @@ -195,11 +213,21 @@ struct CommunicationScreen: View { var body: some View { Form { - Toggle("Allow contacts not in my contact list to contact me", isOn: $privacyDefaultDB.allowNonRosterContacts) - Toggle("Allow approved contacts to query my Monal and iOS version", isOn: $privacyDefaultDB.allowVersionIQ) - Toggle("Calls: Allow contacts not in my contact list to call me", isOn: $privacyDefaultDB.allowCallsFromNonRosterContacts) - Toggle("Calls: Allow P2P sessions", isOn: $privacyDefaultDB.webrtcAllowP2P) - Toggle("Calls: Allow TURN fallback to Monal-Servers", isOn: $privacyDefaultDB.webrtcUseFallbackTurn) + Toggle(isOn: $privacyDefaultDB.allowNonRosterContacts) { + Text("Allow contacts not in my contact list to contact me") + } + Toggle(isOn: $privacyDefaultDB.allowVersionIQ) { + Text("Allow approved contacts to query my Monal and iOS version") + } + Toggle(isOn: $privacyDefaultDB.allowCallsFromNonRosterContacts) { + Text("Calls: Allow contacts not in my contact list to call me") + } + Toggle(isOn: $privacyDefaultDB.webrtcAllowP2P) { + Text("Calls: Allow P2P sessions") + } + Toggle(isOn: $privacyDefaultDB.webrtcUseFallbackTurn) { + Text("Calls: Allow TURN fallback to Monal-Servers") + } } .navigationBarTitle("Communication", displayMode: .inline) } @@ -211,7 +239,9 @@ struct MLAutoDownloadFiletransferSettingView: View { var body: some View { Form { Section(header: Text("General File Transfer Settings")) { - Toggle("Auto-Download Media", isOn: $privacyDefaultDB.autodownloadFiletransfers) + Toggle(isOn: $privacyDefaultDB.autodownloadFiletransfers) { + Text("Auto-Download Media") + } } Section(header: Text("Download Settings")) { From 91e943a8990b76f93ef9daf8b4259a044efdc024 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 20:18:20 +0200 Subject: [PATCH 14/23] Clean up "omemo not posible" code --- Monal/Classes/chatViewController.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Monal/Classes/chatViewController.m b/Monal/Classes/chatViewController.m index 01264ac896..d2718adaa0 100644 --- a/Monal/Classes/chatViewController.m +++ b/Monal/Classes/chatViewController.m @@ -813,7 +813,7 @@ -(void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; #ifndef DISABLE_OMEMO - if(self.xmppAccount) + if(self.xmppAccount && [[DataLayer sharedInstance] isAccountEnabled:self.xmppAccount.accountNo]) { BOOL omemoDeviceForContactFound = NO; if(!self.contact.isGroup) @@ -831,7 +831,7 @@ -(void) viewDidAppear:(BOOL)animated break; } } - if(!omemoDeviceForContactFound && self.contact.isEncrypted && [[DataLayer sharedInstance] isAccountEnabled:self.xmppAccount.accountNo]) + if(!omemoDeviceForContactFound && self.contact.isEncrypted) { if(!self.contact.isGroup && [[HelperTools splitJid:self.contact.contactJid][@"host"] isEqualToString:@"cheogram.com"]) { From 82a4b71a2aa47ac6cf980bfaff396dec25e1e793 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 20:24:47 +0200 Subject: [PATCH 15/23] Change height to fit notification privacy picker items --- Monal/Classes/PrivacySettings.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Monal/Classes/PrivacySettings.swift b/Monal/Classes/PrivacySettings.swift index 88bf69bda4..e576447538 100644 --- a/Monal/Classes/PrivacySettings.swift +++ b/Monal/Classes/PrivacySettings.swift @@ -152,6 +152,7 @@ struct PrivacyScreen: View { Text(getNotificationPrivacyOption(option)).tag(option.rawValue) } } + .frame(width: .infinity, height: 56, alignment: .trailing) Toggle(isOn: $privacyDefaultDB.omemoDefaultOn) { Text("Enable encryption by default for new chats") } From bb386e5f00d8ae9f2ae2f81c252a605ca41daf4d Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 21:14:12 +0200 Subject: [PATCH 16/23] Show muc server in server details --- Monal/Classes/MLServerDetails.m | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Monal/Classes/MLServerDetails.m b/Monal/Classes/MLServerDetails.m index 2b079b5f53..2247c7b2e4 100644 --- a/Monal/Classes/MLServerDetails.m +++ b/Monal/Classes/MLServerDetails.m @@ -16,6 +16,7 @@ @interface MLServerDetails () @property (nonatomic, strong) MLContactSoftwareVersionInfo* serverVersion; @property (nonatomic, strong) NSMutableArray* serverCaps; +@property (nonatomic, strong) NSMutableArray* mucServers; @property (nonatomic, strong) NSMutableArray* stunTurnServers; @property (nonatomic, strong) NSMutableArray* srvRecords; @property (nonatomic, strong) NSMutableArray* tlsVersions; @@ -30,6 +31,7 @@ @implementation MLServerDetails enum MLServerDetailsSections { SERVER_VERSION_SECTION, SUPPORTED_SERVER_XEPS_SECTION, + MUC_SERVERS_SECTION, VOIP_SECTION, SRV_RECORS_SECTION, TLS_SECTION, @@ -52,6 +54,7 @@ -(void) viewWillAppear:(BOOL) animated { [super viewWillAppear:animated]; self.serverCaps = [NSMutableArray new]; + self.mucServers = [NSMutableArray new]; self.stunTurnServers = [NSMutableArray new]; self.srvRecords = [NSMutableArray new]; self.tlsVersions = [NSMutableArray new]; @@ -63,6 +66,7 @@ -(void) viewWillAppear:(BOOL) animated self.serverVersion = self.xmppAccount.connectionProperties.serverVersion; [self checkServerCaps:self.xmppAccount.connectionProperties]; + [self checkMucServers:self.xmppAccount.connectionProperties]; [self convertSRVRecordsToReadable]; [self checkTLSVersions:self.xmppAccount.connectionProperties]; [self checkSASLMethods:self.xmppAccount.connectionProperties]; @@ -171,6 +175,19 @@ -(void) checkServerCaps:(MLXMPPConnection*) connection }]; } +-(void) checkMucServers:(MLXMPPConnection*) connection +{ + DDLogVerbose(@"Checking muc servers: %@", connection.conferenceServer); + //yes, checkMucServers: is plural, but for now, our connectionProperties only store one single muc server (the first one encountered) + if(connection.conferenceServer == nil || [@"" isEqualToString:connection.conferenceServer]) + { + [self.mucServers addObject:@{@"Title": NSLocalizedString(@"None", @""), @"Description":NSLocalizedString(@"This server does not provide any MUC servers.", @""), @"Color":SERVER_DETAILS_COLOR_ERROR}]; + return; + } + [self.mucServers addObject:@{@"Title": [NSString stringWithFormat:NSLocalizedString(@"Server: %@", @""), connection.conferenceServer], @"Description": NSLocalizedString(@"Conference server for Channels and Groups", @""), @"Color": SERVER_DETAILS_COLOR_OK}]; + DDLogVerbose(@"Muc server entries: %@", self.mucServers); +} + -(void) checkStunServers:(NSMutableArray*) stunTurnServers { for(NSDictionary* service in stunTurnServers) @@ -301,6 +318,8 @@ -(NSInteger) tableView:(UITableView*) tableView numberOfRowsInSection:(NSInteger return 1; else if(section == SUPPORTED_SERVER_XEPS_SECTION) return (NSInteger)self.serverCaps.count; + else if(section == MUC_SERVERS_SECTION) + return (NSInteger)self.mucServers.count; else if(section == VOIP_SECTION) return (NSInteger)self.stunTurnServers.count; else if(section == SRV_RECORS_SECTION) @@ -335,7 +354,9 @@ -(UITableViewCell*) tableView:(UITableView*) tableView cellForRowAtIndexPath:(NS } else if(indexPath.section == SUPPORTED_SERVER_XEPS_SECTION) dic = [self.serverCaps objectAtIndex:(NSUInteger)indexPath.row]; - if(indexPath.section == VOIP_SECTION) + else if(indexPath.section == MUC_SERVERS_SECTION) + dic = [self.mucServers objectAtIndex:(NSUInteger)indexPath.row]; + else if(indexPath.section == VOIP_SECTION) dic = [self.stunTurnServers objectAtIndex:(NSUInteger)indexPath.row]; else if(indexPath.section == SRV_RECORS_SECTION) dic = [self.srvRecords objectAtIndex:(NSUInteger)indexPath.row]; @@ -390,8 +411,10 @@ -(NSString*) tableView:(UITableView*) tableView titleForHeaderInSection:(NSInteg return NSLocalizedString(@"This is the software running on your server.", @""); else if(section == SUPPORTED_SERVER_XEPS_SECTION) return NSLocalizedString(@"These are the modern XMPP capabilities Monal detected on your server after you have logged in.", @""); + else if(section == MUC_SERVERS_SECTION) + return NSLocalizedString(@"These are the MUC servers detected by Monal.", @""); else if(section == VOIP_SECTION) - return NSLocalizedString(@"These are STUN and TURN services announced by your server. (blue entries are used by monal)", @""); + return NSLocalizedString(@"These are STUN and TURN services announced by your server (blue entries are used by Monal).", @""); else if(section == SRV_RECORS_SECTION) return NSLocalizedString(@"These are SRV resource records found for your domain.", @""); else if(section == TLS_SECTION) From 4e6df1b23d50ed175512f54329c213f264b91687 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 22:25:42 +0200 Subject: [PATCH 17/23] Fix muc error display, fix muc server discovery, cleanup code --- Monal/Classes/AddContactMenu.swift | 20 +++++------ Monal/Classes/CreateGroupMenu.swift | 55 ++++++++++++++++------------- Monal/Classes/LoadingOverlay.swift | 12 +++++++ Monal/Classes/MLIQProcessor.m | 4 +-- Monal/Classes/MLMucProcessor.h | 3 +- Monal/Classes/MLMucProcessor.m | 24 ++++++++++--- Monal/Classes/MLServerDetails.m | 24 +++++++------ Monal/Classes/MLXMPPConnection.h | 2 +- Monal/Classes/MLXMPPConnection.m | 1 + Monal/Classes/xmpp.m | 11 +++--- 10 files changed, 98 insertions(+), 58 deletions(-) diff --git a/Monal/Classes/AddContactMenu.swift b/Monal/Classes/AddContactMenu.swift index 92ea6e2592..313570b9d8 100644 --- a/Monal/Classes/AddContactMenu.swift +++ b/Monal/Classes/AddContactMenu.swift @@ -136,7 +136,7 @@ struct AddContactMenu: View { } showLoadingOverlay(overlay, headline: NSLocalizedString("Adding...", comment: "")) account.checkJidType(jid, withCompletion: { type, errorMsg in - if(type == "account") { + if type == "account" { hideLoadingOverlay(overlay) let contact = MLContact.createContact(fromJid: jid, andAccountNo: account.accountNo) self.newContact = contact @@ -144,16 +144,16 @@ struct AddContactMenu: View { //import omemo fingerprints as manually trusted, if requested trustFingerprints(self.importScannedFingerprints ? self.scannedFingerprints : [:], for:jid, on:account) successAlert(title: Text("Permission Requested"), message: Text("The new contact will be added to your contacts list when the person you've added has approved your request.")) - } else if(type == "muc") { + } else if type == "muc" { showLoadingOverlay(overlay, headline: NSLocalizedString("Adding Group/Channel...", comment: "")) account.mucProcessor.addUIHandler({data in let success : Bool = (data as! NSDictionary)["success"] as! Bool; hideLoadingOverlay(overlay) - if(success) { + if success { self.newContact = MLContact.createContact(fromJid: jid, andAccountNo: account.accountNo) successAlert(title: Text("Success!"), message: Text(String.localizedStringWithFormat("Successfully joined group/channel %@!", jid))) } else { - errorAlert(title: Text("Error entering group/channel!")) + errorAlert(title: Text("Error entering group/channel!"), message: Text((data as! NSDictionary)["errorMessage"] as! String)) } }, forMuc: jid) account.joinMuc(jid) @@ -168,14 +168,14 @@ struct AddContactMenu: View { let account = self.connectedAccounts[selectedAccount] let splitJid = HelperTools.splitJid(account.connectionProperties.identity.jid) Form { - if(connectedAccounts.isEmpty) { + if connectedAccounts.isEmpty { Text("Please make sure at least one account has connected before trying to add a contact or channel.") .foregroundColor(.secondary) } else { Section(header:Text("Contact and Group/Channel Jids are usually in the format: name@domain.tld")) { - if(connectedAccounts.count > 1) { + if connectedAccounts.count > 1 { Picker("Use account", selection: $selectedAccount) { ForEach(Array(self.connectedAccounts.enumerated()), id: \.element) { idx, account in Text(account.connectionProperties.identity.jid).tag(idx) @@ -196,7 +196,7 @@ struct AddContactMenu: View { toAdd = toAdd.replacingOccurrences(of: " ", with: "") } } - if(scannedFingerprints != nil && scannedFingerprints!.count > 0) { + if scannedFingerprints != nil && scannedFingerprints!.count > 0 { Section(header: Text("A contact was scanned through the QR code scanner")) { Toggle(isOn: $importScannedFingerprints) { Text("Import and trust OMEMO fingerprints from QR code") @@ -204,7 +204,7 @@ struct AddContactMenu: View { } } Section { - if(scannedFingerprints != nil) { + if scannedFingerprints != nil { Button(action: { toAdd = "" importScannedFingerprints = true @@ -217,9 +217,9 @@ struct AddContactMenu: View { Button(action: { showAlert = toAddEmptyAlert || toAddInvalidAlert - if(!showAlert) { + if !showAlert { let jidComponents = HelperTools.splitJid(toAdd) - if(jidComponents["host"] == nil || jidComponents["host"]!.isEmpty) { + if jidComponents["host"] == nil || jidComponents["host"]!.isEmpty { errorAlert(title: Text("Error"), message: Text("Something went wrong while parsing the string...")) showAlert = true return diff --git a/Monal/Classes/CreateGroupMenu.swift b/Monal/Classes/CreateGroupMenu.swift index d88db79a82..025f7e5a37 100644 --- a/Monal/Classes/CreateGroupMenu.swift +++ b/Monal/Classes/CreateGroupMenu.swift @@ -47,7 +47,7 @@ struct CreateGroupMenu: View { var body: some View { Form { - if(connectedAccounts.isEmpty) { + if connectedAccounts.isEmpty { Text("Please make sure at least one account has connected before trying to create new group.") .foregroundColor(.secondary) } @@ -70,41 +70,46 @@ struct CreateGroupMenu: View { Text("Change Group Members") }) Button(action: { + guard let generatedJid = self.selectedAccount!.mucProcessor.generateMucJid() else { + errorAlert(title: Text("Error creating group!"), message: Text("Your server does not provide a MUC component.")) + return + } showLoadingOverlay(overlay, headline: NSLocalizedString("Creating Group", comment: "")) - let roomJid = self.selectedAccount!.mucProcessor.createGroup(nil) - if(roomJid == nil) { - let groupContact = MLContact.createContact(fromJid: roomJid!, andAccountNo: self.selectedAccount!.accountNo) + guard let roomJid = self.selectedAccount!.mucProcessor.createGroup(generatedJid) else { + //room already existing in our local bookmarks --> just open it + //this should never happen since we randomly generated a jid above hideLoadingOverlay(overlay) + let groupContact = MLContact.createContact(fromJid: generatedJid, andAccountNo: self.selectedAccount!.accountNo) self.delegate.dismissWithoutAnimation() if let activeChats = self.appDelegate.activeChats { activeChats.presentChat(with:groupContact) } - } else { - self.selectedAccount!.mucProcessor.addUIHandler({data in - let success : Bool = (data as! NSDictionary)["success"] as! Bool; - if(success) { - self.selectedAccount!.mucProcessor.changeName(ofMuc: roomJid!, to: self.groupName) - for user in self.selectedContacts { - self.selectedAccount!.mucProcessor.setAffiliation("member", ofUser: user.contactJid, inMuc: roomJid!) - self.selectedAccount!.mucProcessor.inviteUser(user.contactJid, inMuc: roomJid!) - } - let groupContact = MLContact.createContact(fromJid: roomJid!, andAccountNo: self.selectedAccount!.accountNo) - hideLoadingOverlay(overlay) - self.delegate.dismissWithoutAnimation() - if let activeChats = self.appDelegate.activeChats { - activeChats.presentChat(with:groupContact) - } - } else { - hideLoadingOverlay(overlay) - errorAlert(title: Text("Error creating group!")) - } - }, forMuc: roomJid!) + return } + self.selectedAccount!.mucProcessor.addUIHandler({data in + let success : Bool = (data as! NSDictionary)["success"] as! Bool; + if success { + self.selectedAccount!.mucProcessor.changeName(ofMuc: roomJid, to: self.groupName) + for user in self.selectedContacts { + self.selectedAccount!.mucProcessor.setAffiliation("member", ofUser: user.contactJid, inMuc: roomJid) + self.selectedAccount!.mucProcessor.inviteUser(user.contactJid, inMuc: roomJid) + } + let groupContact = MLContact.createContact(fromJid: roomJid, andAccountNo: self.selectedAccount!.accountNo) + hideLoadingOverlay(overlay) + self.delegate.dismissWithoutAnimation() + if let activeChats = self.appDelegate.activeChats { + activeChats.presentChat(with:groupContact) + } + } else { + hideLoadingOverlay(overlay) + errorAlert(title: Text("Error creating group!"), message: Text((data as! NSDictionary)["errorMessage"] as! String)) + } + }, forMuc: roomJid) }, label: { Text("Create new group") }) } - if(self.selectedContacts.count > 0) { + if self.selectedContacts.count > 0 { Section(header: Text("Selected Group Members")) { ForEach(self.selectedContacts, id: \.obj.contactJid) { contact in ContactEntry(contact: contact) diff --git a/Monal/Classes/LoadingOverlay.swift b/Monal/Classes/LoadingOverlay.swift index bb8f0d4f62..49450045a0 100644 --- a/Monal/Classes/LoadingOverlay.swift +++ b/Monal/Classes/LoadingOverlay.swift @@ -61,6 +61,10 @@ func showLoadingOverlay(_ overlay: LoadingOverlayState, headli overlay.enabled = true //only rerender ui once (not sure if this optimization is really needed, if this is missing, use @Published for member vars of state class) overlay.objectWillChange.send() + //make sure to really draw the overlay on race conditions + DispatchQueue.main.asyncAfter(deadline: .now() + 0.250) { + overlay.objectWillChange.send() + } } } @@ -71,6 +75,10 @@ func showLoadingOverlay(_ overlay: LoadingOverlayState, headli overlay.enabled = true //only rerender ui once (not sure if this optimization is really needed, if this is missing, use @Published for member vars of state class) overlay.objectWillChange.send() + //make sure to really draw the overlay on race conditions + DispatchQueue.main.asyncAfter(deadline: .now() + 0.250) { + overlay.objectWillChange.send() + } } } @@ -81,6 +89,10 @@ func hideLoadingOverlay(_ overlay: LoadingOverlayState) { overlay.enabled = false //only rerender ui once (not sure if this optimization is really needed, if this is missing, use @Published for member vars of state class) overlay.objectWillChange.send() + //make sure to really draw the overlay on race conditions + DispatchQueue.main.asyncAfter(deadline: .now() + 0.250) { + overlay.objectWillChange.send() + } } } diff --git a/Monal/Classes/MLIQProcessor.m b/Monal/Classes/MLIQProcessor.m index fcb64a0337..8aaa03660c 100644 --- a/Monal/Classes/MLIQProcessor.m +++ b/Monal/Classes/MLIQProcessor.m @@ -561,8 +561,8 @@ +(BOOL) processRosterWithAccount:(xmpp*) account andIqNode:(XMPPIQ*) iqNode DDLogInfo(@"Upload max filesize: %lu", account.connectionProperties.uploadSize); } - if(!account.connectionProperties.conferenceServer && [features containsObject:@"http://jabber.org/protocol/muc"]) - account.connectionProperties.conferenceServer = iqNode.fromUser; + if([features containsObject:@"http://jabber.org/protocol/muc"]) + account.connectionProperties.conferenceServers[iqNode.fromUser] = [iqNode findFirst:@"{http://jabber.org/protocol/disco#info}query"]; $$ $$class_handler(handleServerDiscoItems, $$ID(xmpp*, account), $$ID(XMPPIQ*, iqNode)) diff --git a/Monal/Classes/MLMucProcessor.h b/Monal/Classes/MLMucProcessor.h index 2e06ecf3d2..f3d82f8f65 100644 --- a/Monal/Classes/MLMucProcessor.h +++ b/Monal/Classes/MLMucProcessor.h @@ -26,7 +26,8 @@ NS_ASSUME_NONNULL_BEGIN -(void) leave:(NSString*) room withBookmarksUpdate:(BOOL) updateBookmarks keepBuddylistEntry:(BOOL) keepBuddylistEntry; //muc management methods --(NSString* _Nullable) createGroup:(NSString* _Nullable) node; +-(NSString* _Nullable) generateMucJid; +-(NSString* _Nullable) createGroup:(NSString*) room; -(void) changeNameOfMuc:(NSString*) room to:(NSString*) name; -(void) changeSubjectOfMuc:(NSString*) room to:(NSString*) subject; -(void) publishAvatar:(UIImage* _Nullable) image forMuc:(NSString*) room; diff --git a/Monal/Classes/MLMucProcessor.m b/Monal/Classes/MLMucProcessor.m index 7a698f4b6c..75a846bb85 100644 --- a/Monal/Classes/MLMucProcessor.m +++ b/Monal/Classes/MLMucProcessor.m @@ -191,6 +191,7 @@ -(void) addUIHandler:(monal_id_block_t) handler forMuc:(NSString*) room { //this will replace the old handler @synchronized(_stateLockObject) { + DDLogVerbose(@"Adding ui handler for muc: %@", room); _uiHandler[room] = handler; } } @@ -849,12 +850,27 @@ -(void) handleStatusCodes:(XMPPStanza*) node [self handleError:[NSString stringWithFormat:NSLocalizedString(@"Could not create group '%@': timeout", @""), room] forMuc:room withNode:nil andIsSevere:YES]; $$ --(NSString* _Nullable) createGroup:(NSString* _Nullable) node +-(NSString* _Nullable) generateMucJid { - if(node == nil) - node = [self generateSpeakableGroupNode]; + NSString* mucServer = nil; + for(NSString* jid in _account.connectionProperties.conferenceServers) + { + if([_account.connectionProperties.conferenceServers[jid] check:@"identity"]) + { + mucServer = jid; + break; + } + } + if(mucServer == nil) + return nil; + NSString* node = [self generateSpeakableGroupNode]; node = [node stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet].lowercaseString; - NSString* room = [[NSString stringWithFormat:@"%@@%@", node, _account.connectionProperties.conferenceServer] lowercaseString]; + NSString* room = [[NSString stringWithFormat:@"%@@%@", node, mucServer] lowercaseString]; + return room; +} + +-(NSString* _Nullable) createGroup:(NSString*) room +{ if([[DataLayer sharedInstance] isBuddyMuc:room forAccount:_account.accountNo]) { DDLogWarn(@"Cannot create muc already existing in our buddy list, checking if we are still joined and join if needed..."); diff --git a/Monal/Classes/MLServerDetails.m b/Monal/Classes/MLServerDetails.m index 2247c7b2e4..6b067c7c0a 100644 --- a/Monal/Classes/MLServerDetails.m +++ b/Monal/Classes/MLServerDetails.m @@ -177,15 +177,19 @@ -(void) checkServerCaps:(MLXMPPConnection*) connection -(void) checkMucServers:(MLXMPPConnection*) connection { - DDLogVerbose(@"Checking muc servers: %@", connection.conferenceServer); + DDLogVerbose(@"Checking muc servers: %@", connection.conferenceServers); //yes, checkMucServers: is plural, but for now, our connectionProperties only store one single muc server (the first one encountered) - if(connection.conferenceServer == nil || [@"" isEqualToString:connection.conferenceServer]) + if(connection.conferenceServers.count == 0) { [self.mucServers addObject:@{@"Title": NSLocalizedString(@"None", @""), @"Description":NSLocalizedString(@"This server does not provide any MUC servers.", @""), @"Color":SERVER_DETAILS_COLOR_ERROR}]; return; } - [self.mucServers addObject:@{@"Title": [NSString stringWithFormat:NSLocalizedString(@"Server: %@", @""), connection.conferenceServer], @"Description": NSLocalizedString(@"Conference server for Channels and Groups", @""), @"Color": SERVER_DETAILS_COLOR_OK}]; - DDLogVerbose(@"Muc server entries: %@", self.mucServers); + for(NSString* jid in connection.conferenceServers) + { + NSDictionary* entry = [connection.conferenceServers[jid] findFirst:@"identity@@"]; + [self.mucServers addObject:@{@"Title": [NSString stringWithFormat:NSLocalizedString(@"Server: %@", @""), jid], @"Description": [NSString stringWithFormat:NSLocalizedString(@"%@ (type '%@', category '%@')", @""), entry[@"name"], entry[@"type"], entry[@"category"]], @"Color": [@"text" isEqualToString:entry[@"type"]] ? SERVER_DETAILS_COLOR_OK : SERVER_DETAILS_COLOR_NONE}]; + } + DDLogVerbose(@"Extracted muc server entries: %@", self.mucServers); } -(void) checkStunServers:(NSMutableArray*) stunTurnServers @@ -231,7 +235,7 @@ -(void) convertSRVRecordsToReadable NSString* prio = [srvEntry objectForKey:@"priority"]; // Check if entry is currently in use - NSString* entryColor = @"None"; + NSString* entryColor = SERVER_DETAILS_COLOR_NONE; if([self.xmppAccount.connectionProperties.server.connectServer isEqualToString:hostname] && self.xmppAccount.connectionProperties.server.connectPort == port && self.xmppAccount.connectionProperties.server.isDirectTLS == [[srvEntry objectForKey:@"isSecure"] boolValue]) @@ -253,8 +257,8 @@ -(void) convertSRVRecordsToReadable -(void) checkTLSVersions:(MLXMPPConnection*) connection { DDLogVerbose(@"connection uses tls version: %@", connection.tlsVersion); - [self.tlsVersions addObject:@{@"Title": NSLocalizedString(@"TLS 1.2", @""), @"Description":NSLocalizedString(@"Older, slower, but still secure TLS version", @""), @"Color":([@"1.2" isEqualToString:connection.tlsVersion] ? SERVER_DETAILS_COLOR_OK : @"None")}]; - [self.tlsVersions addObject:@{@"Title": NSLocalizedString(@"TLS 1.3", @""), @"Description":NSLocalizedString(@"Newest TLS version which is faster than TLS 1.2", @""), @"Color":([@"1.3" isEqualToString:connection.tlsVersion] ? SERVER_DETAILS_COLOR_OK : @"None")}]; + [self.tlsVersions addObject:@{@"Title": NSLocalizedString(@"TLS 1.2", @""), @"Description":NSLocalizedString(@"Older, slower, but still secure TLS version", @""), @"Color":([@"1.2" isEqualToString:connection.tlsVersion] ? SERVER_DETAILS_COLOR_OK : SERVER_DETAILS_COLOR_NONE)}]; + [self.tlsVersions addObject:@{@"Title": NSLocalizedString(@"TLS 1.3", @""), @"Description":NSLocalizedString(@"Newest TLS version which is faster than TLS 1.2", @""), @"Color":([@"1.3" isEqualToString:connection.tlsVersion] ? SERVER_DETAILS_COLOR_OK : SERVER_DETAILS_COLOR_NONE)}]; DDLogVerbose(@"tls versions: %@", self.tlsVersions); } @@ -279,7 +283,7 @@ -(void) checkSASLMethods:(MLXMPPConnection*) connection description = NSLocalizedString(@"Salted Challenge Response Authentication Mechanism using the given Hash Method additionally secured by Channel-Binding", @""); else if([method hasPrefix:@"SCRAM-"]) description = NSLocalizedString(@"Salted Challenge Response Authentication Mechanism using the given Hash Method", @""); - [self.saslMethods addObject:@{@"Title": [NSString stringWithFormat:NSLocalizedString(@"Method: %@", @""), method], @"Description":description, @"Color":(used ? SERVER_DETAILS_COLOR_OK : (!supported ? SERVER_DETAILS_COLOR_NON_IDEAL : @"None"))}]; + [self.saslMethods addObject:@{@"Title": [NSString stringWithFormat:NSLocalizedString(@"Method: %@", @""), method], @"Description":description, @"Color":(used ? SERVER_DETAILS_COLOR_OK : (!supported ? SERVER_DETAILS_COLOR_NON_IDEAL : SERVER_DETAILS_COLOR_NONE))}]; } } @@ -301,7 +305,7 @@ -(void) checkChannelBindingTypes:(MLXMPPConnection*) connection description = NSLocalizedString(@"Secure channel-binding defined for TLS1.3 and some TLS1.2 connections.", @""); else if([type isEqualToString:@"tls-server-end-point"]) description = NSLocalizedString(@"Weakest channel-binding type, not securing against stolen certs/keys, but detects wrongly issued certs.", @""); - [self.channelBindingTypes addObject:@{@"Title": [NSString stringWithFormat:NSLocalizedString(@"Type: %@", @""), type], @"Description":description, @"Color":(used ? SERVER_DETAILS_COLOR_OK : (!supported ? SERVER_DETAILS_COLOR_NON_IDEAL : @"None"))}]; + [self.channelBindingTypes addObject:@{@"Title": [NSString stringWithFormat:NSLocalizedString(@"Type: %@", @""), type], @"Description":description, @"Color":(used ? SERVER_DETAILS_COLOR_OK : (!supported ? SERVER_DETAILS_COLOR_NON_IDEAL : SERVER_DETAILS_COLOR_NONE))}]; } } @@ -412,7 +416,7 @@ -(NSString*) tableView:(UITableView*) tableView titleForHeaderInSection:(NSInteg else if(section == SUPPORTED_SERVER_XEPS_SECTION) return NSLocalizedString(@"These are the modern XMPP capabilities Monal detected on your server after you have logged in.", @""); else if(section == MUC_SERVERS_SECTION) - return NSLocalizedString(@"These are the MUC servers detected by Monal.", @""); + return NSLocalizedString(@"These are the MUC servers detected by Monal (blue entry used by Monal).", @""); else if(section == VOIP_SECTION) return NSLocalizedString(@"These are STUN and TURN services announced by your server (blue entries are used by Monal).", @""); else if(section == SRV_RECORS_SECTION) diff --git a/Monal/Classes/MLXMPPConnection.h b/Monal/Classes/MLXMPPConnection.h index b9b1878fdc..8a6dce3592 100644 --- a/Monal/Classes/MLXMPPConnection.h +++ b/Monal/Classes/MLXMPPConnection.h @@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong) NSMutableDictionary* discoveredAdhocCommands; @property (nonatomic, strong) MLContactSoftwareVersionInfo* _Nullable serverVersion; -@property (nonatomic, strong) NSString* _Nullable conferenceServer; +@property (nonatomic, strong) NSMutableDictionary* conferenceServers; @property (nonatomic, assign) BOOL supportsHTTPUpload; @property (nonatomic, strong) NSString* _Nullable uploadServer; diff --git a/Monal/Classes/MLXMPPConnection.m b/Monal/Classes/MLXMPPConnection.m index a48857fb3e..b832a4124e 100644 --- a/Monal/Classes/MLXMPPConnection.m +++ b/Monal/Classes/MLXMPPConnection.m @@ -23,6 +23,7 @@ -(id) initWithServer:(MLXMPPServer*) server andIdentity:(MLXMPPIdentity*) identi self.server = server; self.identity = identity; self.serverFeatures = [NSSet new]; + self.conferenceServers = [NSMutableDictionary new]; self.discoveredServices = [NSMutableArray new]; self.discoveredStunTurnServers = [NSMutableArray new]; self.discoveredAdhocCommands = [NSMutableDictionary new]; diff --git a/Monal/Classes/xmpp.m b/Monal/Classes/xmpp.m index ec53c2b94d..ff776e3e21 100644 --- a/Monal/Classes/xmpp.m +++ b/Monal/Classes/xmpp.m @@ -48,7 +48,7 @@ @import AVFoundation; -#define STATE_VERSION 15 +#define STATE_VERSION 16 #define CONNECT_TIMEOUT 7.0 #define IQ_TIMEOUT 60.0 NSString* const kQueueID = @"queueID"; @@ -3495,8 +3495,9 @@ -(void) realPersistState if(self.connectionProperties.uploadServer) [values setObject:self.connectionProperties.uploadServer forKey:@"uploadServer"]; - if(self.connectionProperties.conferenceServer) - [values setObject:self.connectionProperties.conferenceServer forKey:@"conferenceServer"]; + + if(self.connectionProperties.conferenceServers) + [values setObject:self.connectionProperties.conferenceServers forKey:@"conferenceServers"]; [values setObject:[self.pubsub getInternalData] forKey:@"pubsubData"]; [values setObject:[self.mucProcessor getInternalState] forKey:@"mucState"]; @@ -3654,7 +3655,7 @@ -(void) realReadState self.connectionProperties.serverVersion = [dic objectForKey:@"serverVersion"]; self.connectionProperties.uploadServer = [dic objectForKey:@"uploadServer"]; - self.connectionProperties.conferenceServer = [dic objectForKey:@"conferenceServer"]; + self.connectionProperties.conferenceServers = [[dic objectForKey:@"conferenceServers"] mutableCopy]; if([dic objectForKey:@"loggedInOnce"]) { @@ -3928,7 +3929,7 @@ -(void) bindResource:(NSString*) resource self.connectionProperties.discoveredStunTurnServers = [NSMutableArray new]; self.connectionProperties.discoveredAdhocCommands = [NSMutableDictionary new]; self.connectionProperties.serverVersion = nil; - self.connectionProperties.conferenceServer = nil; + self.connectionProperties.conferenceServers = [NSMutableDictionary new]; self.connectionProperties.supportsHTTPUpload = NO; self.connectionProperties.uploadServer = nil; //self.connectionProperties.supportsClientState = NO; //already set by stream feature parsing From b2b17e7a11871050eafb77b24f70703321926a5b Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 22:32:44 +0200 Subject: [PATCH 18/23] Fix localization update script --- scripts/updateLocalization.sh | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/scripts/updateLocalization.sh b/scripts/updateLocalization.sh index 8460bc0c36..5b2cdf7b2e 100755 --- a/scripts/updateLocalization.sh +++ b/scripts/updateLocalization.sh @@ -10,9 +10,9 @@ if ! which bartycrouch > /dev/null; then exit 1 fi -SWIFT_EMIT_LOC_STRINGS=NO -if [ "$2" != "" ]; then - SWIFT_EMIT_LOC_STRINGS="$2" +compile_swift="NO" +if [ "x$2" != "x" ]; then + compile_swift="$2" fi function pullCurrentState { @@ -71,17 +71,19 @@ git submodule deinit --all -f git submodule update --init --recursive --remote pullCurrentState "$@" -echo "" -echo "*******************************************" -echo "* Building rust packages & bridge *" -echo "*******************************************" -bash ../rust/build-rust.sh +if [ "$compile_swift" == "YES" ]; then + echo "" + echo "*******************************************" + echo "* Building rust packages & bridge *" + echo "*******************************************" + bash ../rust/build-rust.sh -echo "" -echo "***************************************" -echo "* Installing macOS & iOS Pods *" -echo "***************************************" -pod install --repo-update + echo "" + echo "***************************************" + echo "* Installing macOS & iOS Pods *" + echo "***************************************" + pod install --repo-update +fi echo "" echo "***************************************" @@ -114,7 +116,7 @@ dummy="DON'T TRANSLATE: $(head /dev/urandom | LC_ALL=C tr -dc A-Za-z0-9 | head - x=$((1)) while [[ $x -lt 16 ]]; do echo "STARTING RUN $x..." - while ! xcrun xcodebuild -workspace "Monal.xcworkspace" -scheme "Monal" -sdk iphoneos -configuration "Beta" -allowProvisioningUpdates -exportLocalizations -localizationPath localization.tmp -exportLanguage base SWIFT_EMIT_LOC_STRINGS=$SWIFT_EMIT_LOC_STRINGS; do + while ! xcrun xcodebuild -workspace "Monal.xcworkspace" -scheme "Monal" -sdk iphoneos -configuration "Beta" -allowProvisioningUpdates -exportLocalizations -localizationPath localization.tmp -exportLanguage base SWIFT_EMIT_LOC_STRINGS="$compile_swift"; do echo "ERROR, TRYING AGAIN..." done echo "RUN $x SUCCEEDED, EXTRACTING STRINGS FROM XLIFF!" From 230b17e89a8f104d9f8b4be4857b49c370b663f2 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 23:00:16 +0200 Subject: [PATCH 19/23] Fix timeout handling when creating mucs --- Monal/Classes/MLMucProcessor.m | 13 +++++-------- Monal/Classes/MLXMPPManager.m | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Monal/Classes/MLMucProcessor.m b/Monal/Classes/MLMucProcessor.m index 75a846bb85..1d67680c2d 100644 --- a/Monal/Classes/MLMucProcessor.m +++ b/Monal/Classes/MLMucProcessor.m @@ -845,6 +845,7 @@ -(void) handleStatusCodes:(XMPPStanza*) node DDLogError(@"Got room create idle timeout but not creating group, ignoring: %@", room); return; } + DDLogWarn(@"Timeout while creating muc '%@'...", room); [self removeRoomFromCreating:room]; [self deleteMuc:room withBookmarksUpdate:NO keepBuddylistEntry:NO]; [self handleError:[NSString stringWithFormat:NSLocalizedString(@"Could not create group '%@': timeout", @""), room] forMuc:room withNode:nil andIsSevere:YES]; @@ -1484,14 +1485,10 @@ -(void) handleError:(NSString*) description forMuc:(NSString*) room withNode:(XM //remove handler (it will only be called once) [self removeUIHandlerForMuc:room]; - if(node == nil) - { - DDLogInfo(@"Could not extract UI error message. node == nil"); - return; - } - - //prepare data - NSString* message = [HelperTools extractXMPPError:node withDescription:description]; + //prepare data + NSString* message = description; + if(node != nil) + message = [HelperTools extractXMPPError:node withDescription:description]; NSDictionary* data = @{ @"success": @NO, @"muc": room, diff --git a/Monal/Classes/MLXMPPManager.m b/Monal/Classes/MLXMPPManager.m index d383c971ed..01247a8ead 100644 --- a/Monal/Classes/MLXMPPManager.m +++ b/Monal/Classes/MLXMPPManager.m @@ -333,9 +333,9 @@ -(id) init }); nw_path_monitor_start(_path_monitor); - //trigger iq invalidations from a background thread because timeouts aren't time critical - //we use this to decrement the timeout value of an iq handler every second until it reaches zero - dispatch_async(dispatch_queue_create_with_target("im.monal.iqtimeouts", DISPATCH_QUEUE_SERIAL, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)), ^{ + //trigger iq invalidations and idle timers from a background thread because timeouts aren't time critical + //we use this to decrement the timeout value of an iq handler / idle timer every second until it reaches zero + dispatch_async(dispatch_queue_create_with_target("im.monal.timeouts", DISPATCH_QUEUE_SERIAL, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)), ^{ while(YES) { for(xmpp* account in [MLXMPPManager sharedInstance].connectedXMPP) [account updateIqHandlerTimeouts]; From 26ddd11ccf136ed45324a8f9c6a602b20effe530 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 23:09:55 +0200 Subject: [PATCH 20/23] Don't assert when activating same audio session (pointer equality) --- Monal/Classes/MLCall.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Monal/Classes/MLCall.m b/Monal/Classes/MLCall.m index 03705f57ea..186a65c204 100644 --- a/Monal/Classes/MLCall.m +++ b/Monal/Classes/MLCall.m @@ -410,6 +410,11 @@ -(BOOL) isConnected -(void) setAudioSession:(AVAudioSession*) audioSession { @synchronized(self) { + if(audioSession == _audioSession) + { + DDLogWarn(@"Trying to activate same audio session a second time, ignoring..."); + return; + } if(audioSession != nil) MLAssert(_audioSession == nil, @"Audio session should never be activated without deactivating old audio session first!", (@{ @"oldAudioSession": nilWrapper(_audioSession), From d2b6d55bc3056be17b8e65f04e72edb14f19426b Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Thu, 2 May 2024 23:35:10 +0200 Subject: [PATCH 21/23] Make Picker() translatable, too For details, see previous commit making Toggle() translatable. --- Monal/Classes/CreateGroupMenu.swift | 2 +- Monal/Classes/NotificationSettings.swift | 2 +- Monal/Classes/PrivacySettings.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Monal/Classes/CreateGroupMenu.swift b/Monal/Classes/CreateGroupMenu.swift index 025f7e5a37..1c99b7474c 100644 --- a/Monal/Classes/CreateGroupMenu.swift +++ b/Monal/Classes/CreateGroupMenu.swift @@ -54,7 +54,7 @@ struct CreateGroupMenu: View { else { Section() { - Picker("Use account", selection: $selectedAccount) { + Picker(selection: $selectedAccount, label: Text("Use account")) { ForEach(Array(self.connectedAccounts.enumerated()), id: \.element) { idx, account in Text(account.connectionProperties.identity.jid).tag(account as xmpp?) } diff --git a/Monal/Classes/NotificationSettings.swift b/Monal/Classes/NotificationSettings.swift index 42e3135967..8e37883ebb 100644 --- a/Monal/Classes/NotificationSettings.swift +++ b/Monal/Classes/NotificationSettings.swift @@ -92,7 +92,7 @@ struct NotificationSettings: View { } } Section(header: Text("Pushserver Region").font(.title3)) { - Picker("Push Server", selection: $selectedPushServer) { + Picker(selection: $selectedPushServer, label: Text("Push Server")) { ForEach(self.availablePushServers.sorted(by: >), id: \.key) { pushServerFqdn, pushServerName in Text(pushServerName).tag(pushServerFqdn) } diff --git a/Monal/Classes/PrivacySettings.swift b/Monal/Classes/PrivacySettings.swift index e576447538..2070e716ee 100644 --- a/Monal/Classes/PrivacySettings.swift +++ b/Monal/Classes/PrivacySettings.swift @@ -147,7 +147,7 @@ struct PrivacyScreen: View { var body: some View { Form { - Picker("Notification privacy", selection: $privacyDefaultDB.notificationPrivacySetting) { + Picker(selection: $privacyDefaultDB.notificationPrivacySetting, label: Text("Notification privacy")) { ForEach(NotificationPrivacySettingOption.allCases, id: \.self) { option in Text(getNotificationPrivacyOption(option)).tag(option.rawValue) } From 02fb8b65152e7afbc3b4e16243cee00a338f7dc1 Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Fri, 3 May 2024 00:50:19 +0200 Subject: [PATCH 22/23] Bump marketing version to 6.3.1 --- Monal/Monal.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Monal/Monal.xcodeproj/project.pbxproj b/Monal/Monal.xcodeproj/project.pbxproj index e8969e929d..93f01047d2 100644 --- a/Monal/Monal.xcodeproj/project.pbxproj +++ b/Monal/Monal.xcodeproj/project.pbxproj @@ -2657,7 +2657,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 14.0; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 6.3.0; + MARKETING_VERSION = 6.3.1; PRESERVE_DEAD_CODE_INITS_AND_TERMS = NO; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; @@ -3024,7 +3024,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 14.0; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 6.3.0; + MARKETING_VERSION = 6.3.1; PRESERVE_DEAD_CODE_INITS_AND_TERMS = NO; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; @@ -3186,7 +3186,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 14.0; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 6.3.0; + MARKETING_VERSION = 6.3.1; ONLY_ACTIVE_ARCH = YES; PRESERVE_DEAD_CODE_INITS_AND_TERMS = NO; RUN_CLANG_STATIC_ANALYZER = YES; @@ -3462,7 +3462,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 14.0; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 6.3.0; + MARKETING_VERSION = 6.3.1; PRESERVE_DEAD_CODE_INITS_AND_TERMS = NO; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; @@ -3815,7 +3815,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 14.0; LLVM_LTO = YES; MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 6.3.0; + MARKETING_VERSION = 6.3.1; PRESERVE_DEAD_CODE_INITS_AND_TERMS = NO; SDKROOT = iphoneos; STRIP_INSTALLED_PRODUCT = NO; @@ -4229,7 +4229,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 14.0; LLVM_LTO = NO; MACOSX_DEPLOYMENT_TARGET = 11.0; - MARKETING_VERSION = 6.3.0; + MARKETING_VERSION = 6.3.1; PRESERVE_DEAD_CODE_INITS_AND_TERMS = NO; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; From c0222aad8f3460087a2e4c36abbb7b9658c1c14f Mon Sep 17 00:00:00 2001 From: Thilo Molitor Date: Fri, 3 May 2024 01:17:39 +0200 Subject: [PATCH 23/23] Update privacy settings submenu label --- Monal/Classes/PrivacySettings.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Monal/Classes/PrivacySettings.swift b/Monal/Classes/PrivacySettings.swift index 2070e716ee..b86f41c07a 100644 --- a/Monal/Classes/PrivacySettings.swift +++ b/Monal/Classes/PrivacySettings.swift @@ -102,7 +102,7 @@ struct PrivacySettings: View { .resizable() .aspectRatio(contentMode: .fit) .frame(width: 20, height: 20) - Text("Publishing") + Text("Publishing & Appearance") } } NavigationLink(destination: PreviewsScreen()) { @@ -189,7 +189,7 @@ struct PublishingScreen: View { } } } - .navigationBarTitle("Publishing & appearance", displayMode: .inline) + .navigationBarTitle("Publishing & Appearance", displayMode: .inline) } }