From 13cc05fb35f1f6a5890823f4ab7e77a829c0d240 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 6 Jun 2024 15:17:33 +0200 Subject: [PATCH 01/57] coding Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 22 +- iOSClient/More/CCManageAccount.h | 28 -- iOSClient/More/CCManageAccount.m | 434 ------------------ .../Manage Account/NCManageAccountModel.swift | 76 +++ .../Manage Account/NCManageAccountView.swift | 66 +++ iOSClient/More/NCMore.swift | 13 +- iOSClient/Nextcloud-Bridging-Header.h | 1 - 7 files changed, 163 insertions(+), 477 deletions(-) delete mode 100644 iOSClient/More/CCManageAccount.h delete mode 100644 iOSClient/More/CCManageAccount.m create mode 100644 iOSClient/More/Manage Account/NCManageAccountModel.swift create mode 100644 iOSClient/More/Manage Account/NCManageAccountView.swift diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 0335f2c98c..a413294eac 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -554,7 +554,6 @@ F768823C2C0DD231001CF441 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76882132C0DD1E7001CF441 /* NCKeychain.swift */; }; F768823E2C0DD305001CF441 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768823D2C0DD304001CF441 /* LazyView.swift */; }; F76882402C0DD30B001CF441 /* ViewOnAppear.swift in Sources */ = {isa = PBXBuildFile; fileRef = F768823F2C0DD30B001CF441 /* ViewOnAppear.swift */; }; - F76882432C0DD3B4001CF441 /* CCManageAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = F76882422C0DD3B4001CF441 /* CCManageAccount.m */; }; F769453C22E9CFFF000A798A /* NCShareUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F769453B22E9CFFF000A798A /* NCShareUserCell.xib */; }; F769454022E9F077000A798A /* NCSharePaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769453F22E9F077000A798A /* NCSharePaging.swift */; }; F769454622E9F1B0000A798A /* NCShareCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454522E9F1B0000A798A /* NCShareCommon.swift */; }; @@ -746,6 +745,8 @@ F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */; }; F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */; }; F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */; }; + F7AEEAA62C11DBAF00011412 /* NCManageAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AEEAA52C11DBAF00011412 /* NCManageAccountView.swift */; }; + F7AEEAA82C11DBFD00011412 /* NCManageAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AEEAA72C11DBFD00011412 /* NCManageAccountModel.swift */; }; F7B398422A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */; }; F7B398432A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */; }; F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B6B70327C4E7FA00A7F6EB /* NCScan+CollectionView.swift */; }; @@ -1380,8 +1381,6 @@ F76882212C0DD1E7001CF441 /* NCAcknowledgementsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAcknowledgementsView.swift; sourceTree = ""; }; F768823D2C0DD304001CF441 /* LazyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = ""; }; F768823F2C0DD30B001CF441 /* ViewOnAppear.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewOnAppear.swift; sourceTree = ""; }; - F76882412C0DD3B4001CF441 /* CCManageAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCManageAccount.h; sourceTree = ""; }; - F76882422C0DD3B4001CF441 /* CCManageAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCManageAccount.m; sourceTree = ""; }; F769453B22E9CFFF000A798A /* NCShareUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareUserCell.xib; sourceTree = ""; }; F769453F22E9F077000A798A /* NCSharePaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSharePaging.swift; sourceTree = ""; }; F769454522E9F1B0000A798A /* NCShareCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCommon.swift; sourceTree = ""; }; @@ -1538,6 +1537,8 @@ F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginWeb.swift; sourceTree = ""; }; F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCBrowserWeb.swift; sourceTree = ""; }; F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCBrowserWeb.storyboard; sourceTree = ""; }; + F7AEEAA52C11DBAF00011412 /* NCManageAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCManageAccountView.swift; sourceTree = ""; }; + F7AEEAA72C11DBFD00011412 /* NCManageAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCManageAccountModel.swift; sourceTree = ""; }; F7AF7632246BEDFE00B86E3C /* TOPasscodeViewController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TOPasscodeViewController.framework; path = Carthage/Build/iOS/TOPasscodeViewController.framework; sourceTree = ""; }; F7B1076C25D3CF2800E72DE2 /* BackgroundTasks.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BackgroundTasks.framework; path = System/Library/Frameworks/BackgroundTasks.framework; sourceTree = SDKROOT; }; F7B1A7761EBB3C8000BFB6D1 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; @@ -2625,6 +2626,15 @@ path = BrowserWeb; sourceTree = ""; }; + F7AEEAA92C11DC0600011412 /* Manage Account */ = { + isa = PBXGroup; + children = ( + F7AEEAA52C11DBAF00011412 /* NCManageAccountView.swift */, + F7AEEAA72C11DBFD00011412 /* NCManageAccountModel.swift */, + ); + path = "Manage Account"; + sourceTree = ""; + }; F7BAAD951ED5A63D00B7EAD4 /* Data */ = { isa = PBXGroup; children = ( @@ -2783,11 +2793,10 @@ F7CB68942541670D0050EC94 /* More */ = { isa = PBXGroup; children = ( + F7AEEAA92C11DC0600011412 /* Manage Account */, F3BB46502A39EC2D00461F6E /* Cells */, F7CB68992541676B0050EC94 /* NCMore.storyboard */, F73F537E1E929C8500F8678D /* NCMore.swift */, - F76882412C0DD3B4001CF441 /* CCManageAccount.h */, - F76882422C0DD3B4001CF441 /* CCManageAccount.m */, ); path = More; sourceTree = ""; @@ -4303,7 +4312,6 @@ F70BFC7420E0FA7D00C67599 /* NCUtility.swift in Sources */, F79EDAA526B004980007D134 /* NCPlayer.swift in Sources */, F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */, - F76882432C0DD3B4001CF441 /* CCManageAccount.m in Sources */, F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */, AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */, F718C24E254D507B00C5C256 /* NCViewerMediaDetailView.swift in Sources */, @@ -4325,6 +4333,7 @@ F769CA192966EA3C00039397 /* ComponentView.swift in Sources */, F7C9B91D2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, AF93474C27E34120002537EE /* NCUtility+Image.swift in Sources */, + F7AEEAA62C11DBAF00011412 /* NCManageAccountView.swift in Sources */, F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */, AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */, F7C30DFD291BD0B80017149B /* NCNetworkingE2EEDelete.swift in Sources */, @@ -4375,6 +4384,7 @@ D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */, F745B253222D88AE00346520 /* NCLoginQRCode.swift in Sources */, F769454822E9F20D000A798A /* NCShareNetworking.swift in Sources */, + F7AEEAA82C11DBFD00011412 /* NCManageAccountModel.swift in Sources */, F749B64A297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, F7C9555521F0C5470024296E /* NCActivity.swift in Sources */, F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */, diff --git a/iOSClient/More/CCManageAccount.h b/iOSClient/More/CCManageAccount.h deleted file mode 100644 index 48a072c44f..0000000000 --- a/iOSClient/More/CCManageAccount.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// CCManageAccount.h -// Nextcloud -// -// Created by Marino Faggiana on 12/03/15. -// Copyright (c) 2015 Marino Faggiana. All rights reserved. -// -// Author Marino Faggiana -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#import - -@interface CCManageAccount : XLFormViewController - -@end diff --git a/iOSClient/More/CCManageAccount.m b/iOSClient/More/CCManageAccount.m deleted file mode 100644 index ac89ff723d..0000000000 --- a/iOSClient/More/CCManageAccount.m +++ /dev/null @@ -1,434 +0,0 @@ -// -// CCManageAccount.m -// Nextcloud -// -// Created by Marino Faggiana on 12/03/15. -// Copyright (c) 2015 Marino Faggiana. All rights reserved. -// -// Author Marino Faggiana -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#import "CCManageAccount.h" -#import "NCBridgeSwift.h" - -#define actionSheetCancellaAccount 1 - -@interface CCManageAccount () -{ - AppDelegate *appDelegate; -} -@end - -@implementation CCManageAccount - -- (void)initializeForm -{ - XLFormDescriptor *form = [XLFormDescriptor formDescriptor]; - XLFormSectionDescriptor *section; - XLFormRowDescriptor *row; - - NSArray *accounts = [[NCManageDatabase shared] getAllAccount]; - tableAccount *activeAccount = [[NCManageDatabase shared] getActiveAccount]; - - // Section : ACCOUNTS ------------------------------------------- - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_accounts_", nil) sectionOptions:XLFormSectionOptionCanDelete]; - [form addFormSection:section]; - - for (tableAccount *account in accounts) { - - NSString *title = [NSString stringWithFormat:@"%@ %@", account.user, [NSURL URLWithString:account.urlBase].host]; - row = [XLFormRowDescriptor formRowDescriptorWithTag:account.account rowType:XLFormRowDescriptorTypeBooleanCheck title:title]; - - // Avatar - UIImage *avatar = [[[NCUtility alloc] init] loadUserImageFor:account.user displayName:account.displayName userBaseUrl:account]; - - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:13.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:avatar forKey:@"imageView.image"]; - if (account.active) { - row.value = @"YES"; - } - [section addFormRow:row]; - } - - // Section : ALIAS -------------------------------------------------- - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_alias_", nil)]; - section.footerTitle = NSLocalizedString(@"_alias_footer_", nil); - [form addFormSection:section]; - - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"alias" rowType:XLFormRowDescriptorTypeText]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[[UIImage imageNamed:@"form-textbox"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textField.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textField.textColor"]; - row.value = activeAccount.alias; - [section addFormRow:row]; - - // Section : MANAGE ACCOUNT ------------------------------------------- - - if ([NCBrandOptions shared].disable_manage_account == NO) { - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_manage_account_", nil)]; - [form addFormSection:section]; - - if ([NCBrandOptions shared].disable_multiaccount == NO) { - - // New Account nextcloud - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"addAccount" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_add_account_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[[UIImage systemImageNamed:@"plus"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - row.action.formSelector = @selector(addAccount:); - [section addFormRow:row]; - } - - // Set user status - - BOOL userStatus = [[NCGlobal shared] capabilityUserStatusEnabled]; - if (userStatus) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"setUserStatus" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_set_user_status_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"userStatusAway"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; - row.action.formSelector = @selector(setUserStatus:); - if (accounts.count == 0) row.disabled = @YES; - [section addFormRow:row]; - } - - if ([NCBrandOptions shared].disable_multiaccount == NO) { - - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"accountRequest" rowType:XLFormRowDescriptorTypeBooleanSwitch title:NSLocalizedString(@"_settings_account_request_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[[UIImage imageNamed:@"users"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - if ([[NCKeychain alloc] init].accountRequest) row.value = @1; - else row.value = @0; - [section addFormRow:row]; - } - } - - // Section : CERIFICATES ------------------------------------------- - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_certificates_", nil)]; - [form addFormSection:section]; - - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"certificateDetails" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_certificate_details_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"lock"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - row.action.formSelector = @selector(certificateDetails:); - [section addFormRow:row]; - - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"certificatePNDetails" rowType:XLFormRowDescriptorTypeButton title:NSLocalizedString(@"_certificate_pn_details_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"lock"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - [row.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - row.action.formSelector = @selector(certificatePNDetails:); - [section addFormRow:row]; - - // Section : USER INFORMATION ------------------------------------------- - - section = [XLFormSectionDescriptor formSectionWithTitle:NSLocalizedString(@"_personal_information_", nil)]; - [form addFormSection:section]; - - // Full Name - if ([activeAccount.displayName length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userfullname" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_full_name_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"user"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = activeAccount.displayName; - [section addFormRow:row]; - } - - // Address - if ([activeAccount.address length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"useraddress" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_address_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"address"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = activeAccount.address; - [section addFormRow:row]; - } - - // City + zip - if ([activeAccount.city length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"usercity" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_city_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"city"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = activeAccount.city; - if ([activeAccount.zip length] > 0) { - row.value = [NSString stringWithFormat:@"%@ %@", row.value, activeAccount.zip]; - } - [section addFormRow:row]; - } - - // Country - if ([activeAccount.country length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"usercountry" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_country_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"country"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = [[NSLocale systemLocale] displayNameForKey:NSLocaleCountryCode value:activeAccount.country]; - [section addFormRow:row]; - } - - // Phone - if ([activeAccount.phone length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userphone" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_phone_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"phone"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = activeAccount.phone; - [section addFormRow:row]; - } - - // Email - if ([activeAccount.email length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"useremail" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_email_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"email"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = activeAccount.email; - [section addFormRow:row]; - } - - // Web - if ([activeAccount.website length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"userweb" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_web_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"network"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = activeAccount.website; - [section addFormRow:row]; - } - - // Twitter - if ([activeAccount.twitter length] > 0) { - row = [XLFormRowDescriptor formRowDescriptorWithTag:@"usertwitter" rowType:XLFormRowDescriptorTypeInfo title:NSLocalizedString(@"_user_twitter_", nil)]; - row.cellConfigAtConfigure[@"backgroundColor"] = UIColor.secondarySystemGroupedBackgroundColor; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"textLabel.font"]; - [row.cellConfig setObject:[UIFont systemFontOfSize:15.0] forKey:@"detailTextLabel.font"]; - [row.cellConfig setObject:UIColor.labelColor forKey:@"textLabel.textColor"]; - [row.cellConfig setObject:[[UIImage imageNamed:@"twitter"] imageWithColor:[NCBrandColor shared].iconImageColor size:25] forKey:@"imageView.image"]; - row.value = activeAccount.twitter; - [section addFormRow:row]; - } - - self.tableView.showsVerticalScrollIndicator = NO; - self.form = form; - - // Open Login - if (accounts.count == 0) { - [appDelegate openLoginWithSelector:NCGlobal.shared.introLogin openLoginWeb:false windowForRootViewController: nil]; - } -} - -// MARK: - View Life Cycle - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - self.title = NSLocalizedString(@"_credentials_", nil); - appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; - self.view.backgroundColor = UIColor.systemGroupedBackgroundColor; - - self.tableView.backgroundColor = UIColor.systemGroupedBackgroundColor; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeUser) name:NCGlobal.shared.notificationCenterChangeUser object:nil]; - - [self initializeForm]; -} - -#pragma mark - NotificationCenter - -- (void)changeUser -{ - [self initializeForm]; -} - -#pragma mark - - --(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue -{ - [super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue]; - - if ([rowDescriptor.tag isEqualToString:@"accountRequest"]) { - - if ([[rowDescriptor.value valueData] boolValue] == YES) { - [[NCKeychain alloc] init].accountRequest = true; - } else { - [[NCKeychain alloc] init].accountRequest = false; - } - } - - else if ([rowDescriptor.tag isEqualToString:@"alias"]) { - - if ([newValue isEqual:[NSNull null]]) { - [[NCManageDatabase shared] setAccountAlias:@""]; - } else { - [[NCManageDatabase shared] setAccountAlias:newValue]; - } - } - - else { - - NSArray *accounts = [[NCManageDatabase shared] getAllAccount]; - tableAccount *activeAccount = [[NCManageDatabase shared] getActiveAccount]; - - for (tableAccount *account in accounts) { - if ([rowDescriptor.tag isEqualToString:account.account]) { - if (![account.account isEqualToString:activeAccount.account]) { - [appDelegate changeAccount:account.account userProfile:nil]; - } - } - } - - [self initializeForm]; - } -} - --(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath -{ - return NSLocalizedString(@"_remove_local_account_", nil); -} - --(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { - [super tableView:tableView commitEditingStyle:editingStyle forRowAtIndexPath:indexPath]; - - if (editingStyle == UITableViewCellEditingStyleDelete) { - - [self initializeForm]; - - NSArray *accounts = [[NCManageDatabase shared] getAllAccount]; - tableAccount *tableAccountForDelete = accounts[indexPath.row]; - tableAccount *tableActiveAccount = [[NCManageDatabase shared] getActiveAccount]; - - NSString *accountForDelete = tableAccountForDelete.account; - NSString *activeAccount = tableActiveAccount.account; - - NSString *title = [NSString stringWithFormat:NSLocalizedString(@"_want_delete_account_",nil), accountForDelete]; - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet]; - - [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_remove_local_account_", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { - - if (accountForDelete) { - [appDelegate deleteAccount:accountForDelete wipe:false]; - } - - NSArray *listAccount = [[NCManageDatabase shared] getAccounts]; - if ([listAccount count] > 0) { - if ([accountForDelete isEqualToString:activeAccount]) { - [appDelegate changeAccount:listAccount[0] userProfile:nil]; - } - } - - [self initializeForm]; - }]]; - - [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_cancel_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { }]]; - - alertController.popoverPresentationController.sourceView = self.view; - alertController.popoverPresentationController.sourceRect = [self.tableView rectForRowAtIndexPath:indexPath]; - - [self presentViewController:alertController animated:YES completion:nil]; - } -} - -- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - if (indexPath.section == 0) { - return 60; - } else { - return 50; - } -} - -#pragma mark - - -- (void)addAccount:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - [appDelegate openLoginWithSelector:NCGlobal.shared.introLogin openLoginWeb:false windowForRootViewController:nil]; -} - -#pragma mark - - -- (void)setUserStatus:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCUserStatus" bundle:nil] instantiateInitialViewController]; - [self presentViewController:navigationController animated:YES completion:nil]; -} - -#pragma mark - - -- (void)certificateDetails:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCViewCertificateDetails" bundle:nil] instantiateInitialViewController]; - NCViewCertificateDetails *viewController = (NCViewCertificateDetails *)navigationController.topViewController; - - NSURL *url = [NSURL URLWithString:appDelegate.urlBase]; - viewController.host = [url host]; - - [self presentViewController:navigationController animated:YES completion:nil]; -} - -- (void)certificatePNDetails:(XLFormRowDescriptor *)sender -{ - [self deselectFormRow:sender]; - - UINavigationController *navigationController = [[UIStoryboard storyboardWithName:@"NCViewCertificateDetails" bundle:nil] instantiateInitialViewController]; - NCViewCertificateDetails *viewController = (NCViewCertificateDetails *)navigationController.topViewController; - - NSURL *url = [NSURL URLWithString: NCBrandOptions.shared.pushNotificationServerProxy]; - viewController.host = [url host]; - viewController.certificateTitle = NSLocalizedString(@"_certificate_pn_view_", nil); - - [self presentViewController:navigationController animated:YES completion:nil]; -} - -@end diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift new file mode 100644 index 0000000000..4da2e4b9d6 --- /dev/null +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -0,0 +1,76 @@ +// +// NCManageAccountModel.swift +// Nextcloud +// +// Created by Marino Faggiana on 06/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +import Foundation +import UIKit + +/// A model that allows the user to configure the account +class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { + /// AppDelegate + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + /// Root View Controller + var controller: NCMainTabBarController? + /// All account + var accounts: [tableAccount] = [] + + @Published var indexActiveAccount: Int = 0 + + /// Initialization code to set up the ViewModel with the active account + init(controller: NCMainTabBarController?) { + self.controller = controller + onViewAppear() + } + + /// Triggered when the view appears. + func onViewAppear() { + accounts = NCManageDatabase.shared.getAllAccount() + getIndexActiveAccount() + } + + func getIndexActiveAccount() { + self.indexActiveAccount = 0 + for (index, item) in accounts.enumerated() { + if item.active { + self.indexActiveAccount = index + } + } + } + + func getUserName(account: tableAccount) -> String { + if account.alias.isEmpty { + return account.displayName + } else { + return account.displayName + " (\(account.alias)" + } + } + + func getUserStatus(account: tableAccount) -> (onlineStatus: UIImage?, statusMessage: String?) { + if NCGlobal.shared.capabilityUserStatusEnabled { + let status = NCUtility().getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage) + let image = status.onlineStatus + let text = status.statusMessage + return (image, text) + } + return (nil, nil) + } +} diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift new file mode 100644 index 0000000000..d8cf7eb461 --- /dev/null +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -0,0 +1,66 @@ +// +// NCManageAccountView.swift +// Nextcloud +// +// Created by Marino Faggiana on 06/06/24. +// Copyright © 2024 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +import SwiftUI + +struct NCManageAccountView: View { + @ObservedObject var model: NCManageAccountModel + + var body: some View { + Form { + TabView(selection: $model.indexActiveAccount) { + ForEach(0.. Date: Thu, 6 Jun 2024 15:32:39 +0200 Subject: [PATCH 02/57] cleaning Signed-off-by: Marino Faggiana --- Brand/NCBrand.swift | 2 +- iOSClient/AppDelegate.swift | 20 ++-- iOSClient/NCGlobal.swift | 182 ++++++++++++++++++------------------ 3 files changed, 102 insertions(+), 102 deletions(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index f7b0704c5f..2f67bc1174 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -90,7 +90,7 @@ let userAgent: String = { public let maxConcurrentOperationUpload: Int = 5 // Number of failed attempts after reset app - @objc public let resetAppPasscodeAttempts: Int = 10 + public let resetAppPasscodeAttempts: Int = 10 public let passcodeSecondsFail: Int = 60 // Info Paging diff --git a/iOSClient/AppDelegate.swift b/iOSClient/AppDelegate.swift index 555927ce45..324c632842 100644 --- a/iOSClient/AppDelegate.swift +++ b/iOSClient/AppDelegate.swift @@ -33,11 +33,11 @@ import EasyTipView @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, NCUserBaseUrl { - @objc var account: String = "" - @objc var urlBase: String = "" - @objc var user: String = "" - @objc var userId: String = "" - @objc var password: String = "" + var account: String = "" + var urlBase: String = "" + var user: String = "" + var userId: String = "" + var password: String = "" var tipView: EasyTipView? var backgroundSessionCompletionHandler: (() -> Void)? @@ -340,7 +340,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // MARK: - Login - @objc func openLogin(selector: Int, openLoginWeb: Bool, windowForRootViewController: UIWindow? = nil) { + func openLogin(selector: Int, openLoginWeb: Bool, windowForRootViewController: UIWindow? = nil) { func showLoginViewController(_ viewController: UIViewController?) { guard let viewController else { return } let navigationController = NCLoginNavigationController(rootViewController: viewController) @@ -408,7 +408,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // MARK: - Error Networking - @objc func startTimerErrorNetworking(scene: UIScene) { + func startTimerErrorNetworking(scene: UIScene) { timerErrorNetworkingDisabled = false timerErrorNetworking = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(checkErrorNetworking(_:)), userInfo: nil, repeats: true) } @@ -457,7 +457,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // MARK: - Account - @objc func changeAccount(_ account: String, userProfile: NKUserProfile?) { + func changeAccount(_ account: String, userProfile: NKUserProfile?) { NCNetworking.shared.cancelAllQueue() NCNetworking.shared.cancelDataTask() @@ -500,7 +500,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterChangeUser) } - @objc func deleteAccount(_ account: String, wipe: Bool) { + func deleteAccount(_ account: String, wipe: Bool) { UIApplication.shared.allSceneSessionDestructionExceptFirst() @@ -566,7 +566,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD // MARK: - Reset Application - @objc func resetApplication() { + func resetApplication() { let utilityFileSystem = NCUtilityFileSystem() diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 8cdfc582a7..df47055a1f 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -24,7 +24,7 @@ import UIKit class NCGlobal: NSObject { - @objc static let shared: NCGlobal = { + static let shared: NCGlobal = { let instance = NCGlobal() return instance }() @@ -90,12 +90,12 @@ class NCGlobal: NSObject { // Directory on Group // - @objc let directoryProviderStorage = "File Provider Storage" - @objc let appApplicationSupport = "Library/Application Support" - @objc let appCertificates = "Library/Application Support/Certificates" - @objc let appDatabaseNextcloud = "Library/Application Support/Nextcloud" - @objc let appScan = "Library/Application Support/Scan" - @objc let appUserData = "Library/Application Support/UserData" + let directoryProviderStorage = "File Provider Storage" + let appApplicationSupport = "Library/Application Support" + let appCertificates = "Library/Application Support/Certificates" + let appDatabaseNextcloud = "Library/Application Support/Nextcloud" + let appScan = "Library/Application Support/Scan" + let appUserData = "Library/Application Support/UserData" // Service // @@ -131,7 +131,7 @@ class NCGlobal: NSObject { // Intro selector // - @objc let introLogin: Int = 0 + let introLogin: Int = 0 let introSignup: Int = 1 // Avatar & Preview size @@ -216,82 +216,82 @@ class NCGlobal: NSObject { // ContentPresenter // - @objc let dismissAfterSecond: TimeInterval = 4 - @objc let dismissAfterSecondLong: TimeInterval = 10 + let dismissAfterSecond: TimeInterval = 4 + let dismissAfterSecondLong: TimeInterval = 10 // Error // - @objc let errorRequestExplicityCancelled: Int = 15 - @objc let errorNotModified: Int = 304 - @objc let errorBadRequest: Int = 400 - @objc let errorUnauthorized401: Int = 401 - @objc let errorForbidden: Int = 403 - @objc let errorResourceNotFound: Int = 404 - @objc let errorMethodNotSupported: Int = 405 - @objc let errorConflict: Int = 409 - @objc let errorPreconditionFailed: Int = 412 - @objc let errorUnsupportedMediaType: Int = 415 - @objc let errorInternalServerError: Int = 500 - @objc let errorQuota: Int = 507 - @objc let errorUnauthorized997: Int = 997 - @objc let errorExplicitlyCancelled: Int = -999 - @objc let errorConnectionLost: Int = -1005 - @objc let errorNetworkNotAvailable: Int = -1009 - @objc let errorBadServerResponse: Int = -1011 - @objc let errorInternalError: Int = -99999 - @objc let errorFileNotSaved: Int = -99998 - @objc let errorOffline: Int = -99997 - @objc let errorCharactersForbidden: Int = -99996 - @objc let errorCreationFile: Int = -99995 - @objc let errorReadFile: Int = -99994 - @objc let errorUnauthorizedFilesPasscode: Int = -99993 - @objc let errorDisableFilesApp: Int = -99992 - @objc let errorUnexpectedResponseFromDB: Int = -99991 + let errorRequestExplicityCancelled: Int = 15 + let errorNotModified: Int = 304 + let errorBadRequest: Int = 400 + let errorUnauthorized401: Int = 401 + let errorForbidden: Int = 403 + let errorResourceNotFound: Int = 404 + let errorMethodNotSupported: Int = 405 + let errorConflict: Int = 409 + let errorPreconditionFailed: Int = 412 + let errorUnsupportedMediaType: Int = 415 + let errorInternalServerError: Int = 500 + let errorQuota: Int = 507 + let errorUnauthorized997: Int = 997 + let errorExplicitlyCancelled: Int = -999 + let errorConnectionLost: Int = -1005 + let errorNetworkNotAvailable: Int = -1009 + let errorBadServerResponse: Int = -1011 + let errorInternalError: Int = -99999 + let errorFileNotSaved: Int = -99998 + let errorOffline: Int = -99997 + let errorCharactersForbidden: Int = -99996 + let errorCreationFile: Int = -99995 + let errorReadFile: Int = -99994 + let errorUnauthorizedFilesPasscode: Int = -99993 + let errorDisableFilesApp: Int = -99992 + let errorUnexpectedResponseFromDB: Int = -99991 // E2EE - @objc let errorE2EENotEnabled: Int = -98000 - @objc let errorE2EEVersion: Int = -98001 - @objc let errorE2EEKeyChecksums: Int = -98002 - @objc let errorE2EEKeyEncodeMetadata: Int = -98003 - @objc let errorE2EEKeyDecodeMetadata: Int = -98004 - @objc let errorE2EEKeyVerifySignature: Int = -98005 - @objc let errorE2EEKeyCiphertext: Int = -98006 - @objc let errorE2EEKeyFiledropCiphertext: Int = -98007 - @objc let errorE2EEJSon: Int = -98008 - @objc let errorE2EELock: Int = -98009 - @objc let errorE2EEEncryptFile: Int = -98010 - @objc let errorE2EEEncryptPayloadFile: Int = -98011 - @objc let errorE2EECounter: Int = -98012 - @objc let errorE2EEGenerateKey: Int = -98013 - @objc let errorE2EEEncodedKey: Int = -98014 - @objc let errorE2EENoUserFound: Int = -98015 - @objc let errorE2EEUploadInProgress: Int = -98016 + let errorE2EENotEnabled: Int = -98000 + let errorE2EEVersion: Int = -98001 + let errorE2EEKeyChecksums: Int = -98002 + let errorE2EEKeyEncodeMetadata: Int = -98003 + let errorE2EEKeyDecodeMetadata: Int = -98004 + let errorE2EEKeyVerifySignature: Int = -98005 + let errorE2EEKeyCiphertext: Int = -98006 + let errorE2EEKeyFiledropCiphertext: Int = -98007 + let errorE2EEJSon: Int = -98008 + let errorE2EELock: Int = -98009 + let errorE2EEEncryptFile: Int = -98010 + let errorE2EEEncryptPayloadFile: Int = -98011 + let errorE2EECounter: Int = -98012 + let errorE2EEGenerateKey: Int = -98013 + let errorE2EEEncodedKey: Int = -98014 + let errorE2EENoUserFound: Int = -98015 + let errorE2EEUploadInProgress: Int = -98016 // Filename Mask and Type // - let keyFileNameMask = "fileNameMask" - let keyFileNameType = "fileNameType" - let keyFileNameAutoUploadMask = "fileNameAutoUploadMask" - let keyFileNameAutoUploadType = "fileNameAutoUploadType" - let keyFileNameOriginal = "fileNameOriginal" - let keyFileNameOriginalAutoUpload = "fileNameOriginalAutoUpload" + let keyFileNameMask = "fileNameMask" + let keyFileNameType = "fileNameType" + let keyFileNameAutoUploadMask = "fileNameAutoUploadMask" + let keyFileNameAutoUploadType = "fileNameAutoUploadType" + let keyFileNameOriginal = "fileNameOriginal" + let keyFileNameOriginalAutoUpload = "fileNameOriginalAutoUpload" // Selector // - let selectorDownloadFile = "downloadFile" - let selectorReadFile = "readFile" - let selectorListingFavorite = "listingFavorite" - let selectorLoadFileView = "loadFileView" - let selectorLoadFileQuickLook = "loadFileQuickLook" - let selectorOpenIn = "openIn" - let selectorUploadAutoUpload = "uploadAutoUpload" - let selectorUploadAutoUploadAll = "uploadAutoUploadAll" - let selectorUploadFile = "uploadFile" - let selectorUploadFileNODelete = "UploadFileNODelete" - let selectorUploadFileShareExtension = "uploadFileShareExtension" - let selectorSaveAlbum = "saveAlbum" - let selectorSaveAsScan = "saveAsScan" - let selectorOpenDetail = "openDetail" - let selectorSynchronizationOffline = "synchronizationOffline" + let selectorDownloadFile = "downloadFile" + let selectorReadFile = "readFile" + let selectorListingFavorite = "listingFavorite" + let selectorLoadFileView = "loadFileView" + let selectorLoadFileQuickLook = "loadFileQuickLook" + let selectorOpenIn = "openIn" + let selectorUploadAutoUpload = "uploadAutoUpload" + let selectorUploadAutoUploadAll = "uploadAutoUploadAll" + let selectorUploadFile = "uploadFile" + let selectorUploadFileNODelete = "UploadFileNODelete" + let selectorUploadFileShareExtension = "uploadFileShareExtension" + let selectorSaveAlbum = "saveAlbum" + let selectorSaveAsScan = "saveAsScan" + let selectorOpenDetail = "openDetail" + let selectorSynchronizationOffline = "synchronizationOffline" // Metadata : Status // @@ -300,15 +300,15 @@ class NCGlobal: NSObject { // ± 2 downloading/uploading // ± 3 error // - let metadataStatusNormal: Int = 0 + let metadataStatusNormal: Int = 0 - let metadataStatusWaitDownload: Int = -1 - let metadataStatusDownloading: Int = -2 - let metadataStatusDownloadError: Int = -3 + let metadataStatusWaitDownload: Int = -1 + let metadataStatusDownloading: Int = -2 + let metadataStatusDownloadError: Int = -3 - let metadataStatusWaitUpload: Int = 1 - let metadataStatusUploading: Int = 2 - let metadataStatusUploadError: Int = 3 + let metadataStatusWaitUpload: Int = 1 + let metadataStatusUploading: Int = 2 + let metadataStatusUploadError: Int = 3 // Hidden files included in the read // @@ -316,13 +316,13 @@ class NCGlobal: NSObject { // Auto upload subfolder granularity // - let subfolderGranularityDaily = 2 - let subfolderGranularityMonthly = 1 - let subfolderGranularityYearly = 0 + let subfolderGranularityDaily = 2 + let subfolderGranularityMonthly = 1 + let subfolderGranularityYearly = 0 // Notification Center // - @objc let notificationCenterChangeUser = "changeUser" + let notificationCenterChangeUser = "changeUser" let notificationCenterChangeTheming = "changeTheming" let notificationCenterRichdocumentGrabFocus = "richdocumentGrabFocus" let notificationCenterReloadDataNCShare = "reloadDataNCShare" @@ -412,7 +412,7 @@ class NCGlobal: NSObject { // CAPABILITIES // var capabilityServerVersionMajor: Int = 0 - @objc var capabilityServerVersion: String = "" + var capabilityServerVersion: String = "" var capabilityFileSharingApiEnabled: Bool = false var capabilityFileSharingPubPasswdEnforced: Bool = false @@ -427,11 +427,11 @@ class NCGlobal: NSObject { var capabilityThemingColor: String = "" var capabilityThemingColorElement: String = "" var capabilityThemingColorText: String = "" - @objc var capabilityThemingName: String = "" - @objc var capabilityThemingSlogan: String = "" + var capabilityThemingName: String = "" + var capabilityThemingSlogan: String = "" - @objc var capabilityE2EEEnabled: Bool = false - @objc var capabilityE2EEApiVersion: String = "" + var capabilityE2EEEnabled: Bool = false + var capabilityE2EEApiVersion: String = "" var capabilityRichDocumentsEnabled: Bool = false var capabilityRichDocumentsMimetypes = ThreadSafeArray() @@ -443,7 +443,7 @@ class NCGlobal: NSObject { var capabilityFilesComments: Bool = false // NC 20 var capabilityFilesBigfilechunking: Bool = false - @objc var capabilityUserStatusEnabled: Bool = false + var capabilityUserStatusEnabled: Bool = false var capabilityExternalSites: Bool = false var capabilityGroupfoldersEnabled: Bool = false // NC27 var capabilityAssistantEnabled: Bool = false // NC28 From 9663729ab44fdca45506de246aa9fef907d02639 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 6 Jun 2024 15:42:51 +0200 Subject: [PATCH 03/57] cleaning Signed-off-by: Marino Faggiana --- Brand/NCBrand.swift | 126 +++++++++--------- .../NCAudioRecorderViewController.swift | 3 +- iOSClient/BrowserWeb/NCBrowserWeb.swift | 8 +- iOSClient/Data/NCManageDatabase.swift | 6 +- .../NCCreateFormUploadDocuments.swift | 2 +- 5 files changed, 70 insertions(+), 75 deletions(-) diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift index 2f67bc1174..30ff68e0fb 100755 --- a/Brand/NCBrand.swift +++ b/Brand/NCBrand.swift @@ -35,63 +35,63 @@ let userAgent: String = { return instance }() - @objc public var brand: String = "Nextcloud" - @objc public var textCopyrightNextcloudiOS: String = "Nextcloud Hydrogen for iOS %@ © 2024" - @objc public var textCopyrightNextcloudServer: String = "Nextcloud Server %@" - @objc public var loginBaseUrl: String = "https://cloud.nextcloud.com" - @objc public var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com" - @objc public var linkLoginHost: String = "https://nextcloud.com/install" - @objc public var linkloginPreferredProviders: String = "https://nextcloud.com/signup-ios" - @objc public var webLoginAutenticationProtocol: String = "nc://" // example "abc://" - @objc public var privacy: String = "https://nextcloud.com/privacy" - @objc public var sourceCode: String = "https://github.com/nextcloud/ios" - @objc public var mobileconfig: String = "/remote.php/dav/provisioning/apple-provisioning.mobileconfig" + var brand: String = "Nextcloud" + var textCopyrightNextcloudiOS: String = "Nextcloud Hydrogen for iOS %@ © 2024" + var textCopyrightNextcloudServer: String = "Nextcloud Server %@" + var loginBaseUrl: String = "https://cloud.nextcloud.com" + @objc var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com" + var linkLoginHost: String = "https://nextcloud.com/install" + var linkloginPreferredProviders: String = "https://nextcloud.com/signup-ios" + var webLoginAutenticationProtocol: String = "nc://" // example "abc://" + var privacy: String = "https://nextcloud.com/privacy" + var sourceCode: String = "https://github.com/nextcloud/ios" + var mobileconfig: String = "/remote.php/dav/provisioning/apple-provisioning.mobileconfig" // Personalized - @objc public var webCloseViewProtocolPersonalized: String = "" // example "abc://change/plan" Don't touch me !! - @objc public var folderBrandAutoUpload: String = "" // example "_auto_upload_folder_" Don't touch me !! + var webCloseViewProtocolPersonalized: String = "" // example "abc://change/plan" Don't touch me !! + var folderBrandAutoUpload: String = "" // example "_auto_upload_folder_" Don't touch me !! // Auto Upload default folder - @objc public var folderDefaultAutoUpload: String = "Photos" + var folderDefaultAutoUpload: String = "Photos" // Capabilities Group - @objc public var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud" - @objc public var capabilitiesGroupApps: String = "group.com.nextcloud.apps" + var capabilitiesGroups: String = "group.it.twsweb.Crypto-Cloud" + var capabilitiesGroupApps: String = "group.com.nextcloud.apps" // BRAND ONLY - @objc public var use_login_web_personalized: Bool = false // Don't touch me !! - @objc public var use_AppConfig: Bool = false // Don't touch me !! - @objc public var use_GroupApps: Bool = true // Don't touch me !! + var use_login_web_personalized: Bool = false // Don't touch me !! + var use_AppConfig: Bool = false // Don't touch me !! + var use_GroupApps: Bool = true // Don't touch me !! // Options - @objc public var use_default_auto_upload: Bool = false - @objc public var use_themingColor: Bool = true - @objc public var use_themingLogo: Bool = false - @objc public var use_storeLocalAutoUploadAll: Bool = false - @objc public var use_loginflowv2: Bool = false // Don't touch me !! - - @objc public var disable_intro: Bool = false - @objc public var disable_request_login_url: Bool = false - @objc public var disable_multiaccount: Bool = false - @objc public var disable_manage_account: Bool = false - @objc public var disable_more_external_site: Bool = false - @objc public var disable_openin_file: Bool = false // Don't touch me !! - @objc public var disable_crash_service: Bool = false - @objc public var disable_log: Bool = false - @objc public var disable_mobileconfig: Bool = false - @objc public var disable_show_more_nextcloud_apps_in_settings: Bool = false - @objc public var doNotAskPasscodeAtStartup: Bool = false + var use_default_auto_upload: Bool = false + var use_themingColor: Bool = true + var use_themingLogo: Bool = false + var use_storeLocalAutoUploadAll: Bool = false + var use_loginflowv2: Bool = false // Don't touch me !! + + var disable_intro: Bool = false + var disable_request_login_url: Bool = false + var disable_multiaccount: Bool = false + var disable_manage_account: Bool = false + var disable_more_external_site: Bool = false + var disable_openin_file: Bool = false // Don't touch me !! + var disable_crash_service: Bool = false + var disable_log: Bool = false + var disable_mobileconfig: Bool = false + var disable_show_more_nextcloud_apps_in_settings: Bool = false + var doNotAskPasscodeAtStartup: Bool = false // Internal option behaviour - @objc public var cleanUpDay: Int = 0 // Set default "Delete, in the cache, all files older than" possible days value are: 0, 1, 7, 30, 90, 180, 365 + var cleanUpDay: Int = 0 // Set default "Delete, in the cache, all files older than" possible days value are: 0, 1, 7, 30, 90, 180, 365 // Max download/upload concurrent - public let maxConcurrentOperationDownload: Int = 5 - public let maxConcurrentOperationUpload: Int = 5 + let maxConcurrentOperationDownload: Int = 5 + let maxConcurrentOperationUpload: Int = 5 // Number of failed attempts after reset app - public let resetAppPasscodeAttempts: Int = 10 - public let passcodeSecondsFail: Int = 60 + let resetAppPasscodeAttempts: Int = 10 + let passcodeSecondsFail: Int = 60 // Info Paging enum NCInfoPagingTab: Int, CaseIterable { @@ -140,53 +140,53 @@ let userAgent: String = { } class NCBrandColor: NSObject { - @objc static let shared: NCBrandColor = { + static let shared: NCBrandColor = { let instance = NCBrandColor() return instance }() // Color - @objc public let customer: UIColor = UIColor(red: 0.0 / 255.0, green: 130.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0) // BLU NC : #0082c9 - @objc public var customerText: UIColor = .white + let customer: UIColor = UIColor(red: 0.0 / 255.0, green: 130.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0) // BLU NC : #0082c9 + var customerText: UIColor = .white - @objc private var brand: UIColor // don't touch me - @objc public var brandElement: UIColor // don't touch me - @objc public var brandText: UIColor // don't touch me + var brand: UIColor // don't touch me + var brandElement: UIColor // don't touch me + var brandText: UIColor // don't touch me - @objc public let nextcloud: UIColor = UIColor(red: 0.0 / 255.0, green: 130.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0) - @objc public let yellowFavorite: UIColor = UIColor(red: 248.0 / 255.0, green: 205.0 / 255.0, blue: 70.0 / 255.0, alpha: 1.0) + let nextcloud: UIColor = UIColor(red: 0.0 / 255.0, green: 130.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0) + let yellowFavorite: UIColor = UIColor(red: 248.0 / 255.0, green: 205.0 / 255.0, blue: 70.0 / 255.0, alpha: 1.0) - public var userColors: [CGColor] = [] - public var themingColor: String = "" - public var themingColorElement: String = "" - public var themingColorText: String = "" + var userColors: [CGColor] = [] + var themingColor: String = "" + var themingColorElement: String = "" + var themingColorText: String = "" - @objc public let iconImageColor: UIColor = .label - @objc public let iconImageColor2: UIColor = .secondaryLabel - @objc public let iconImageMultiColors: [UIColor] = [.secondaryLabel, .label] + let iconImageColor: UIColor = .label + let iconImageColor2: UIColor = .secondaryLabel + let iconImageMultiColors: [UIColor] = [.secondaryLabel, .label] - @objc public let textColor: UIColor = .label - @objc public let textColor2: UIColor = .secondaryLabel + let textColor: UIColor = .label + let textColor2: UIColor = .secondaryLabel - @objc public var systemMint: UIColor { + var systemMint: UIColor { get { return UIColor(red: 0.0 / 255.0, green: 199.0 / 255.0, blue: 190.0 / 255.0, alpha: 1.0) } } - @objc public var documentIconColor: UIColor { + var documentIconColor: UIColor { get { return UIColor(hex: "#49abe9")! } } - @objc public var spreadsheetIconColor: UIColor { + var spreadsheetIconColor: UIColor { get { return UIColor(hex: "#9abd4e")! } } - @objc public var presentationIconColor: UIColor { + var presentationIconColor: UIColor { get { return UIColor(hex: "#f0965f")! } @@ -203,12 +203,10 @@ class NCBrandColor: NSObject { } func settingThemingColor(account: String) { - let darker: CGFloat = 30 // % let lighter: CGFloat = 30 // % if NCBrandOptions.shared.use_themingColor { - self.themingColor = NCGlobal.shared.capabilityThemingColor self.themingColorElement = NCGlobal.shared.capabilityThemingColorElement self.themingColorText = NCGlobal.shared.capabilityThemingColorText diff --git a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift index fb9803f8c0..6ae7328808 100644 --- a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift +++ b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift @@ -138,8 +138,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { } open class NCAudioRecorder: NSObject { - - @objc public enum State: Int { + public enum State: Int { case none, record, play } diff --git a/iOSClient/BrowserWeb/NCBrowserWeb.swift b/iOSClient/BrowserWeb/NCBrowserWeb.swift index bc351f602e..fc45fdee5b 100644 --- a/iOSClient/BrowserWeb/NCBrowserWeb.swift +++ b/iOSClient/BrowserWeb/NCBrowserWeb.swift @@ -30,10 +30,10 @@ import WebKit class NCBrowserWeb: UIViewController { - @objc var urlBase = "" - @objc var isHiddenButtonExit = false - @objc var titleBrowser: String? - @objc weak var delegate: NCBrowserWebDelegate? + var urlBase = "" + var isHiddenButtonExit = false + var titleBrowser: String? + weak var delegate: NCBrowserWebDelegate? @IBOutlet weak var buttonExit: UIButton! diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 1d7873053a..8871e3caac 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -186,8 +186,7 @@ class NCManageDatabase: NSObject { // MARK: - // MARK: Utility Database - @objc func clearTable(_ table: Object.Type, account: String? = nil) { - + func clearTable(_ table: Object.Type, account: String? = nil) { do { let realm = try Realm() try realm.write { @@ -206,8 +205,7 @@ class NCManageDatabase: NSObject { } } - @objc func clearDatabase(account: String?, removeAccount: Bool) { - + func clearDatabase(account: String?, removeAccount: Bool) { if removeAccount { self.clearTable(tableAccount.self, account: account) } diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift index 07a1c608fc..31cca24a9e 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadDocuments.swift @@ -27,7 +27,7 @@ import XLForm // MARK: - -@objc class NCCreateFormUploadDocuments: XLFormViewController, NCSelectDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, NCCreateFormUploadConflictDelegate { +class NCCreateFormUploadDocuments: XLFormViewController, NCSelectDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, NCCreateFormUploadConflictDelegate { @IBOutlet weak var indicator: UIActivityIndicatorView! @IBOutlet weak var collectionView: UICollectionView! From 1114a242a49d0ce0bd1644c95d1ba95781ac5b65 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 6 Jun 2024 15:56:27 +0200 Subject: [PATCH 04/57] fix Signed-off-by: Marino Faggiana --- .../AutoUpload/NCAutoUploadView.swift | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/iOSClient/Settings/AutoUpload/NCAutoUploadView.swift b/iOSClient/Settings/AutoUpload/NCAutoUploadView.swift index c34b4a6eca..5da2cdd669 100644 --- a/iOSClient/Settings/AutoUpload/NCAutoUploadView.swift +++ b/iOSClient/Settings/AutoUpload/NCAutoUploadView.swift @@ -113,17 +113,6 @@ struct NCAutoUploadView: View { } .font(.system(size: 16)) }) - /// Auto Upload Full - Section(content: { - Toggle(NSLocalizedString("_autoupload_fullphotos_", comment: ""), isOn: $model.autoUploadFull) - .tint(Color(NCBrandColor.shared.brandElement)) - .onChange(of: model.autoUploadFull) { newValue in - model.handleAutoUploadFullChange(newValue: newValue) - } - .font(.system(size: 16)) - }, footer: { - Text(NSLocalizedString("_autoupload_fullphotos_footer_", comment: "")) - }) /// Auto Upload create subfolder Section(content: { Toggle(NSLocalizedString("_autoupload_create_subfolder_", comment: ""), isOn: $model.autoUploadCreateSubfolder) @@ -152,12 +141,20 @@ struct NCAutoUploadView: View { Text(NSLocalizedString("_autoupload_filenamemask_", comment: "")) .font(.system(size: 16)) } + }, footer: { + Text(NSLocalizedString("_autoupload_filenamemask_footer_", comment: "")) + }) + /// Auto Upload Full + Section(content: { + Toggle(NSLocalizedString("_autoupload_fullphotos_", comment: ""), isOn: $model.autoUploadFull) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.autoUploadFull) { newValue in + model.handleAutoUploadFullChange(newValue: newValue) + } + .font(.system(size: 16)) }, footer: { Text( - NSLocalizedString("_autoupload_filenamemask_footer_", comment: "") - + - "\n \n" - ) + NSLocalizedString("_autoupload_fullphotos_footer_", comment: "") + "\n \n") }) } } From f4fe39218598258e2b876237e5026f5c884d874e Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 6 Jun 2024 16:25:31 +0200 Subject: [PATCH 05/57] coding Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase+Account.swift | 13 ++++--------- .../More/Manage Account/NCManageAccountModel.swift | 11 +++++++++-- .../More/Manage Account/NCManageAccountView.swift | 11 +++++++++++ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index f365de359a..0819f2b8ce 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -453,19 +453,14 @@ extension NCManageDatabase { } } - @objc func setAccountAlias(_ alias: String?) { - - let alias = alias?.trimmingCharacters(in: .whitespacesAndNewlines) + @objc func setAccountAlias(_ account: String, alias: String) { + let alias = alias.trimmingCharacters(in: .whitespacesAndNewlines) do { let realm = try Realm() try realm.write { - if let result = realm.objects(tableAccount.self).filter("active == true").first { - if let alias = alias { - result.alias = alias - } else { - result.alias = "" - } + if let result = realm.objects(tableAccount.self).filter("account == %@", account).first { + result.alias = alias } } } catch let error { diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 4da2e4b9d6..e7576518f1 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -32,8 +32,10 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { var controller: NCMainTabBarController? /// All account var accounts: [tableAccount] = [] - + /// @Published var indexActiveAccount: Int = 0 + /// + @Published var alias: String = "" /// Initialization code to set up the ViewModel with the active account init(controller: NCMainTabBarController?) { @@ -52,6 +54,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { for (index, item) in accounts.enumerated() { if item.active { self.indexActiveAccount = index + self.alias = item.alias } } } @@ -60,7 +63,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { if account.alias.isEmpty { return account.displayName } else { - return account.displayName + " (\(account.alias)" + return account.displayName + " (\(account.alias))" } } @@ -73,4 +76,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } return (nil, nil) } + + func submitChangedAlias(account: tableAccount) { + NCManageDatabase.shared.setAccountAlias(account.account, alias: alias) + } } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index d8cf7eb461..bcaf1fa691 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -34,6 +34,7 @@ struct NCManageAccountView: View { let account = model.accounts[index] let status = model.getUserStatus(account: account) let avatar = NCUtility().loadUserImage(for: account.user, displayName: account.displayName, userBaseUrl: account) + /// VStack { Image(uiImage: avatar) .resizable() @@ -48,6 +49,16 @@ struct NCManageAccountView: View { Text(message) .font(.system(size: 10)) } + Spacer() + TextField(NSLocalizedString("_alias_", comment: ""), text: $model.alias) + .onSubmit { + model.submitChangedAlias(account: account) + } + .onChange(of: model.alias, perform: { _ in + model.submitChangedAlias(account: account) + }) + .font(.system(size: 15)) + .multilineTextAlignment(.trailing) } } } From 91653e3211764cea3991d08e85731d80110da901 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 6 Jun 2024 17:26:10 +0200 Subject: [PATCH 06/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountModel.swift | 4 +++ .../Manage Account/NCManageAccountView.swift | 36 ++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index e7576518f1..f1ae27bfa0 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -80,4 +80,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { func submitChangedAlias(account: tableAccount) { NCManageDatabase.shared.setAccountAlias(account.account, alias: alias) } + + func getTableAccount(account: String) -> tableAccount? { + return NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) + } } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index bcaf1fa691..28a9093e82 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -39,33 +39,43 @@ struct NCManageAccountView: View { Image(uiImage: avatar) .resizable() .scaledToFit() - .frame(width: UIScreen.main.bounds.width) + .frame(width: UIScreen.main.bounds.width, height: 75) .clipped() - Spacer() Text(model.getUserName(account: account)) .font(.system(size: 16)) - Spacer() if let message = status.statusMessage { Text(message) .font(.system(size: 10)) } + HStack { + Spacer() + .frame(width: 5) + Text(NSLocalizedString("_alias_", comment: "")) + .font(.system(size: 17)) + .fontWeight(.medium) + Spacer() + TextField(NSLocalizedString("_alias_", comment: ""), text: $model.alias) + .onSubmit { + model.submitChangedAlias(account: account) + } + .font(.system(size: 17)) + .multilineTextAlignment(.trailing) + Spacer() + .frame(width: 5) + } Spacer() - TextField(NSLocalizedString("_alias_", comment: ""), text: $model.alias) - .onSubmit { - model.submitChangedAlias(account: account) - } - .onChange(of: model.alias, perform: { _ in - model.submitChangedAlias(account: account) - }) - .font(.system(size: 15)) - .multilineTextAlignment(.trailing) } } } } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - .frame(height: 100) + .frame(height: 400) .edgesIgnoringSafeArea(.all) + .onChange(of: model.indexActiveAccount) { index in + if let account = model.getTableAccount(account: model.accounts[index].account) { + model.alias = account.alias + } + } } .navigationBarTitle(NSLocalizedString("_credentials_", comment: "")) .defaultViewModifier(model) From 22b2b25180cede54495f43e1ba25494550b5b6a2 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 6 Jun 2024 17:46:33 +0200 Subject: [PATCH 07/57] coding Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountView.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 28a9093e82..c6712c38d5 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -44,9 +44,13 @@ struct NCManageAccountView: View { Text(model.getUserName(account: account)) .font(.system(size: 16)) if let message = status.statusMessage { + Spacer() + .frame(height: 10) Text(message) .font(.system(size: 10)) } + Spacer() + .frame(height: 30) HStack { Spacer() .frame(width: 5) @@ -63,6 +67,14 @@ struct NCManageAccountView: View { Spacer() .frame(width: 5) } + HStack { + Spacer() + .frame(width: 5) + Text(NSLocalizedString("_alias_footer_", comment: "")) + .font(.system(size: 10)) + .foregroundColor(Color(UIColor.lightGray)) + } + .background(Color.blue) Spacer() } } From 33a76b4fd9aca4b01b2186f5f2795e163b6f5117 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 10:33:42 +0200 Subject: [PATCH 08/57] coding Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase.swift | 13 +++++++++++++ .../More/Manage Account/NCManageAccountModel.swift | 3 +++ 2 files changed, 16 insertions(+) diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 8871e3caac..6fbff77b3f 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -285,4 +285,17 @@ class NCManageDatabase: NSObject { return nil } + + // MARK: - + // MARK: SWIFTUI PREVIEW + + func previewCreateDB() { + /// Account + let account = "marinofaggiana https://cloud.nextcloud.com" + let userProfile = NKUserProfile() + userProfile.displayName = "Marino Faggiana" + userProfile.phone = "000 000000000" + NCManageDatabase.shared.addAccount(account, urlBase: "https://cloud.nextcloud.com", user: "marinofaggiana", userId: "marinofaggiana", password: "password") + NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile) + } } diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index f1ae27bfa0..5efbcf4b45 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -40,6 +40,9 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { /// Initialization code to set up the ViewModel with the active account init(controller: NCMainTabBarController?) { self.controller = controller + if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { + NCManageDatabase.shared.previewCreateDB() + } onViewAppear() } From a7937731ee5d9d7f17c510502593be9d50e3ebf5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 11:05:35 +0200 Subject: [PATCH 09/57] coding Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase.swift | 9 +++++-- .../Manage Account/NCManageAccountView.swift | 22 +++++++----------- .../en.lproj/Localizable.strings | 3 ++- .../it.lproj/Localizable.strings | Bin 137180 -> 137280 bytes 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index 6fbff77b3f..b1286c9d07 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -292,10 +292,15 @@ class NCManageDatabase: NSObject { func previewCreateDB() { /// Account let account = "marinofaggiana https://cloud.nextcloud.com" + let account2 = "mariorossi https://cloud.nextcloud.com" + NCManageDatabase.shared.addAccount(account, urlBase: "https://cloud.nextcloud.com", user: "marinofaggiana", userId: "marinofaggiana", password: "password") + NCManageDatabase.shared.addAccount(account2, urlBase: "https://cloud.nextcloud.com", user: "mariorossi", userId: "mariorossi", password: "password") let userProfile = NKUserProfile() userProfile.displayName = "Marino Faggiana" - userProfile.phone = "000 000000000" - NCManageDatabase.shared.addAccount(account, urlBase: "https://cloud.nextcloud.com", user: "marinofaggiana", userId: "marinofaggiana", password: "password") NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile) + let userProfile2 = NKUserProfile() + userProfile2.displayName = "Mario Rossi" + NCManageDatabase.shared.setAccountUserProfile(account: account2, userProfile: userProfile2) + } } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index c6712c38d5..ded0a43aff 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -52,36 +52,32 @@ struct NCManageAccountView: View { Spacer() .frame(height: 30) HStack { - Spacer() - .frame(width: 5) Text(NSLocalizedString("_alias_", comment: "")) .font(.system(size: 17)) .fontWeight(.medium) Spacer() - TextField(NSLocalizedString("_alias_", comment: ""), text: $model.alias) + TextField(NSLocalizedString("_alias_placeholder_", comment: ""), text: $model.alias) .onSubmit { model.submitChangedAlias(account: account) } - .font(.system(size: 17)) + .font(.system(size: 16)) .multilineTextAlignment(.trailing) Spacer() .frame(width: 5) + } - HStack { - Spacer() - .frame(width: 5) - Text(NSLocalizedString("_alias_footer_", comment: "")) - .font(.system(size: 10)) - .foregroundColor(Color(UIColor.lightGray)) - } - .background(Color.blue) + Text(NSLocalizedString("_alias_footer_", comment: "")) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.system(size: 12)) + .foregroundColor(Color(UIColor.lightGray)) + Spacer() } } } } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - .frame(height: 400) + .frame(height: 300) .edgesIgnoringSafeArea(.all) .onChange(of: model.indexActiveAccount) { index in if let account = model.getTableAccount(account: model.accounts[index].account) { diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index ee09a0971e..197292d843 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -196,7 +196,8 @@ "_account_request_" = "Request account"; "_settings_account_request_" = "Request account at startup"; "_print_" = "Print"; -"_alias_" = "Alias"; +"_alias_" = "Alias :"; +"_alias_placeholder_" = "Write the alias"; "_alias_footer_" = "Give your account names a descriptive name such as Home, Office, School …"; "_chunk_size_mb_" = "Chunk size in MB"; "_chunk_footer_title_" = "Chunked file upload (0 is disabled)\nImportant: the chunked upload works only when the app is \"active\"."; diff --git a/iOSClient/Supporting Files/it.lproj/Localizable.strings b/iOSClient/Supporting Files/it.lproj/Localizable.strings index 1f334adb7a56e926ca89ee32387745845472e7c4..57c205706beda16aba6ef2ac480721db3bf4388a 100644 GIT binary patch delta 72 zcmcb!p5wp~ WG9Xp}%BwRZHpd2Sj}2n1KMDZFyc4Pb delta 18 acmX@Gf#c44jtyx+&8LF4p9*3uI|=|;*9js3 From 1eef14b298cb4516ab05c64f5b1fa0e8ecb67db7 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 11:48:40 +0200 Subject: [PATCH 10/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountView.swift | 119 ++++++++++++------ 1 file changed, 81 insertions(+), 38 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index ded0a43aff..55bd630539 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -25,60 +25,103 @@ import SwiftUI struct NCManageAccountView: View { @ObservedObject var model: NCManageAccountModel + @State private var showServerCertificate = false + @State private var showPushCertificate = false var body: some View { Form { TabView(selection: $model.indexActiveAccount) { ForEach(0.. Date: Fri, 7 Jun 2024 12:02:53 +0200 Subject: [PATCH 11/57] coding Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountView.swift | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 55bd630539..3e40a5acb3 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -52,6 +52,7 @@ struct NCManageAccountView: View { } Spacer() .frame(height: 30) + HStack { Text(NSLocalizedString("_alias_", comment: "")) .font(.system(size: 17)) @@ -63,17 +64,19 @@ struct NCManageAccountView: View { } .font(.system(size: 16)) .multilineTextAlignment(.trailing) - Spacer() - .frame(width: 5) - } + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + Text(NSLocalizedString("_alias_footer_", comment: "")) + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) .frame(maxWidth: .infinity, alignment: .leading) .font(.system(size: 12)) .foregroundColor(Color(UIColor.lightGray)) + Spacer() /// Divider() + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) /// Button(action: { showServerCertificate.toggle() @@ -89,13 +92,14 @@ struct NCManageAccountView: View { } .font(.system(size: 14)) }) + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) .frame(maxWidth: .infinity, alignment: .leading) .tint(Color(NCBrandColor.shared.textColor)) .sheet(isPresented: $showServerCertificate) { } /// Divider() - + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) /// Button(action: { showPushCertificate.toggle() @@ -112,6 +116,7 @@ struct NCManageAccountView: View { .multilineTextAlignment(.leading) .font(.system(size: 14)) }) + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) .frame(maxWidth: .infinity, alignment: .leading) .tint(Color(NCBrandColor.shared.textColor)) .sheet(isPresented: $showPushCertificate) { @@ -120,6 +125,7 @@ struct NCManageAccountView: View { } } } + .listRowInsets(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .frame(height: 300) .onChange(of: model.indexActiveAccount) { index in From dbb687366b59670cbfc580b939374487c4152171 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 12:21:59 +0200 Subject: [PATCH 12/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountView.swift | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 3e40a5acb3..2abc6eedd3 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -35,7 +35,7 @@ struct NCManageAccountView: View { let account = model.accounts[index] let status = model.getUserStatus(account: account) let avatar = NCUtility().loadUserImage(for: account.user, displayName: account.displayName, userBaseUrl: account) - /// + /// Avatar zone VStack { Image(uiImage: avatar) .resizable() @@ -50,9 +50,10 @@ struct NCManageAccountView: View { Text(message) .font(.system(size: 10)) } + /// Spacer() - .frame(height: 30) - + .frame(height: 50) + /// Change alias HStack { Text(NSLocalizedString("_alias_", comment: "")) .font(.system(size: 17)) @@ -68,16 +69,14 @@ struct NCManageAccountView: View { .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) Text(NSLocalizedString("_alias_footer_", comment: "")) - .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 15)) + .padding(EdgeInsets(top: 1, leading: 15, bottom: 0, trailing: 15)) .frame(maxWidth: .infinity, alignment: .leading) .font(.system(size: 12)) .foregroundColor(Color(UIColor.lightGray)) - - Spacer() /// Divider() - .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) - /// + .padding(EdgeInsets(top: 5, leading: 15, bottom: 5, trailing: 5)) + /// Certificates Button(action: { showServerCertificate.toggle() }, label: { @@ -89,6 +88,9 @@ struct NCManageAccountView: View { .frame(width: 25, height: 25) .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) Text(NSLocalizedString("_certificate_details_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 15)) } .font(.system(size: 14)) }) @@ -99,7 +101,7 @@ struct NCManageAccountView: View { } /// Divider() - .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) + .padding(EdgeInsets(top: 5, leading: 15, bottom: 5, trailing: 0)) /// Button(action: { showPushCertificate.toggle() @@ -112,8 +114,10 @@ struct NCManageAccountView: View { .frame(width: 25, height: 25) .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) Text(NSLocalizedString("_certificate_pn_details_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 15)) } - .multilineTextAlignment(.leading) .font(.system(size: 14)) }) .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) @@ -127,7 +131,7 @@ struct NCManageAccountView: View { } .listRowInsets(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - .frame(height: 300) + .frame(height: 500) .onChange(of: model.indexActiveAccount) { index in if let account = model.getTableAccount(account: model.accounts[index].account) { model.alias = account.alias From cdceda4723318114bf0797e3b0c7b3bb48d0aa58 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 12:23:16 +0200 Subject: [PATCH 13/57] fix Signed-off-by: Marino Faggiana --- iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift b/iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift index 3ee5bfa6e4..b588ac22be 100644 --- a/iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift +++ b/iOSClient/Settings/Settings/E2EE/NCManageE2EEView.swift @@ -74,7 +74,7 @@ struct NCManageE2EEView: View { .scaledToFit() .font(Font.system(.body).weight(.light)) .frame(width: 25, height: 15) - .foregroundColor(.red) + .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) } Spacer() } From 0355022925ec9f7b985a1623ecaddcd07eb1f3ca Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 12:43:55 +0200 Subject: [PATCH 14/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountView.swift | 68 ++++++++++++++++--- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 2abc6eedd3..4c72d966c3 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -25,6 +25,7 @@ import SwiftUI struct NCManageAccountView: View { @ObservedObject var model: NCManageAccountModel + @State private var showUserStatus = false @State private var showServerCertificate = false @State private var showPushCertificate = false @@ -72,11 +73,37 @@ struct NCManageAccountView: View { .padding(EdgeInsets(top: 1, leading: 15, bottom: 0, trailing: 15)) .frame(maxWidth: .infinity, alignment: .leading) .font(.system(size: 12)) - .foregroundColor(Color(UIColor.lightGray)) + .foregroundStyle(Color(UIColor.lightGray)) /// Divider() .padding(EdgeInsets(top: 5, leading: 15, bottom: 5, trailing: 5)) - /// Certificates + /// User Status + Button(action: { + showUserStatus.toggle() + }, label: { + HStack { + Image(systemName: "moon.fill") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_set_user_status_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .foregroundStyle(Color(NCBrandColor.shared.textColor)) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 15)) + } + .font(.system(size: 14)) + }) + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) + .frame(maxWidth: .infinity, alignment: .leading) + .sheet(isPresented: $showUserStatus) { + } + /// + Divider() + .padding(EdgeInsets(top: 5, leading: 15, bottom: 5, trailing: 5)) + /// Certificate server Button(action: { showServerCertificate.toggle() }, label: { @@ -86,23 +113,23 @@ struct NCManageAccountView: View { .scaledToFit() .font(Font.system(.body).weight(.light)) .frame(width: 25, height: 25) - .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) Text(NSLocalizedString("_certificate_details_", comment: "")) .lineLimit(1) .truncationMode(.middle) + .foregroundStyle(Color(NCBrandColor.shared.textColor)) .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 15)) } .font(.system(size: 14)) }) .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) .frame(maxWidth: .infinity, alignment: .leading) - .tint(Color(NCBrandColor.shared.textColor)) .sheet(isPresented: $showServerCertificate) { } /// Divider() .padding(EdgeInsets(top: 5, leading: 15, bottom: 5, trailing: 0)) - /// + /// Certificate push Button(action: { showPushCertificate.toggle() }, label: { @@ -112,26 +139,49 @@ struct NCManageAccountView: View { .scaledToFit() .font(Font.system(.body).weight(.light)) .frame(width: 25, height: 25) - .foregroundColor(Color(NCBrandColor.shared.iconImageColor)) + .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) Text(NSLocalizedString("_certificate_pn_details_", comment: "")) .lineLimit(1) .truncationMode(.middle) + .foregroundStyle(Color(NCBrandColor.shared.textColor)) .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 15)) } .font(.system(size: 14)) }) .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) .frame(maxWidth: .infinity, alignment: .leading) - .tint(Color(NCBrandColor.shared.textColor)) .sheet(isPresented: $showPushCertificate) { } - Spacer() + /// + Divider() + .padding(EdgeInsets(top: 5, leading: 15, bottom: 5, trailing: 0)) + /// Delete account + Button(action: { + + }, label: { + HStack { + Image(systemName: "trash") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 25, height: 25) + .foregroundStyle(.red) + Text(NSLocalizedString("_remove_local_account_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .foregroundStyle(.red) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 15)) + } + .font(.system(size: 14)) + }) + .padding(EdgeInsets(top: 0, leading: 15, bottom: 0, trailing: 0)) + .frame(maxWidth: .infinity, alignment: .leading) } } } .listRowInsets(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 0)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - .frame(height: 500) + .frame(height: 410) .onChange(of: model.indexActiveAccount) { index in if let account = model.getTableAccount(account: model.accounts[index].account) { model.alias = account.alias From 23bf9841a7f8e58a4d45677b92e4c4515155d67b Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 14:13:28 +0200 Subject: [PATCH 15/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountView.swift | 314 ++++++++++-------- 1 file changed, 169 insertions(+), 145 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 4c72d966c3..ddcc6111b9 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -31,162 +31,186 @@ struct NCManageAccountView: View { var body: some View { Form { - TabView(selection: $model.indexActiveAccount) { - ForEach(0.. Date: Fri, 7 Jun 2024 14:27:31 +0200 Subject: [PATCH 16/57] coding Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountModel.swift | 7 +++++++ .../More/Manage Account/NCManageAccountView.swift | 14 ++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 5efbcf4b45..1bc6915ed6 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -36,6 +36,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { @Published var indexActiveAccount: Int = 0 /// @Published var alias: String = "" + /// + @Published var accountRequest: Bool = false /// Initialization code to set up the ViewModel with the active account init(controller: NCMainTabBarController?) { @@ -87,4 +89,9 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { func getTableAccount(account: String) -> tableAccount? { return NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) } + + /// + func updateAccountRequest() { + NCKeychain().accountRequest = accountRequest + } } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index ddcc6111b9..c25f53e70c 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -78,7 +78,7 @@ struct NCManageAccountView: View { .foregroundStyle(Color(UIColor.lightGray)) /// Divider() - .padding(EdgeInsets(top: 5, leading: 20, bottom: 5, trailing: 0)) + .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) /// User Status Button(action: { showUserStatus.toggle() @@ -104,7 +104,7 @@ struct NCManageAccountView: View { } /// Divider() - .padding(EdgeInsets(top: 5, leading: 20, bottom: 5, trailing: 0)) + .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) /// Certificate server Button(action: { showServerCertificate.toggle() @@ -130,7 +130,7 @@ struct NCManageAccountView: View { } /// Divider() - .padding(EdgeInsets(top: 5, leading: 20, bottom: 5, trailing: 0)) + .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) /// Certificate push Button(action: { showPushCertificate.toggle() @@ -156,7 +156,7 @@ struct NCManageAccountView: View { } /// Divider() - .padding(EdgeInsets(top: 5, leading: 20, bottom: 5, trailing: 0)) + .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) /// Delete account Button(action: { @@ -210,6 +210,12 @@ struct NCManageAccountView: View { } .font(.system(size: 14)) }) + Toggle(NSLocalizedString("_settings_account_request_", comment: ""), isOn: $model.accountRequest) + .font(.system(size: 16)) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.accountRequest, perform: { _ in + model.updateAccountRequest() + }) }) } .navigationBarTitle(NSLocalizedString("_credentials_", comment: "")) From ea451b92282a50b31811fdd8c8e6268fc084bd5b Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 15:00:24 +0200 Subject: [PATCH 17/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountView.swift | 185 ++++++++---------- 1 file changed, 83 insertions(+), 102 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index c25f53e70c..07e4ea050d 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -77,118 +77,99 @@ struct NCManageAccountView: View { .lineLimit(2) .foregroundStyle(Color(UIColor.lightGray)) /// - Divider() - .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) - /// User Status - Button(action: { - showUserStatus.toggle() - }, label: { - HStack { - Image(systemName: "moon.fill") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) - Text(NSLocalizedString("_set_user_status_", comment: "")) - .lineLimit(1) - .truncationMode(.middle) - .foregroundStyle(Color(NCBrandColor.shared.textColor)) - .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) - } - .font(.system(size: 14)) - }) - .padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0)) - .frame(maxWidth: .infinity, alignment: .leading) - .sheet(isPresented: $showUserStatus) { - } - /// - Divider() - .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) - /// Certificate server - Button(action: { - showServerCertificate.toggle() - }, label: { - HStack { - Image(systemName: "lock") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) - Text(NSLocalizedString("_certificate_details_", comment: "")) - .lineLimit(1) - .truncationMode(.middle) - .foregroundStyle(Color(NCBrandColor.shared.textColor)) - .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) - } - .font(.system(size: 14)) - }) - .padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0)) - .frame(maxWidth: .infinity, alignment: .leading) - .sheet(isPresented: $showServerCertificate) { - } - /// - Divider() - .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) - /// Certificate push - Button(action: { - showPushCertificate.toggle() - }, label: { - HStack { - Image(systemName: "lock") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) - Text(NSLocalizedString("_certificate_pn_details_", comment: "")) - .lineLimit(1) - .truncationMode(.middle) - .foregroundStyle(Color(NCBrandColor.shared.textColor)) - .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) - } - .font(.system(size: 14)) - }) - .padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0)) - .frame(maxWidth: .infinity, alignment: .leading) - .sheet(isPresented: $showPushCertificate) { - } - /// - Divider() - .padding(EdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 0)) - /// Delete account - Button(action: { - - }, label: { - HStack { - Image(systemName: "trash") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - .foregroundStyle(.red) - Text(NSLocalizedString("_remove_local_account_", comment: "")) - .lineLimit(1) - .truncationMode(.middle) - .foregroundStyle(.red) - .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) - } - .font(.system(size: 14)) - }) - .padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0)) - .frame(maxWidth: .infinity, alignment: .leading) } } } .listRowInsets(EdgeInsets(top: 20, leading: 0, bottom: 20, trailing: 0)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - .frame(height: 390) + .frame(height: 300) .onChange(of: model.indexActiveAccount) { index in if let account = model.getTableAccount(account: model.accounts[index].account) { model.alias = account.alias } } + /// User Status + Button(action: { + showUserStatus.toggle() + }, label: { + HStack { + Image(systemName: "moon.fill") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_set_user_status_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .foregroundStyle(Color(NCBrandColor.shared.textColor)) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) + } + .font(.system(size: 14)) + }) + .sheet(isPresented: $showUserStatus) { + } + /// Certificate server + Button(action: { + showServerCertificate.toggle() + }, label: { + HStack { + Image(systemName: "lock") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_certificate_details_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .foregroundStyle(Color(NCBrandColor.shared.textColor)) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) + } + .font(.system(size: 14)) + }) + .sheet(isPresented: $showServerCertificate) { + } + /// Certificate push + Button(action: { + showPushCertificate.toggle() + }, label: { + HStack { + Image(systemName: "lock") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) + Text(NSLocalizedString("_certificate_pn_details_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .foregroundStyle(Color(NCBrandColor.shared.textColor)) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) + } + .font(.system(size: 14)) + }) + .sheet(isPresented: $showPushCertificate) { + } + /// Delete account + Button(action: { + + }, label: { + HStack { + Image(systemName: "trash") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + .foregroundStyle(.red) + Text(NSLocalizedString("_remove_local_account_", comment: "")) + .lineLimit(1) + .truncationMode(.middle) + .foregroundStyle(.red) + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) + } + .font(.system(size: 14)) + }) }) /// All users Section(content: { From 321724ad9cd4300f90d7dcca1034d8a7478add04 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 15:25:02 +0200 Subject: [PATCH 18/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountModel.swift | 18 +++-- .../Manage Account/NCManageAccountView.swift | 68 ++++++++++--------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 1bc6915ed6..7bddf7f764 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -33,6 +33,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { /// All account var accounts: [tableAccount] = [] /// + @Published var account: tableAccount? + /// @Published var indexActiveAccount: Int = 0 /// @Published var alias: String = "" @@ -56,15 +58,17 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { func getIndexActiveAccount() { self.indexActiveAccount = 0 - for (index, item) in accounts.enumerated() { - if item.active { + for (index, account) in accounts.enumerated() { + if account.active { + self.account = account self.indexActiveAccount = index - self.alias = item.alias + self.alias = account.alias } } } - func getUserName(account: tableAccount) -> String { + func getUserName() -> String { + guard let account else { return "" } if account.alias.isEmpty { return account.displayName } else { @@ -72,7 +76,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } } - func getUserStatus(account: tableAccount) -> (onlineStatus: UIImage?, statusMessage: String?) { + func getUserStatus() -> (onlineStatus: UIImage?, statusMessage: String?) { + guard let account else { return (nil, nil) } if NCGlobal.shared.capabilityUserStatusEnabled { let status = NCUtility().getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage) let image = status.onlineStatus @@ -82,7 +87,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { return (nil, nil) } - func submitChangedAlias(account: tableAccount) { + func submitChangedAlias() { + guard let account else { return } NCManageDatabase.shared.setAccountAlias(account.account, alias: alias) } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 07e4ea050d..f7055ff78f 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -34,9 +34,8 @@ struct NCManageAccountView: View { Section(content: { TabView(selection: $model.indexActiveAccount) { ForEach(0.. Date: Fri, 7 Jun 2024 15:36:43 +0200 Subject: [PATCH 19/57] coding Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountModel.swift | 11 +++++++---- .../More/Manage Account/NCManageAccountView.swift | 5 +---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 7bddf7f764..8c2a3b1214 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -69,10 +69,10 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { func getUserName() -> String { guard let account else { return "" } - if account.alias.isEmpty { + if self.alias.isEmpty { return account.displayName } else { - return account.displayName + " (\(account.alias))" + return account.displayName + " (\(self.alias))" } } @@ -92,8 +92,11 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { NCManageDatabase.shared.setAccountAlias(account.account, alias: alias) } - func getTableAccount(account: String) -> tableAccount? { - return NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) + func setAccount(account: String) { + if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) { + self.account = tableAccount + self.alias = tableAccount.alias + } } /// diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index f7055ff78f..71c6696d96 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -57,10 +57,7 @@ struct NCManageAccountView: View { .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .frame(height: 150) .onChange(of: model.indexActiveAccount) { index in - if let account = model.getTableAccount(account: model.accounts[index].account) { - model.account = account - model.alias = account.alias - } + model.setAccount(account: model.accounts[index].account) } /// /// Change alias From 2cf8803976dc3fda624f5ee2d8ba829ed0688819 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 7 Jun 2024 15:46:42 +0200 Subject: [PATCH 20/57] coding Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountModel.swift | 12 ++++-------- .../More/Manage Account/NCManageAccountView.swift | 3 --- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 8c2a3b1214..1ef503cc55 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -32,7 +32,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { var controller: NCMainTabBarController? /// All account var accounts: [tableAccount] = [] - /// + /// Account @Published var account: tableAccount? /// @Published var indexActiveAccount: Int = 0 @@ -69,10 +69,11 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { func getUserName() -> String { guard let account else { return "" } - if self.alias.isEmpty { + NCManageDatabase.shared.setAccountAlias(account.account, alias: alias) + if alias.isEmpty { return account.displayName } else { - return account.displayName + " (\(self.alias))" + return account.displayName + " (\(alias))" } } @@ -87,11 +88,6 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { return (nil, nil) } - func submitChangedAlias() { - guard let account else { return } - NCManageDatabase.shared.setAccountAlias(account.account, alias: alias) - } - func setAccount(account: String) { if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) { self.account = tableAccount diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 71c6696d96..121d8f8a74 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -68,9 +68,6 @@ struct NCManageAccountView: View { .fontWeight(.medium) Spacer() TextField(NSLocalizedString("_alias_placeholder_", comment: ""), text: $model.alias) - .onSubmit { - model.submitChangedAlias() - } .font(.system(size: 16)) .multilineTextAlignment(.trailing) } From 704c0e6ffe18a61c23b3062d7a48818494c300d9 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 10:42:35 +0200 Subject: [PATCH 21/57] coding Signed-off-by: Marino Faggiana --- iOSClient/Login/NCViewCertificateDetails.swift | 13 +++++++------ .../More/Manage Account/NCManageAccountView.swift | 6 ++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/iOSClient/Login/NCViewCertificateDetails.swift b/iOSClient/Login/NCViewCertificateDetails.swift index d08a7a2a0e..25b673a92b 100644 --- a/iOSClient/Login/NCViewCertificateDetails.swift +++ b/iOSClient/Login/NCViewCertificateDetails.swift @@ -41,9 +41,10 @@ class NCViewCertificateDetails: UIViewController { var delegate: NCViewCertificateDetailsDelegate? let utilityFileSystem = NCUtilityFileSystem() - @objc public var host: String = "" + + public var host: String = "" public var fileNamePath: String = "" - @objc public var certificateTitle = NSLocalizedString("_certificate_view_", comment: "") + public var certificateTitle = NSLocalizedString("_certificate_view_", comment: "") // MARK: - View Life Cycle @@ -105,11 +106,11 @@ class NCViewCertificateDetails: UIViewController { // MARK: - UIViewControllerRepresentable -struct NCViewCertificateDetailsRepresentable: UIViewControllerRepresentable { +struct certificateDetailsView: UIViewControllerRepresentable { typealias UIViewControllerType = UINavigationController - var fileNamePath: String - var title: String + var host: String = "" + var title: String = "" func makeUIViewController(context: Context) -> UINavigationController { @@ -117,7 +118,7 @@ struct NCViewCertificateDetailsRepresentable: UIViewControllerRepresentable { let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController let viewController = navigationController?.topViewController as? NCViewCertificateDetails - viewController?.fileNamePath = fileNamePath + viewController?.host = host viewController?.certificateTitle = title return navigationController! diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 121d8f8a74..aee6ae3043 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -121,6 +121,9 @@ struct NCManageAccountView: View { .font(.system(size: 14)) }) .sheet(isPresented: $showServerCertificate) { + if let url = URL(string: model.account?.urlBase), let host = url.host { + certificateDetailsView(host: host, title: NSLocalizedString("_certificate_view_", comment: "")) + } } /// /// Certificate push @@ -143,6 +146,9 @@ struct NCManageAccountView: View { .font(.system(size: 14)) }) .sheet(isPresented: $showPushCertificate) { + if let url = URL(string: NCBrandOptions.shared.pushNotificationServerProxy), let host = url.host { + certificateDetailsView(host: host, title: NSLocalizedString("_certificate_pn_view_", comment: "")) + } } /// /// Delete account From 3f26d6060f7ef33de2ab2c281071d86690cd6da8 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 10:49:11 +0200 Subject: [PATCH 22/57] coding Signed-off-by: Marino Faggiana --- iOSClient/More/Manage Account/NCManageAccountModel.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 1ef503cc55..f6944f9b83 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -89,9 +89,11 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } func setAccount(account: String) { - if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) { + if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.account?.account != tableAccount.account { self.account = tableAccount self.alias = tableAccount.alias + /// Change active account + appDelegate.changeAccount(tableAccount.account, userProfile: nil) } } From 297e33459b714ca5379a5dbe8d3b8863bfe417bd Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 11:03:12 +0200 Subject: [PATCH 23/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountView.swift | 1 + iOSClient/Select/NCSelect.swift | 5 ---- iOSClient/UserStatus/NCUserStatus.swift | 25 ++++++++++++++++++- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index aee6ae3043..d51f2a8011 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -99,6 +99,7 @@ struct NCManageAccountView: View { .font(.system(size: 14)) }) .sheet(isPresented: $showUserStatus) { + UserStatusView() } /// /// Certificate server diff --git a/iOSClient/Select/NCSelect.swift b/iOSClient/Select/NCSelect.swift index 2eab5ad472..f5dd414d22 100644 --- a/iOSClient/Select/NCSelect.swift +++ b/iOSClient/Select/NCSelect.swift @@ -647,13 +647,9 @@ struct NCSelectViewControllerRepresentable: UIViewControllerRepresentable { } struct SelectView: UIViewControllerRepresentable { - - typealias UIViewControllerType = UINavigationController - @Binding var serverUrl: String class Coordinator: NSObject, NCSelectDelegate { - var parent: SelectView init(_ parent: SelectView) { @@ -668,7 +664,6 @@ struct SelectView: UIViewControllerRepresentable { } func makeUIViewController(context: Context) -> UINavigationController { - let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController let viewController = navigationController?.topViewController as? NCSelect diff --git a/iOSClient/UserStatus/NCUserStatus.swift b/iOSClient/UserStatus/NCUserStatus.swift index c2005ee9ac..22ca634c19 100644 --- a/iOSClient/UserStatus/NCUserStatus.swift +++ b/iOSClient/UserStatus/NCUserStatus.swift @@ -22,8 +22,9 @@ // along with this program. If not, see . // -import UIKit import Foundation +import UIKit +import SwiftUI import NextcloudKit import DropDown @@ -605,3 +606,25 @@ extension NCUserStatus: UITableViewDataSource { return cell } } + +struct UserStatusView: UIViewControllerRepresentable { + class Coordinator: NSObject { + var parent: UserStatusView + + init(_ parent: UserStatusView) { + self.parent = parent + } + } + + func makeUIViewController(context: Context) -> UINavigationController { + let storyboard = UIStoryboard(name: "NCUserStatus", bundle: nil) + let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController + return navigationController! + } + + func updateUIViewController(_ uiViewController: UINavigationController, context: Context) { } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } +} From c73b55c2cdb14baef23a9aff2da346434f5ba70d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 11:58:21 +0200 Subject: [PATCH 24/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountModel.swift | 23 ++++++++++--------- .../Manage Account/NCManageAccountView.swift | 7 +++--- iOSClient/UserStatus/NCUserStatus.swift | 20 +++++++++++++--- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index f6944f9b83..497062f966 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -33,7 +33,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { /// All account var accounts: [tableAccount] = [] /// Account - @Published var account: tableAccount? + @Published var tableAccount: tableAccount? /// @Published var indexActiveAccount: Int = 0 /// @@ -60,7 +60,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { self.indexActiveAccount = 0 for (index, account) in accounts.enumerated() { if account.active { - self.account = account + self.tableAccount = account self.indexActiveAccount = index self.alias = account.alias } @@ -68,19 +68,20 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } func getUserName() -> String { - guard let account else { return "" } - NCManageDatabase.shared.setAccountAlias(account.account, alias: alias) + guard let tableAccount else { return "" } + NCManageDatabase.shared.setAccountAlias(tableAccount.account, alias: alias) if alias.isEmpty { - return account.displayName + return tableAccount.displayName } else { - return account.displayName + " (\(alias))" + return tableAccount.displayName + " (\(alias))" } } func getUserStatus() -> (onlineStatus: UIImage?, statusMessage: String?) { - guard let account else { return (nil, nil) } - if NCGlobal.shared.capabilityUserStatusEnabled { - let status = NCUtility().getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage) + guard let tableAccount else { return (nil, nil) } + if NCGlobal.shared.capabilityUserStatusEnabled, + let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", tableAccount.account)) { + let status = NCUtility().getUserStatus(userIcon: tableAccount.userStatusIcon, userStatus: tableAccount.userStatusStatus, userMessage: tableAccount.userStatusMessage) let image = status.onlineStatus let text = status.statusMessage return (image, text) @@ -89,8 +90,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } func setAccount(account: String) { - if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.account?.account != tableAccount.account { - self.account = tableAccount + if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { + self.tableAccount = tableAccount self.alias = tableAccount.alias /// Change active account appDelegate.changeAccount(tableAccount.account, userProfile: nil) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index d51f2a8011..759803d4ae 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -81,7 +81,7 @@ struct NCManageAccountView: View { /// /// User Status Button(action: { - showUserStatus.toggle() + showUserStatus = true }, label: { HStack { Image(systemName: "moon.fill") @@ -99,8 +99,9 @@ struct NCManageAccountView: View { .font(.system(size: 14)) }) .sheet(isPresented: $showUserStatus) { - UserStatusView() + UserStatusView(showUserStatus: $showUserStatus) } + .onChange(of: showUserStatus) { _ in } /// /// Certificate server Button(action: { @@ -122,7 +123,7 @@ struct NCManageAccountView: View { .font(.system(size: 14)) }) .sheet(isPresented: $showServerCertificate) { - if let url = URL(string: model.account?.urlBase), let host = url.host { + if let url = URL(string: model.tableAccount?.urlBase), let host = url.host { certificateDetailsView(host: host, title: NSLocalizedString("_certificate_view_", comment: "")) } } diff --git a/iOSClient/UserStatus/NCUserStatus.swift b/iOSClient/UserStatus/NCUserStatus.swift index 22ca634c19..7dda363839 100644 --- a/iOSClient/UserStatus/NCUserStatus.swift +++ b/iOSClient/UserStatus/NCUserStatus.swift @@ -28,6 +28,10 @@ import SwiftUI import NextcloudKit import DropDown +protocol NCUserStatusDelegate: AnyObject { + func userStatusDismiss(_ viewController: NCUserStatus) +} + class NCUserStatus: UIViewController { @IBOutlet weak var buttonCancel: UIBarButtonItem! @@ -63,6 +67,8 @@ class NCUserStatus: UIViewController { @IBOutlet weak var clearStatusMessageButton: UIButton! @IBOutlet weak var setStatusMessageButton: UIButton! + weak var delegate: NCUserStatusDelegate? + private var statusPredefinedStatuses: [NKUserStatus] = [] private let utility = NCUtility() private var clearAtTimestamp: Double = 0 // Unix Timestamp representing the time to clear the status @@ -173,10 +179,9 @@ class NCUserStatus: UIViewController { super.viewWillDisappear(animated) NextcloudKit.shared.getUserStatus { account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, _, _, error in - if error == .success { - NCManageDatabase.shared.setAccountUserStatus(userStatusClearAt: clearAt, userStatusIcon: icon, userStatusMessage: message, userStatusMessageId: messageId, userStatusMessageIsPredefined: messageIsPredefined, userStatusStatus: status, userStatusStatusIsUserDefined: statusIsUserDefined, account: account) + self.delegate?.userStatusDismiss(self) } } } @@ -608,17 +613,26 @@ extension NCUserStatus: UITableViewDataSource { } struct UserStatusView: UIViewControllerRepresentable { - class Coordinator: NSObject { + @Binding var showUserStatus: Bool + + class Coordinator: NSObject, NCUserStatusDelegate { var parent: UserStatusView init(_ parent: UserStatusView) { self.parent = parent } + + func userStatusDismiss(_ viewController: NCUserStatus) { + parent.showUserStatus = false + } } func makeUIViewController(context: Context) -> UINavigationController { let storyboard = UIStoryboard(name: "NCUserStatus", bundle: nil) let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController + let viewController = navigationController?.topViewController as? NCUserStatus + + viewController?.delegate = context.coordinator return navigationController! } From a3886097ea308d5e9d8da56b428ca6e05d46b1a2 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 12:26:57 +0200 Subject: [PATCH 25/57] coding Signed-off-by: Marino Faggiana --- iOSClient/More/Manage Account/NCManageAccountModel.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 497062f966..1f5c9b7ad3 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -53,9 +53,11 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { /// Triggered when the view appears. func onViewAppear() { accounts = NCManageDatabase.shared.getAllAccount() + accountRequest = NCKeychain().accountRequest getIndexActiveAccount() } + /// func getIndexActiveAccount() { self.indexActiveAccount = 0 for (index, account) in accounts.enumerated() { @@ -67,6 +69,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } } + /// func getUserName() -> String { guard let tableAccount else { return "" } NCManageDatabase.shared.setAccountAlias(tableAccount.account, alias: alias) @@ -77,6 +80,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } } + /// func getUserStatus() -> (onlineStatus: UIImage?, statusMessage: String?) { guard let tableAccount else { return (nil, nil) } if NCGlobal.shared.capabilityUserStatusEnabled, @@ -89,6 +93,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { return (nil, nil) } + /// func setAccount(account: String) { if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { self.tableAccount = tableAccount From 304b6b8e1144408227b57d6c8b115ddc76ab2692 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 12:53:36 +0200 Subject: [PATCH 26/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountView.swift | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 759803d4ae..4635b4b017 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -36,13 +36,27 @@ struct NCManageAccountView: View { ForEach(0.. Date: Sat, 8 Jun 2024 13:04:26 +0200 Subject: [PATCH 27/57] coding Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountView.swift | 10 +++++++++- .../Supporting Files/en.lproj/Localizable.strings | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 4635b4b017..ac75f3eb4c 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -28,6 +28,8 @@ struct NCManageAccountView: View { @State private var showUserStatus = false @State private var showServerCertificate = false @State private var showPushCertificate = false + @State private var showDeleteAccountAlert: Bool = false + var body: some View { Form { @@ -169,7 +171,7 @@ struct NCManageAccountView: View { /// /// Delete account Button(action: { - + showDeleteAccountAlert.toggle() }, label: { HStack { Image(systemName: "trash") @@ -186,6 +188,12 @@ struct NCManageAccountView: View { } .font(.system(size: 14)) }) + .alert(NSLocalizedString("_want_delete_account_", comment: ""), isPresented: $showDeleteAccountAlert) { + Button(NSLocalizedString("_remove_local_account_", comment: ""), role: .destructive) { + //model.resetNextCloud(exit: showExitAlert) + } + Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel) { } + } }) Section(content: { diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 197292d843..0dd234d090 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -210,7 +210,7 @@ "_copy_failed_" = "Copy failed"; "_certificate_installed_" = "Certificate installed"; "_remove_local_account_" = "Remove local account"; -"_want_delete_account_" = "Do you want to remove local account %@"; +"_want_delete_account_" = "Do you want to remove local account"; "_prevent_http_redirection_"= "The redirection in HTTP is not permitted"; "_pdf_vertical_" = "PDF vertical display"; "_pdf_horizontal_" = "PDF horizontal display"; From fd7258f4258aef67662e6be810ebcaa73b269ae9 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 14:20:33 +0200 Subject: [PATCH 28/57] coding Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountModel.swift | 10 ++++++++++ .../More/Manage Account/NCManageAccountView.swift | 9 ++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 1f5c9b7ad3..3e59226be8 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -107,4 +107,14 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { func updateAccountRequest() { NCKeychain().accountRequest = accountRequest } + + /// + func deleteAccount() { + + } + + /// + func addAccount() { + + } } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index ac75f3eb4c..c6c1e776dc 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -29,7 +29,7 @@ struct NCManageAccountView: View { @State private var showServerCertificate = false @State private var showPushCertificate = false @State private var showDeleteAccountAlert: Bool = false - + @State private var showAddAccount: Bool = false var body: some View { Form { @@ -190,7 +190,7 @@ struct NCManageAccountView: View { }) .alert(NSLocalizedString("_want_delete_account_", comment: ""), isPresented: $showDeleteAccountAlert) { Button(NSLocalizedString("_remove_local_account_", comment: ""), role: .destructive) { - //model.resetNextCloud(exit: showExitAlert) + model.deleteAccount() } Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel) { } } @@ -200,7 +200,7 @@ struct NCManageAccountView: View { /// /// Add account Button(action: { - + showAddAccount.toggle() }, label: { HStack { Image(systemName: "plus") @@ -217,6 +217,9 @@ struct NCManageAccountView: View { } .font(.system(size: 14)) }) + .sheet(isPresented: $showAddAccount) { + + } /// /// Request account Toggle(NSLocalizedString("_settings_account_request_", comment: ""), isOn: $model.accountRequest) From 37e117c5541608bed63ceb52d66d1556d5d0e7c6 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 14:26:24 +0200 Subject: [PATCH 29/57] coding Signed-off-by: Marino Faggiana --- iOSClient/More/Manage Account/NCManageAccountModel.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 3e59226be8..529d5d0f2c 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -110,11 +110,14 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { /// func deleteAccount() { - + if let tableAccount { + appDelegate.deleteAccount(tableAccount.account, wipe: false) + onViewAppear() + } } /// func addAccount() { - + // appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) } } From 4ddbbc7fe6bbb3d63330abdf614365abcb171e0d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sat, 8 Jun 2024 15:26:48 +0200 Subject: [PATCH 30/57] coding Signed-off-by: Marino Faggiana --- iOSClient/More/Manage Account/NCManageAccountModel.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 529d5d0f2c..e59cfb9db0 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -112,6 +112,11 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { func deleteAccount() { if let tableAccount { appDelegate.deleteAccount(tableAccount.account, wipe: false) + if let tableAccount = NCManageDatabase.shared.getAllAccount().first { + appDelegate.changeAccount(tableAccount.account, userProfile: nil) + } else { + addAccount() + } onViewAppear() } } From c0b8356b9df554cc1b9eb51ec2aa37e6bd08d11f Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 9 Jun 2024 13:41:36 +0200 Subject: [PATCH 31/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountModel.swift | 11 ++--- .../Manage Account/NCManageAccountView.swift | 13 ++--- iOSClient/More/NCMore.swift | 2 +- iOSClient/Share/NCShareUserCell.swift | 4 +- iOSClient/UserStatus/NCUserStatus.swift | 8 ++-- iOSClient/Utility/NCUtility+Image.swift | 48 ++++++++++++++++++- iOSClient/Utility/NCUtility.swift | 39 --------------- 7 files changed, 63 insertions(+), 62 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index e59cfb9db0..fe95ced026 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -81,16 +81,13 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } /// - func getUserStatus() -> (onlineStatus: UIImage?, statusMessage: String?) { - guard let tableAccount else { return (nil, nil) } + func getUserStatus() -> (statusImage: UIImage, statusMessage: String, descriptionMessage: String) { + guard let tableAccount else { return (UIImage(), "", "") } if NCGlobal.shared.capabilityUserStatusEnabled, let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", tableAccount.account)) { - let status = NCUtility().getUserStatus(userIcon: tableAccount.userStatusIcon, userStatus: tableAccount.userStatusStatus, userMessage: tableAccount.userStatusMessage) - let image = status.onlineStatus - let text = status.statusMessage - return (image, text) + return NCUtility().getUserStatus(userIcon: tableAccount.userStatusIcon, userStatus: tableAccount.userStatusStatus, userMessage: tableAccount.userStatusMessage) } - return (nil, nil) + return (UIImage(), "", "") } /// diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index c6c1e776dc..120f954156 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -46,12 +46,11 @@ struct NCManageAccountView: View { .resizable() .scaledToFit() .frame(width: UIScreen.main.bounds.width, height: 75) - ZStack { Circle() .fill(.white) .frame(width: 30, height: 30) - Image(uiImage: status.onlineStatus ?? UIImage()) + Image(uiImage: status.statusImage) .resizable() .scaledToFit() .frame(width: 30, height: 30) @@ -61,12 +60,10 @@ struct NCManageAccountView: View { .frame(maxWidth: .infinity, maxHeight: .infinity) Text(model.getUserName()) .font(.system(size: 16)) - if let message = status.statusMessage { - Spacer() - .frame(height: 10) - Text(message) - .font(.system(size: 10)) - } + Spacer() + .frame(height: 10) + Text(status.statusMessage) + .font(.system(size: 10)) } } } diff --git a/iOSClient/More/NCMore.swift b/iOSClient/More/NCMore.swift index fe4ab021eb..6dc47b774a 100644 --- a/iOSClient/More/NCMore.swift +++ b/iOSClient/More/NCMore.swift @@ -348,7 +348,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { if NCGlobal.shared.capabilityUserStatusEnabled, let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) { let status = utility.getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage) - cell.icon.image = status.onlineStatus + cell.icon.image = status.statusImage cell.status.text = status.statusMessage cell.status.textColor = NCBrandColor.shared.textColor cell.status.trailingBuffer = cell.status.frame.width diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift index 842707301f..afa5eba26a 100644 --- a/iOSClient/Share/NCShareUserCell.swift +++ b/iOSClient/Share/NCShareUserCell.swift @@ -72,7 +72,7 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { imageItem.image = NCShareCommon().getImageShareType(shareType: tableShare.shareType) let status = utility.getUserStatus(userIcon: tableShare.userIcon, userStatus: tableShare.userStatus, userMessage: tableShare.userMessage) - imageStatus.image = status.onlineStatus + imageStatus.image = status.statusImage self.status.text = status.statusMessage // If the initiator or the recipient is not the current user, show the list of sharees without any options to edit it. @@ -157,7 +157,7 @@ class NCSearchUserDropDownCell: DropDownCell, NCCellProtocol { imageItem.image = NCShareCommon().getImageShareType(shareType: sharee.shareType) imageShareeType.image = NCShareCommon().getImageShareType(shareType: sharee.shareType) let status = utility.getUserStatus(userIcon: sharee.userIcon, userStatus: sharee.userStatus, userMessage: sharee.userMessage) - imageStatus.image = status.onlineStatus + imageStatus.image = status.statusImage self.status.text = status.statusMessage if self.status.text?.count ?? 0 > 0 { centerTitle.constant = -5 diff --git a/iOSClient/UserStatus/NCUserStatus.swift b/iOSClient/UserStatus/NCUserStatus.swift index 7dda363839..812e77788d 100644 --- a/iOSClient/UserStatus/NCUserStatus.swift +++ b/iOSClient/UserStatus/NCUserStatus.swift @@ -93,7 +93,7 @@ class NCUserStatus: UIViewController { onlineButton.layer.masksToBounds = true onlineButton.backgroundColor = .systemGray5 let onLine = utility.getUserStatus(userIcon: nil, userStatus: "online", userMessage: nil) - onlineImage.image = onLine.onlineStatus + onlineImage.image = onLine.statusImage onlineLabel.text = onLine.statusMessage onlineLabel.textColor = NCBrandColor.shared.textColor @@ -101,7 +101,7 @@ class NCUserStatus: UIViewController { awayButton.layer.masksToBounds = true awayButton.backgroundColor = .systemGray5 let away = utility.getUserStatus(userIcon: nil, userStatus: "away", userMessage: nil) - awayImage.image = away.onlineStatus + awayImage.image = away.statusImage awayLabel.text = away.statusMessage awayLabel.textColor = NCBrandColor.shared.textColor @@ -109,7 +109,7 @@ class NCUserStatus: UIViewController { dndButton.layer.masksToBounds = true dndButton.backgroundColor = .systemGray5 let dnd = utility.getUserStatus(userIcon: nil, userStatus: "dnd", userMessage: nil) - dndImage.image = dnd.onlineStatus + dndImage.image = dnd.statusImage dndLabel.text = dnd.statusMessage dndLabel.textColor = NCBrandColor.shared.textColor dndDescrLabel.text = dnd.descriptionMessage @@ -119,7 +119,7 @@ class NCUserStatus: UIViewController { invisibleButton.layer.masksToBounds = true invisibleButton.backgroundColor = .systemGray5 let invisible = utility.getUserStatus(userIcon: nil, userStatus: "invisible", userMessage: nil) - invisibleImage.image = invisible.onlineStatus + invisibleImage.image = invisible.statusImage invisibleLabel.text = invisible.statusMessage invisibleLabel.textColor = NCBrandColor.shared.textColor invisibleDescrLabel.text = invisible.descriptionMessage diff --git a/iOSClient/Utility/NCUtility+Image.swift b/iOSClient/Utility/NCUtility+Image.swift index 9ab5099e98..4d3afc369c 100644 --- a/iOSClient/Utility/NCUtility+Image.swift +++ b/iOSClient/Utility/NCUtility+Image.swift @@ -30,7 +30,6 @@ import Photos import SVGKit extension NCUtility { - func loadImage(named imageName: String, colors: [UIColor]? = nil, size: CGFloat? = nil, useTypeIconFile: Bool = false ) -> UIImage { var image: UIImage? @@ -405,4 +404,51 @@ extension NCUtility { } return CGSize(width: widthPreview, height: heightPreview) } + + func getUserStatus(userIcon: String?, userStatus: String?, userMessage: String?) -> (statusImage: UIImage, statusMessage: String, descriptionMessage: String) { + var statusImage: UIImage? + var statusMessage: String = "" + var descriptionMessage: String = "" + var messageUserDefined: String = "" + + if userStatus?.lowercased() == "online" { + statusImage = loadImage(named: "circle_fill", colors: [.systemGreen]) + messageUserDefined = NSLocalizedString("_online_", comment: "") + } + if userStatus?.lowercased() == "away" { + statusImage = loadImage(named: "userStatusAway", colors: [UIColor(red: 233.0 / 255.0, green: 166.0 / 255.0, blue: 75.0 / 255.0, alpha: 1.0)]) + /* + onlineStatus = UIImage(named: "userStatusAway")!.image(color: UIColor(red: 233.0 / 255.0, green: 166.0 / 255.0, blue: 75.0 / 255.0, alpha: 1.0), size: 50) + */ + messageUserDefined = NSLocalizedString("_away_", comment: "") + } + if userStatus?.lowercased() == "dnd" { + statusImage = UIImage(named: "userStatusDnd")?.resizeImage(size: CGSize(width: 100, height: 100), isAspectRation: false) + messageUserDefined = NSLocalizedString("_dnd_", comment: "") + descriptionMessage = NSLocalizedString("_dnd_description_", comment: "") + } + if userStatus?.lowercased() == "offline" || userStatus?.lowercased() == "invisible" { + statusImage = UIImage(named: "userStatusOffline")!.withTintColor(.init(named: "SystemBackgroundInverted")!) + messageUserDefined = NSLocalizedString("_invisible_", comment: "") + descriptionMessage = NSLocalizedString("_invisible_description_", comment: "") + } + + if let userIcon = userIcon { + statusMessage = userIcon + " " + } + if let userMessage = userMessage { + statusMessage += userMessage + } + statusMessage = statusMessage.trimmingCharacters(in: .whitespaces) + if statusMessage.isEmpty { + statusMessage = messageUserDefined + } + + if let statusImage { + return(statusImage, statusMessage, descriptionMessage) + } else { + return(UIImage(), statusMessage, descriptionMessage) + + } + } } diff --git a/iOSClient/Utility/NCUtility.swift b/iOSClient/Utility/NCUtility.swift index 43260ca6bb..c3d588b3a9 100644 --- a/iOSClient/Utility/NCUtility.swift +++ b/iOSClient/Utility/NCUtility.swift @@ -136,45 +136,6 @@ class NCUtility: NSObject { return String(intFileId) } - func getUserStatus(userIcon: String?, userStatus: String?, userMessage: String?) -> (onlineStatus: UIImage?, statusMessage: String, descriptionMessage: String) { - var onlineStatus: UIImage? - var statusMessage: String = "" - var descriptionMessage: String = "" - var messageUserDefined: String = "" - - if userStatus?.lowercased() == "online" { - onlineStatus = UIImage(named: "circle_fill")!.image(color: UIColor(red: 103.0 / 255.0, green: 176.0 / 255.0, blue: 134.0 / 255.0, alpha: 1.0), size: 50) - messageUserDefined = NSLocalizedString("_online_", comment: "") - } - if userStatus?.lowercased() == "away" { - onlineStatus = UIImage(named: "userStatusAway")!.image(color: UIColor(red: 233.0 / 255.0, green: 166.0 / 255.0, blue: 75.0 / 255.0, alpha: 1.0), size: 50) - messageUserDefined = NSLocalizedString("_away_", comment: "") - } - if userStatus?.lowercased() == "dnd" { - onlineStatus = UIImage(named: "userStatusDnd")?.resizeImage(size: CGSize(width: 100, height: 100), isAspectRation: false) - messageUserDefined = NSLocalizedString("_dnd_", comment: "") - descriptionMessage = NSLocalizedString("_dnd_description_", comment: "") - } - if userStatus?.lowercased() == "offline" || userStatus?.lowercased() == "invisible" { - onlineStatus = UIImage(named: "userStatusOffline")!.withTintColor(.init(named: "SystemBackgroundInverted")!) - messageUserDefined = NSLocalizedString("_invisible_", comment: "") - descriptionMessage = NSLocalizedString("_invisible_description_", comment: "") - } - - if let userIcon = userIcon { - statusMessage = userIcon + " " - } - if let userMessage = userMessage { - statusMessage += userMessage - } - statusMessage = statusMessage.trimmingCharacters(in: .whitespaces) - if statusMessage.isEmpty { - statusMessage = messageUserDefined - } - - return(onlineStatus, statusMessage, descriptionMessage) - } - @objc func getVersionApp(withBuild: Bool = true) -> String { if let dictionary = Bundle.main.infoDictionary { if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] { From 55eb220bbfe1ad112a5322eed009529197d6a02e Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 9 Jun 2024 18:08:21 +0200 Subject: [PATCH 32/57] coding Signed-off-by: Marino Faggiana --- .../circle_fill.imageset/Contents.json | 10 +++++----- .../circle_fill.imageset/circle.pdf | Bin 3231 -> 0 bytes .../circle_fill.imageset/circle_fill.pdf | Bin 0 -> 3353 bytes iOSClient/Utility/NCUtility+Image.swift | 8 ++------ 4 files changed, 7 insertions(+), 11 deletions(-) delete mode 100644 iOSClient/Images.xcassets/circle_fill.imageset/circle.pdf create mode 100644 iOSClient/Images.xcassets/circle_fill.imageset/circle_fill.pdf diff --git a/iOSClient/Images.xcassets/circle_fill.imageset/Contents.json b/iOSClient/Images.xcassets/circle_fill.imageset/Contents.json index b73baca819..09a262759f 100644 --- a/iOSClient/Images.xcassets/circle_fill.imageset/Contents.json +++ b/iOSClient/Images.xcassets/circle_fill.imageset/Contents.json @@ -1,15 +1,15 @@ { "images" : [ { - "idiom" : "universal", - "filename" : "circle.pdf" + "filename" : "circle_fill.pdf", + "idiom" : "universal" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "preserves-vector-representation" : true } -} \ No newline at end of file +} diff --git a/iOSClient/Images.xcassets/circle_fill.imageset/circle.pdf b/iOSClient/Images.xcassets/circle_fill.imageset/circle.pdf deleted file mode 100644 index 4be68b831daf7f2e043f1280ddbccd035b11d69c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3231 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 G!v6zej=sDA literal 0 HcmV?d00001 diff --git a/iOSClient/Utility/NCUtility+Image.swift b/iOSClient/Utility/NCUtility+Image.swift index 4d3afc369c..23c5bccb99 100644 --- a/iOSClient/Utility/NCUtility+Image.swift +++ b/iOSClient/Utility/NCUtility+Image.swift @@ -412,18 +412,15 @@ extension NCUtility { var messageUserDefined: String = "" if userStatus?.lowercased() == "online" { - statusImage = loadImage(named: "circle_fill", colors: [.systemGreen]) + statusImage = loadImage(named: "circle_fill", colors: [UIColor(red: 103.0 / 255.0, green: 176.0 / 255.0, blue: 134.0 / 255.0, alpha: 1.0)]) messageUserDefined = NSLocalizedString("_online_", comment: "") } if userStatus?.lowercased() == "away" { statusImage = loadImage(named: "userStatusAway", colors: [UIColor(red: 233.0 / 255.0, green: 166.0 / 255.0, blue: 75.0 / 255.0, alpha: 1.0)]) - /* - onlineStatus = UIImage(named: "userStatusAway")!.image(color: UIColor(red: 233.0 / 255.0, green: 166.0 / 255.0, blue: 75.0 / 255.0, alpha: 1.0), size: 50) - */ messageUserDefined = NSLocalizedString("_away_", comment: "") } if userStatus?.lowercased() == "dnd" { - statusImage = UIImage(named: "userStatusDnd")?.resizeImage(size: CGSize(width: 100, height: 100), isAspectRation: false) + statusImage = loadImage(named: "userStatusDnd") messageUserDefined = NSLocalizedString("_dnd_", comment: "") descriptionMessage = NSLocalizedString("_dnd_description_", comment: "") } @@ -448,7 +445,6 @@ extension NCUtility { return(statusImage, statusMessage, descriptionMessage) } else { return(UIImage(), statusMessage, descriptionMessage) - } } } From 93dd51980fd7fce9d9c715de9deb293f3d23261d Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Sun, 9 Jun 2024 18:10:32 +0200 Subject: [PATCH 33/57] coding Signed-off-by: Marino Faggiana --- iOSClient/More/Manage Account/NCManageAccountView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 120f954156..c971b71d6c 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -55,7 +55,7 @@ struct NCManageAccountView: View { .scaledToFit() .frame(width: 30, height: 30) } - .offset(x: 25, y: 25) + .offset(x: 30, y: 30) } .frame(maxWidth: .infinity, maxHeight: .infinity) Text(model.getUserName()) From 60d6ff08c3b8e9b2e6d297d612a42373ca4025a8 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 19 Jun 2024 11:28:27 +0200 Subject: [PATCH 34/57] fix file provider extension Signed-off-by: Marino Faggiana --- .../FileProviderEnumerator.swift | 47 ++++--------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/File Provider Extension/FileProviderEnumerator.swift b/File Provider Extension/FileProviderEnumerator.swift index 07304b9d71..08179e2aa0 100644 --- a/File Provider Extension/FileProviderEnumerator.swift +++ b/File Provider Extension/FileProviderEnumerator.swift @@ -26,20 +26,17 @@ import FileProvider import NextcloudKit class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { - var enumeratedItemIdentifier: NSFileProviderItemIdentifier var serverUrl: String? let fpUtility = fileProviderUtility() init(enumeratedItemIdentifier: NSFileProviderItemIdentifier) { - self.enumeratedItemIdentifier = enumeratedItemIdentifier // Select ServerUrl if enumeratedItemIdentifier == .rootContainer { serverUrl = fileProviderData.shared.homeServerUrl } else { - let metadata = fpUtility.getTableMetadataFromItemIdentifier(enumeratedItemIdentifier) if metadata != nil { if let directorySource = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", metadata!.account, metadata!.serverUrl)) { @@ -56,12 +53,10 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { } func enumerateItems(for observer: NSFileProviderEnumerationObserver, startingAt page: NSFileProviderPage) { - var items: [NSFileProviderItemProtocol] = [] /*** WorkingSet ***/ if enumeratedItemIdentifier == .workingSet { - var itemIdentifierMetadata: [NSFileProviderItemIdentifier: tableMetadata] = [:] // ***** Tags ***** @@ -103,13 +98,10 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { } if page == NSFileProviderPage.initialPageSortedByDate as NSFileProviderPage || page == NSFileProviderPage.initialPageSortedByName as NSFileProviderPage { - self.readFileOrFolder(serverUrl: serverUrl) { metadatas in self.completeObserver(observer, numPage: 1, metadatas: metadatas) } - } else { - let numPage = Int(String(data: page.rawValue, encoding: .utf8)!)! completeObserver(observer, numPage: numPage, metadatas: nil) } @@ -117,7 +109,6 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { } func enumerateChanges(for observer: NSFileProviderChangeObserver, from anchor: NSFileProviderSyncAnchor) { - var itemsDelete: [NSFileProviderItemIdentifier] = [] var itemsUpdate: [FileProviderItem] = [] @@ -166,18 +157,13 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { // -------------------------------------------------------------------------------------------- func completeObserver(_ observer: NSFileProviderEnumerationObserver, numPage: Int, metadatas: [tableMetadata]?) { - var numPage = numPage var items: [NSFileProviderItemProtocol] = [] if metadatas != nil { - for metadata in metadatas! { - if metadata.e2eEncrypted || (!metadata.session.isEmpty && metadata.session != NCNetworking.shared.sessionUploadBackgroundExtension) { continue } - fpUtility.createocIdentifierOnFileSystem(metadata: metadata) - let parentItemIdentifier = fpUtility.getParentItemIdentifier(metadata: metadata) if parentItemIdentifier != nil { let item = FileProviderItem(metadata: metadata, parentItemIdentifier: parentItemIdentifier!) @@ -197,29 +183,16 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { } func readFileOrFolder(serverUrl: String, completionHandler: @escaping (_ metadatas: [tableMetadata]?) -> Void) { - - var directoryEtag: String? - - if let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl)) { - directoryEtag = tableDirectory.etag - } - - NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "0", showHiddenFiles: NCKeychain().showHiddenFiles) { account, files, _, error in - - if directoryEtag != files.first?.etag { - - NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: NCKeychain().showHiddenFiles) { account, files, _, error in - - if error == .success { - DispatchQueue.global().async { - NCManageDatabase.shared.convertFilesToMetadatas(files, useFirstAsMetadataFolder: true) { _, metadatas in - let predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrl, NCGlobal.shared.metadataStatusNormal) - NCManageDatabase.shared.updateMetadatas(metadatas, predicate: predicate) - let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl), sorted: "fileName", ascending: true) - completionHandler(metadatas) - } - } - } else { + NextcloudKit.shared.readFileOrFolder(serverUrlFileName: serverUrl, depth: "1", showHiddenFiles: NCKeychain().showHiddenFiles) { account, files, _, error in + if error == .success { + DispatchQueue.global().async { + NCManageDatabase.shared.convertFilesToMetadatas(files, useFirstAsMetadataFolder: true) { metadataFolder, metadatas in + /// FOLDER + NCManageDatabase.shared.addMetadata(metadataFolder) + NCManageDatabase.shared.addDirectory(e2eEncrypted: metadataFolder.e2eEncrypted, favorite: metadataFolder.favorite, ocId: metadataFolder.ocId, fileId: metadataFolder.fileId, etag: metadataFolder.etag, permissions: metadataFolder.permissions, richWorkspace: metadataFolder.richWorkspace, serverUrl: serverUrl, account: metadataFolder.account) + /// FILES + let predicate = NSPredicate(format: "account == %@ AND serverUrl == %@ AND status == %d", account, serverUrl, NCGlobal.shared.metadataStatusNormal) + NCManageDatabase.shared.updateMetadatas(metadatas, predicate: predicate) let metadatas = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", fileProviderData.shared.account, serverUrl), sorted: "fileName", ascending: true) completionHandler(metadatas) } From 36bc65425a4b028f598993e307618b0c7d142cc1 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 19 Jun 2024 12:31:26 +0200 Subject: [PATCH 35/57] cleaning DB Signed-off-by: Marino Faggiana --- Brand/Database.swift | 2 +- iOSClient/Data/NCManageDatabase+Account.swift | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Brand/Database.swift b/Brand/Database.swift index 04492bd278..3a2f4ed488 100644 --- a/Brand/Database.swift +++ b/Brand/Database.swift @@ -26,4 +26,4 @@ import Foundation // Database Realm // let databaseName = "nextcloud.realm" -let databaseSchemaVersion: UInt64 = 347 +let databaseSchemaVersion: UInt64 = 348 diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index 0819f2b8ce..d19a8374ea 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -44,10 +44,6 @@ class tableAccount: Object, NCUserBaseUrl { @objc dynamic var backend = "" @objc dynamic var backendCapabilitiesSetDisplayName: Bool = false @objc dynamic var backendCapabilitiesSetPassword: Bool = false - @objc dynamic var businessSize: String = "" - @objc dynamic var businessType = "" - @objc dynamic var city = "" - @objc dynamic var country = "" @objc dynamic var displayName = "" @objc dynamic var email = "" @objc dynamic var enabled: Bool = false @@ -64,7 +60,6 @@ class tableAccount: Object, NCUserBaseUrl { @objc dynamic var quotaRelative: Double = 0 @objc dynamic var quotaTotal: Int64 = 0 @objc dynamic var quotaUsed: Int64 = 0 - @objc dynamic var role = "" @objc dynamic var storageLocation = "" @objc dynamic var subadmin = "" @objc dynamic var twitter = "" @@ -79,7 +74,6 @@ class tableAccount: Object, NCUserBaseUrl { @objc dynamic var userStatusStatus: String? @objc dynamic var userStatusStatusIsUserDefined: Bool = false @objc dynamic var website = "" - @objc dynamic var zip = "" override static func primaryKey() -> String { return "account" From 7f0c4b3e6370c3833272550eaf3ae537f45516c2 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 19 Jun 2024 15:48:06 +0200 Subject: [PATCH 36/57] coding Signed-off-by: Marino Faggiana --- iOSClient/Data/NCManageDatabase.swift | 15 ++++-- .../Manage Account/NCManageAccountModel.swift | 13 +++++ .../Manage Account/NCManageAccountView.swift | 47 ++++++++++++++++++- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index b1286c9d07..daf5df2fbb 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -291,16 +291,21 @@ class NCManageDatabase: NSObject { func previewCreateDB() { /// Account - let account = "marinofaggiana https://cloud.nextcloud.com" - let account2 = "mariorossi https://cloud.nextcloud.com" - NCManageDatabase.shared.addAccount(account, urlBase: "https://cloud.nextcloud.com", user: "marinofaggiana", userId: "marinofaggiana", password: "password") - NCManageDatabase.shared.addAccount(account2, urlBase: "https://cloud.nextcloud.com", user: "mariorossi", userId: "mariorossi", password: "password") + let account = "marinofaggiana https://cloudtest.nextcloud.com" + let account2 = "mariorossi https://cloudtest.nextcloud.com" + NCManageDatabase.shared.addAccount(account, urlBase: "https://cloudtest.nextcloud.com", user: "marinofaggiana", userId: "marinofaggiana", password: "password") + NCManageDatabase.shared.addAccount(account2, urlBase: "https://cloudtest.nextcloud.com", user: "mariorossi", userId: "mariorossi", password: "password") let userProfile = NKUserProfile() userProfile.displayName = "Marino Faggiana" + userProfile.address = "Hirschstrasse 26, 70192 Stuttgart, Germany" + userProfile.phone = "+49 (711) 252 428 - 90" + userProfile.email = "cloudtest@nextcloud.com" NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile) let userProfile2 = NKUserProfile() userProfile2.displayName = "Mario Rossi" + userProfile2.phone = "+49 (711) 252 428 - 90" + userProfile2.address = "Hirschstrasse 26, 70192 Stuttgart, Germany" + userProfile2.email = "cloudtest@nextcloud.com" NCManageDatabase.shared.setAccountUserProfile(account: account2, userProfile: userProfile2) - } } diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index fe95ced026..811cbdd7a3 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -90,6 +90,19 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { return (UIImage(), "", "") } + /// + func getTableViewHeight() -> CGFloat { + guard let tableAccount else { return 0 } + var height: CGFloat = 170 + if NCGlobal.shared.capabilityUserStatusEnabled, + let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", tableAccount.account)) { + if !tableAccount.email.isEmpty { height += 30 } + if !tableAccount.phone.isEmpty { height += 30 } + if !tableAccount.address.isEmpty { height += 30 } + } + return height + } + /// func setAccount(account: String) { if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index c971b71d6c..7056c398e7 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -64,11 +64,56 @@ struct NCManageAccountView: View { .frame(height: 10) Text(status.statusMessage) .font(.system(size: 10)) + Spacer() + .frame(height: 20) + /// Personal data + if let tableAccount = model.tableAccount, !tableAccount.email.isEmpty { + HStack { + Image(systemName: "mail") + .resizable() + .scaledToFit() + .lineLimit(1) + .truncationMode(.middle) + .frame(width: 25, height: 25) + Text(tableAccount.email) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.system(size: 16)) + } + .frame(maxWidth: .infinity, maxHeight: 30) + } + if let tableAccount = model.tableAccount, !tableAccount.phone.isEmpty { + HStack { + Image(systemName: "phone") + .resizable() + .scaledToFit() + .lineLimit(1) + .truncationMode(.middle) + .frame(width: 25, height: 25) + Text(tableAccount.phone) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.system(size: 16)) + } + .frame(maxWidth: .infinity, maxHeight: 30) + } + if let tableAccount = model.tableAccount, !tableAccount.address.isEmpty { + HStack { + Image(systemName: "house") + .resizable() + .scaledToFit() + .lineLimit(1) + .truncationMode(.middle) + .frame(width: 25, height: 25) + Text(tableAccount.address) + .frame(maxWidth: .infinity, alignment: .leading) + .font(.system(size: 16)) + } + .frame(maxWidth: .infinity, maxHeight: 30) + } } } } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - .frame(height: 150) + .frame(height: model.getTableViewHeight()) .onChange(of: model.indexActiveAccount) { index in model.setAccount(account: model.accounts[index].account) } From 8c121323d08f5fc428e5188cc3edd27d725df476 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 19 Jun 2024 16:16:28 +0200 Subject: [PATCH 37/57] coding Signed-off-by: Marino Faggiana --- .../Collection Common/NCCollectionViewCommon.swift | 11 ++++++++++- .../More/Manage Account/NCManageAccountModel.swift | 12 +++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 7dbb415db7..20cf6b1c32 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -22,6 +22,7 @@ // import UIKit +import SwiftUI import Realm import NextcloudKit import EasyTipView @@ -625,11 +626,19 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS return action } + /* let addAccountAction = UIAction(title: NSLocalizedString("_add_account_", comment: ""), image: utility.loadImage(named: "person.crop.circle.badge.plus", colors: NCBrandColor.shared.iconImageMultiColors)) { _ in self.appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) } + */ - let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: [addAccountAction]) + let settingsAccountAction = UIAction(title: NSLocalizedString("_settings_", comment: ""), image: utility.loadImage(named: "gear", colors: [NCBrandColor.shared.iconImageColor])) { _ in + let manageAccountView = NCManageAccountView(model: NCManageAccountModel(controller: self.tabBarController as? NCMainTabBarController)) + let manageAccountController = UIHostingController(rootView: manageAccountView) + self.present(manageAccountController, animated: true, completion: nil) + } + + let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: [settingsAccountAction]) let menu = UIMenu(children: accountActions + [addAccountSubmenu]) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 811cbdd7a3..3ebeb45381 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -105,11 +105,13 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { /// func setAccount(account: String) { - if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { - self.tableAccount = tableAccount - self.alias = tableAccount.alias - /// Change active account - appDelegate.changeAccount(tableAccount.account, userProfile: nil) + DispatchQueue.global().async { + if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { + self.tableAccount = tableAccount + self.alias = tableAccount.alias + /// Change active account + self.appDelegate.changeAccount(tableAccount.account, userProfile: nil) + } } } From 202c1902be8e9f871b34a9b32129d2bfa360db88 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 09:51:29 +0200 Subject: [PATCH 38/57] cod Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 8 -- .../NCCollectionViewCommon.swift | 6 +- iOSClient/More/Cells/NCMoreUserCell.swift | 44 ----------- iOSClient/More/Cells/NCMoreUserCell.xib | 77 ------------------- .../Manage Account/NCManageAccountModel.swift | 7 +- .../Manage Account/NCManageAccountView.swift | 60 ++++----------- iOSClient/More/NCMore.swift | 58 ++------------ .../Settings/Settings/NCSettingsModel.swift | 8 ++ .../Settings/Settings/NCSettingsView.swift | 17 +++- .../en.lproj/Localizable.strings | 3 + 10 files changed, 50 insertions(+), 238 deletions(-) delete mode 100644 iOSClient/More/Cells/NCMoreUserCell.swift delete mode 100755 iOSClient/More/Cells/NCMoreUserCell.xib diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index a413294eac..16945df41b 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -81,7 +81,6 @@ F3391B102B4C52E6001C0C4B /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B0F2B4C52E6001C0C4B /* SVGKit */; }; F3391B142B4C52EF001C0C4B /* JGProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B132B4C52EF001C0C4B /* JGProgressHUD */; }; F3391B162B4C52F6001C0C4B /* FirebaseDatabase in Frameworks */ = {isa = PBXBuildFile; productRef = F3391B152B4C52F6001C0C4B /* FirebaseDatabase */; }; - F33AAF9A2A60394C006ECCBD /* NCMoreUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */; }; F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; }; F343A4B42A1E084100DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; }; F343A4B52A1E084200DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; }; @@ -145,7 +144,6 @@ F3A0479E2BD268B500658E7B /* PopupView in Frameworks */ = {isa = PBXBuildFile; productRef = F3A0479D2BD268B500658E7B /* PopupView */; }; F3A7AFC62A41AA82001FC89C /* BaseUIXCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3A7AFC52A41AA82001FC89C /* BaseUIXCTestCase.swift */; }; F3BB464D2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F3BB464C2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib */; }; - F3BB464F2A39EBE500461F6E /* NCMoreUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */; }; F3BB46522A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */; }; F3BB46542A3A1E9D00461F6E /* CCCellMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */; }; F3F0419B2B9F7E6700D5155F /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F3F0419A2B9F7E6700D5155F /* RealmSwift */; }; @@ -1115,7 +1113,6 @@ F3131ED82B038DB20018DB28 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/System/iOSSupport/System/Library/Frameworks/SwiftUI.framework; sourceTree = DEVELOPER_DIR; }; F3131EDA2B038DB90018DB28 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/System/iOSSupport/System/Library/Frameworks/WidgetKit.framework; sourceTree = DEVELOPER_DIR; }; F321DA892B71205A00DDA0E6 /* NCTrashSelectTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTrashSelectTabBar.swift; sourceTree = ""; }; - F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCMoreUserCell.xib; sourceTree = ""; }; F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAsset+Extension.swift"; sourceTree = ""; }; F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = ""; }; F359D8662A7D03420023F405 /* NCUtility+Exif.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCUtility+Exif.swift"; sourceTree = ""; }; @@ -1135,7 +1132,6 @@ F3A047962BD2668800658E7B /* NCAssistant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAssistant.swift; sourceTree = ""; }; F3A7AFC52A41AA82001FC89C /* BaseUIXCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUIXCTestCase.swift; sourceTree = ""; }; F3BB464C2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCMoreAppSuggestionsCell.xib; sourceTree = ""; }; - F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreUserCell.swift; sourceTree = ""; }; F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreAppSuggestionsCell.swift; sourceTree = ""; }; F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCCellMore.swift; sourceTree = ""; }; F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = ""; }; @@ -2004,8 +2000,6 @@ children = ( F3BB464C2A39ADCC00461F6E /* NCMoreAppSuggestionsCell.xib */, F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */, - F33AAF992A60394C006ECCBD /* NCMoreUserCell.xib */, - F3BB464E2A39EBE500461F6E /* NCMoreUserCell.swift */, F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */, F39298962A3B12CB00509762 /* BaseNCMoreCell.swift */, ); @@ -3676,7 +3670,6 @@ F723985C253C95CE00257F49 /* NCViewerRichdocument.storyboard in Resources */, F758B45A212C564000515F55 /* NCScan.storyboard in Resources */, F70D87CF25EE6E58008CBBBD /* NCRenameFile.storyboard in Resources */, - F33AAF9A2A60394C006ECCBD /* NCMoreUserCell.xib in Resources */, F765F73225237E3F00391DBE /* NCRecent.storyboard in Resources */, F78F74342163757000C2ADAD /* NCTrash.storyboard in Resources */, F702F30225EE5D2C008F8E80 /* english.txt in Resources */, @@ -4355,7 +4348,6 @@ F7134186259747BA00768D21 /* NCPushNotification.m in Sources */, F76882322C0DD1E7001CF441 /* NCAutoUploadView.swift in Sources */, F36E64F72B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift in Sources */, - F3BB464F2A39EBE500461F6E /* NCMoreUserCell.swift in Sources */, F79A65C62191D95E00FF6DCC /* NCSelect.swift in Sources */, F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */, F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */, diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 20cf6b1c32..c69d928bc3 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -626,19 +626,17 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS return action } - /* let addAccountAction = UIAction(title: NSLocalizedString("_add_account_", comment: ""), image: utility.loadImage(named: "person.crop.circle.badge.plus", colors: NCBrandColor.shared.iconImageMultiColors)) { _ in self.appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) } - */ - let settingsAccountAction = UIAction(title: NSLocalizedString("_settings_", comment: ""), image: utility.loadImage(named: "gear", colors: [NCBrandColor.shared.iconImageColor])) { _ in + let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "person.crop.circle.badge.checkmark", colors: NCBrandColor.shared.iconImageMultiColors)) { _ in let manageAccountView = NCManageAccountView(model: NCManageAccountModel(controller: self.tabBarController as? NCMainTabBarController)) let manageAccountController = UIHostingController(rootView: manageAccountView) self.present(manageAccountController, animated: true, completion: nil) } - let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: [settingsAccountAction]) + let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: [addAccountAction, settingsAccountAction]) let menu = UIMenu(children: accountActions + [addAccountSubmenu]) diff --git a/iOSClient/More/Cells/NCMoreUserCell.swift b/iOSClient/More/Cells/NCMoreUserCell.swift deleted file mode 100644 index 1d6e30cece..0000000000 --- a/iOSClient/More/Cells/NCMoreUserCell.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// NCMoreUserCell.swift -// Nextcloud -// -// Created by Milen on 14.06.23. -// Copyright © 2023 Marino Faggiana. All rights reserved. -// -// Author Marino Faggiana -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -import Foundation -import MarqueeLabel - -class NCMoreUserCell: BaseNCMoreCell { - @IBOutlet weak var displayName: UILabel! - @IBOutlet weak var avatar: UIImageView! - @IBOutlet weak var icon: UIImageView! - @IBOutlet weak var status: MarqueeLabel! - - static let reuseIdentifier = "NCMoreUserCell" - - static func fromNib() -> UINib { - return UINib(nibName: "NCMoreUserCell", bundle: nil) - } - - override func awakeFromNib() { - super.awakeFromNib() - - icon.makeCircularBackground(withColor: .systemBackground) - } -} diff --git a/iOSClient/More/Cells/NCMoreUserCell.xib b/iOSClient/More/Cells/NCMoreUserCell.xib deleted file mode 100755 index 5cd96162bd..0000000000 --- a/iOSClient/More/Cells/NCMoreUserCell.xib +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 3ebeb45381..cf923c9d1d 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -93,7 +93,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { /// func getTableViewHeight() -> CGFloat { guard let tableAccount else { return 0 } - var height: CGFloat = 170 + var height: CGFloat = 190 if NCGlobal.shared.capabilityUserStatusEnabled, let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", tableAccount.account)) { if !tableAccount.email.isEmpty { height += 30 } @@ -115,11 +115,6 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } } - /// - func updateAccountRequest() { - NCKeychain().accountRequest = accountRequest - } - /// func deleteAccount() { if let tableAccount { diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 7056c398e7..49755928c7 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -72,12 +72,13 @@ struct NCManageAccountView: View { Image(systemName: "mail") .resizable() .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + Text(tableAccount.email) .lineLimit(1) .truncationMode(.middle) - .frame(width: 25, height: 25) - Text(tableAccount.email) .frame(maxWidth: .infinity, alignment: .leading) - .font(.system(size: 16)) + } .frame(maxWidth: .infinity, maxHeight: 30) } @@ -86,12 +87,12 @@ struct NCManageAccountView: View { Image(systemName: "phone") .resizable() .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + Text(tableAccount.phone) .lineLimit(1) .truncationMode(.middle) - .frame(width: 25, height: 25) - Text(tableAccount.phone) .frame(maxWidth: .infinity, alignment: .leading) - .font(.system(size: 16)) } .frame(maxWidth: .infinity, maxHeight: 30) } @@ -100,18 +101,19 @@ struct NCManageAccountView: View { Image(systemName: "house") .resizable() .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + Text(tableAccount.address) .lineLimit(1) .truncationMode(.middle) - .frame(width: 25, height: 25) - Text(tableAccount.address) .frame(maxWidth: .infinity, alignment: .leading) - .font(.system(size: 16)) } .frame(maxWidth: .infinity, maxHeight: 30) } } } } + .font(.system(size: 14)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .frame(height: model.getTableViewHeight()) .onChange(of: model.indexActiveAccount) { index in @@ -210,8 +212,10 @@ struct NCManageAccountView: View { certificateDetailsView(host: host, title: NSLocalizedString("_certificate_pn_view_", comment: "")) } } - /// - /// Delete account + }) + /// + /// Delete account + Section(content: { Button(action: { showDeleteAccountAlert.toggle() }, label: { @@ -237,40 +241,6 @@ struct NCManageAccountView: View { Button(NSLocalizedString("_cancel_", comment: ""), role: .cancel) { } } }) - - Section(content: { - /// - /// Add account - Button(action: { - showAddAccount.toggle() - }, label: { - HStack { - Image(systemName: "plus") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) - Text(NSLocalizedString("_add_account_", comment: "")) - .lineLimit(1) - .truncationMode(.middle) - .foregroundStyle(Color(NCBrandColor.shared.iconImageColor)) - .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 20)) - } - .font(.system(size: 14)) - }) - .sheet(isPresented: $showAddAccount) { - - } - /// - /// Request account - Toggle(NSLocalizedString("_settings_account_request_", comment: ""), isOn: $model.accountRequest) - .font(.system(size: 16)) - .tint(Color(NCBrandColor.shared.brandElement)) - .onChange(of: model.accountRequest, perform: { _ in - model.updateAccountRequest() - }) - }) } .navigationBarTitle(NSLocalizedString("_credentials_", comment: "")) .defaultViewModifier(model) diff --git a/iOSClient/More/NCMore.swift b/iOSClient/More/NCMore.swift index 6dc47b774a..730b2398e9 100644 --- a/iOSClient/More/NCMore.swift +++ b/iOSClient/More/NCMore.swift @@ -50,7 +50,6 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { var type: SectionType enum SectionType { - case account case moreApps case regular } @@ -70,7 +69,6 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { tableView.delegate = self tableView.dataSource = self tableView.backgroundColor = .systemGroupedBackground - tableView.register(NCMoreUserCell.fromNib(), forCellReuseIdentifier: NCMoreUserCell.reuseIdentifier) tableView.register(NCMoreAppSuggestionsCell.fromNib(), forCellReuseIdentifier: NCMoreAppSuggestionsCell.reuseIdentifier) // create tap gesture recognizer @@ -251,9 +249,11 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { } private func loadSections() { + /* if tabAccount != nil { sections.append(Section(items: [NKExternalSite()], type: .account)) } + */ if !NCBrandOptions.shared.disable_show_more_nextcloud_apps_in_settings { sections.append(Section(items: [NKExternalSite()], type: .moreApps)) @@ -296,11 +296,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { // MARK: - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - if sections[indexPath.section].type == .account { - return 75 - } else { - return 50 - } + return 50 } func numberOfSections(in tableView: UITableView) -> Int { @@ -310,9 +306,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, heightForHeaderInSection index: Int) -> CGFloat { let section = sections[index] - if section.type == .account { - return 10 - } else if section.type == .moreApps || sections[index - 1].type == .moreApps { + if section.type == .moreApps || sections[index - 1].type == .moreApps { return 1 } else { return 20 @@ -326,44 +320,7 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let section = sections[indexPath.section] - if section.type == .account { - - guard let cell = tableView.dequeueReusableCell(withIdentifier: NCMoreUserCell.reuseIdentifier, for: indexPath) as? NCMoreUserCell else { return UITableViewCell() } - - cell.avatar.image = nil - cell.icon.image = nil - cell.status.text = "" - cell.displayName.text = "" - - if let account = tabAccount { - cell.avatar.image = utility.loadUserImage(for: account.user, displayName: account.displayName, userBaseUrl: appDelegate) - if account.alias.isEmpty { - cell.displayName?.text = account.displayName - } else { - cell.displayName?.text = account.displayName + " (" + account.alias + ")" - } - cell.displayName.textColor = NCBrandColor.shared.textColor - } - cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator - - if NCGlobal.shared.capabilityUserStatusEnabled, let account = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", appDelegate.account)) { - let status = utility.getUserStatus(userIcon: account.userStatusIcon, userStatus: account.userStatusStatus, userMessage: account.userStatusMessage) - cell.icon.image = status.statusImage - cell.status.text = status.statusMessage - cell.status.textColor = NCBrandColor.shared.textColor - cell.status.trailingBuffer = cell.status.frame.width - if cell.status.labelShouldScroll() { - cell.status.tapToScroll = true - } else { - cell.status.tapToScroll = false - } - } - - cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner] - - return cell - - } else if section.type == .moreApps { + if section.type == .moreApps { guard let cell = tableView.dequeueReusableCell(withIdentifier: NCMoreAppSuggestionsCell.reuseIdentifier, for: indexPath) as? NCMoreAppSuggestionsCell else { return UITableViewCell() } return cell } else { @@ -405,11 +362,6 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let item = sections[indexPath.section].items[indexPath.row] - // Menu Function - if sections[indexPath.section].type == .account { - tapImageLogoManageAccount() - return - } // Action if item.url.contains("segue") && !item.url.contains("//") { self.navigationController?.performSegue(withIdentifier: item.url, sender: self) diff --git a/iOSClient/Settings/Settings/NCSettingsModel.swift b/iOSClient/Settings/Settings/NCSettingsModel.swift index 451fbb7da6..dcf51ec18f 100644 --- a/iOSClient/Settings/Settings/NCSettingsModel.swift +++ b/iOSClient/Settings/Settings/NCSettingsModel.swift @@ -43,6 +43,8 @@ class NCSettingsModel: ObservableObject, ViewOnAppearHandling { @Published var privacyScreen: Bool = false /// State to control @Published var resetWrongAttempts: Bool = false + /// Request account on start + @Published var accountRequest: Bool = false /// Root View Controller @Published var controller: NCMainTabBarController? /// Footer @@ -63,6 +65,7 @@ class NCSettingsModel: ObservableObject, ViewOnAppearHandling { lockScreen = !keychain.requestPasscodeAtStart privacyScreen = keychain.privacyScreenEnabled resetWrongAttempts = keychain.resetAppCounterFail + accountRequest = keychain.accountRequest footerApp = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility().getVersionApp(withBuild: true)) + "\n\n" footerServer = String(format: NCBrandOptions.shared.textCopyrightNextcloudServer, NCGlobal.shared.capabilityServerVersion) + "\n" footerSlogan = NCGlobal.shared.capabilityThemingName + " - " + NCGlobal.shared.capabilityThemingSlogan + "\n\n" @@ -99,6 +102,11 @@ class NCSettingsModel: ObservableObject, ViewOnAppearHandling { configServer.startService(url: url) } } + + /// Function to update Account request on start + func updateAccountRequest() { + keychain.accountRequest = accountRequest + } } struct PasscodeView: UIViewControllerRepresentable { diff --git a/iOSClient/Settings/Settings/NCSettingsView.swift b/iOSClient/Settings/Settings/NCSettingsView.swift index 93cafd8b7a..1fc7030c00 100644 --- a/iOSClient/Settings/Settings/NCSettingsView.swift +++ b/iOSClient/Settings/Settings/NCSettingsView.swift @@ -158,7 +158,22 @@ struct NCSettingsView: View { .lineSpacing(1) }) } - /// `E2EEncryption` Section + /// Users + Section(content: { + Toggle(NSLocalizedString("_settings_account_request_", comment: ""), isOn: $model.accountRequest) + .font(.system(size: 16)) + .tint(Color(NCBrandColor.shared.brandElement)) + .onChange(of: model.accountRequest, perform: { _ in + model.updateAccountRequest() + }) + }, header: { + Text(NSLocalizedString("_users_", comment: "")) + }, footer: { + Text(NSLocalizedString("_users_footer_", comment: "")) + .font(.system(size: 12)) + .lineSpacing(1) + }) + /// E2EEncryption` Section if NCGlobal.shared.capabilityE2EEEnabled && NCGlobal.shared.e2eeVersions.contains(NCGlobal.shared.capabilityE2EEApiVersion) { E2EESection(model: model) } diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 0dd234d090..2f4abd39b4 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -988,6 +988,9 @@ "_light_" = "Light"; "_dark_" = "Dark"; "_use_system_style_" = "Use system style"; +"_account_settings_" = "Settings account"; +"_users_" = "Users"; +"_users_footer_" = "Every time the app is reactivated, the account will be requested"; // Video "_select_trace_" = "Select the trace"; From 39f8b76579b387791b9e3f264fbac4f88a430acb Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 10:09:48 +0200 Subject: [PATCH 39/57] coding Signed-off-by: Marino Faggiana --- .../Manage Account/NCManageAccountModel.swift | 39 +++++++++---------- .../Manage Account/NCManageAccountView.swift | 7 ++++ .../en.lproj/Localizable.strings | 2 +- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index cf923c9d1d..bdca4a7247 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -32,14 +32,16 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { var controller: NCMainTabBarController? /// All account var accounts: [tableAccount] = [] - /// Account + /// Account now active @Published var tableAccount: tableAccount? - /// + /// Index @Published var indexActiveAccount: Int = 0 - /// + /// Current alias @Published var alias: String = "" - /// + /// State to control @Published var accountRequest: Bool = false + /// Set true for dismiss the view + @Published var dismissView = false /// Initialization code to set up the ViewModel with the active account init(controller: NCMainTabBarController?) { @@ -57,7 +59,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { getIndexActiveAccount() } - /// + /// Internal use func getIndexActiveAccount() { self.indexActiveAccount = 0 for (index, account) in accounts.enumerated() { @@ -69,7 +71,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } } - /// + /// Func to get the user display name + alias func getUserName() -> String { guard let tableAccount else { return "" } NCManageDatabase.shared.setAccountAlias(tableAccount.account, alias: alias) @@ -80,7 +82,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { } } - /// + /// Function to update the user data func getUserStatus() -> (statusImage: UIImage, statusMessage: String, descriptionMessage: String) { guard let tableAccount else { return (UIImage(), "", "") } if NCGlobal.shared.capabilityUserStatusEnabled, @@ -90,7 +92,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { return (UIImage(), "", "") } - /// + /// Function to know the height of "account" data func getTableViewHeight() -> CGFloat { guard let tableAccount else { return 0 } var height: CGFloat = 190 @@ -103,33 +105,28 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { return height } - /// + /// Function to change account func setAccount(account: String) { - DispatchQueue.global().async { - if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { - self.tableAccount = tableAccount - self.alias = tableAccount.alias - /// Change active account + if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { + self.tableAccount = tableAccount + self.alias = tableAccount.alias + /// Change active account + DispatchQueue.global().async { self.appDelegate.changeAccount(tableAccount.account, userProfile: nil) } } } - /// + /// Function to delete the current account func deleteAccount() { if let tableAccount { appDelegate.deleteAccount(tableAccount.account, wipe: false) if let tableAccount = NCManageDatabase.shared.getAllAccount().first { appDelegate.changeAccount(tableAccount.account, userProfile: nil) } else { - addAccount() + self.dismissView = true } onViewAppear() } } - - /// - func addAccount() { - // appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) - } } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index 49755928c7..ec8791e157 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -31,6 +31,8 @@ struct NCManageAccountView: View { @State private var showDeleteAccountAlert: Bool = false @State private var showAddAccount: Bool = false + @Environment(\.presentationMode) var presentationMode + var body: some View { Form { Section(content: { @@ -244,6 +246,11 @@ struct NCManageAccountView: View { } .navigationBarTitle(NSLocalizedString("_credentials_", comment: "")) .defaultViewModifier(model) + .onReceive(model.$dismissView) { newValue in + if newValue { + presentationMode.wrappedValue.dismiss() + } + } } } diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 2f4abd39b4..0440fffbdb 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -988,7 +988,7 @@ "_light_" = "Light"; "_dark_" = "Dark"; "_use_system_style_" = "Use system style"; -"_account_settings_" = "Settings account"; +"_account_settings_" = "Account settings"; "_users_" = "Users"; "_users_footer_" = "Every time the app is reactivated, the account will be requested"; From d1cd4ae7d2e8d7a303bb2dd918668cbd3de6c4c6 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 10:16:17 +0200 Subject: [PATCH 40/57] coding Signed-off-by: Marino Faggiana --- iOSClient/More/Manage Account/NCManageAccountModel.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index bdca4a7247..80e799ec71 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -124,7 +124,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { if let tableAccount = NCManageDatabase.shared.getAllAccount().first { appDelegate.changeAccount(tableAccount.account, userProfile: nil) } else { - self.dismissView = true + dismissView = true + appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) } onViewAppear() } From d010fafb08ed3e6f1d02d6ddfa5852970e10e7f4 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 10:25:47 +0200 Subject: [PATCH 41/57] cleaning Signed-off-by: Marino Faggiana --- iOSClient/More/Manage Account/NCManageAccountModel.swift | 1 + iOSClient/More/Manage Account/NCManageAccountView.swift | 2 ++ 2 files changed, 3 insertions(+) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index 80e799ec71..bd2fa97310 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -102,6 +102,7 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { if !tableAccount.phone.isEmpty { height += 30 } if !tableAccount.address.isEmpty { height += 30 } } + if height == 190 { return 170 } return height } diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Manage Account/NCManageAccountView.swift index ec8791e157..5e1335dab6 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Manage Account/NCManageAccountView.swift @@ -25,6 +25,7 @@ import SwiftUI struct NCManageAccountView: View { @ObservedObject var model: NCManageAccountModel + @State private var showUserStatus = false @State private var showServerCertificate = false @State private var showPushCertificate = false @@ -68,6 +69,7 @@ struct NCManageAccountView: View { .font(.system(size: 10)) Spacer() .frame(height: 20) + /// /// Personal data if let tableAccount = model.tableAccount, !tableAccount.email.isEmpty { HStack { From 24ddecf47d54f20a68fa7b4ebd585a66d235ad41 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 10:29:47 +0200 Subject: [PATCH 42/57] coding Signed-off-by: Marino Faggiana --- iOSClient/UserStatus/NCUserStatus.swift | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/iOSClient/UserStatus/NCUserStatus.swift b/iOSClient/UserStatus/NCUserStatus.swift index 812e77788d..886e549fb8 100644 --- a/iOSClient/UserStatus/NCUserStatus.swift +++ b/iOSClient/UserStatus/NCUserStatus.swift @@ -28,10 +28,6 @@ import SwiftUI import NextcloudKit import DropDown -protocol NCUserStatusDelegate: AnyObject { - func userStatusDismiss(_ viewController: NCUserStatus) -} - class NCUserStatus: UIViewController { @IBOutlet weak var buttonCancel: UIBarButtonItem! @@ -67,8 +63,6 @@ class NCUserStatus: UIViewController { @IBOutlet weak var clearStatusMessageButton: UIButton! @IBOutlet weak var setStatusMessageButton: UIButton! - weak var delegate: NCUserStatusDelegate? - private var statusPredefinedStatuses: [NKUserStatus] = [] private let utility = NCUtility() private var clearAtTimestamp: Double = 0 // Unix Timestamp representing the time to clear the status @@ -181,7 +175,6 @@ class NCUserStatus: UIViewController { NextcloudKit.shared.getUserStatus { account, clearAt, icon, message, messageId, messageIsPredefined, status, statusIsUserDefined, _, _, error in if error == .success { NCManageDatabase.shared.setAccountUserStatus(userStatusClearAt: clearAt, userStatusIcon: icon, userStatusMessage: message, userStatusMessageId: messageId, userStatusMessageIsPredefined: messageIsPredefined, userStatusStatus: status, userStatusStatusIsUserDefined: statusIsUserDefined, account: account) - self.delegate?.userStatusDismiss(self) } } } @@ -615,16 +608,12 @@ extension NCUserStatus: UITableViewDataSource { struct UserStatusView: UIViewControllerRepresentable { @Binding var showUserStatus: Bool - class Coordinator: NSObject, NCUserStatusDelegate { + class Coordinator: NSObject { var parent: UserStatusView init(_ parent: UserStatusView) { self.parent = parent } - - func userStatusDismiss(_ viewController: NCUserStatus) { - parent.showUserStatus = false - } } func makeUIViewController(context: Context) -> UINavigationController { @@ -632,7 +621,6 @@ struct UserStatusView: UIViewControllerRepresentable { let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController let viewController = navigationController?.topViewController as? NCUserStatus - viewController?.delegate = context.coordinator return navigationController! } From c911ea643db97e20000698d9ccdc8cc6de763f51 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 10:38:54 +0200 Subject: [PATCH 43/57] fix icon Signed-off-by: Marino Faggiana --- iOSClient/Main/Collection Common/NCCollectionViewCommon.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index c69d928bc3..7cd109f437 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -630,7 +630,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS self.appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) } - let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "person.crop.circle.badge.checkmark", colors: NCBrandColor.shared.iconImageMultiColors)) { _ in + let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "person.crop.circle", colors: [NCBrandColor.shared.iconImageColor])) { _ in let manageAccountView = NCManageAccountView(model: NCManageAccountModel(controller: self.tabBarController as? NCMainTabBarController)) let manageAccountController = UIHostingController(rootView: manageAccountView) self.present(manageAccountController, animated: true, completion: nil) From a3f0bcba9fa3765017ec755a2ea41191aa6603f5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 10:54:00 +0200 Subject: [PATCH 44/57] add timer for change user Signed-off-by: Marino Faggiana --- .../More/Manage Account/NCManageAccountModel.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Manage Account/NCManageAccountModel.swift index bd2fa97310..e5c275d541 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Manage Account/NCManageAccountModel.swift @@ -32,6 +32,8 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { var controller: NCMainTabBarController? /// All account var accounts: [tableAccount] = [] + /// Timer change account + var timerChanheAccount: Timer? /// Account now active @Published var tableAccount: tableAccount? /// Index @@ -112,9 +114,14 @@ class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { self.tableAccount = tableAccount self.alias = tableAccount.alias /// Change active account - DispatchQueue.global().async { - self.appDelegate.changeAccount(tableAccount.account, userProfile: nil) - } + timerChanheAccount?.invalidate() + timerChanheAccount = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(changeAccount), userInfo: nil, repeats: false) + } + } + + @objc func changeAccount() { + if let tableAccount = self.tableAccount { + self.appDelegate.changeAccount(tableAccount.account, userProfile: nil) } } From 43a52bc2171d8a1854a23a6b81078180fb88265c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 11:03:01 +0200 Subject: [PATCH 45/57] cleaning Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 22 +++++++++---------- .../NCCollectionViewCommon.swift | 6 ++--- .../NCAccountSettingsModel.swift} | 8 +++++-- .../NCAccountSettingsView.swift} | 8 +++---- iOSClient/More/NCMore.swift | 6 ----- 5 files changed, 24 insertions(+), 26 deletions(-) rename iOSClient/More/{Manage Account/NCManageAccountModel.swift => Account Settings/NCAccountSettingsModel.swift} (96%) rename iOSClient/More/{Manage Account/NCManageAccountView.swift => Account Settings/NCAccountSettingsView.swift} (98%) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 16945df41b..0d34fcdd55 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -743,8 +743,8 @@ F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */; }; F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */; }; F7AE00FA230E81EB007ACF8A /* NCBrowserWeb.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */; }; - F7AEEAA62C11DBAF00011412 /* NCManageAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AEEAA52C11DBAF00011412 /* NCManageAccountView.swift */; }; - F7AEEAA82C11DBFD00011412 /* NCManageAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AEEAA72C11DBFD00011412 /* NCManageAccountModel.swift */; }; + F7AEEAA62C11DBAF00011412 /* NCAccountSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AEEAA52C11DBAF00011412 /* NCAccountSettingsView.swift */; }; + F7AEEAA82C11DBFD00011412 /* NCAccountSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7AEEAA72C11DBFD00011412 /* NCAccountSettingsModel.swift */; }; F7B398422A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */; }; F7B398432A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */; }; F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B6B70327C4E7FA00A7F6EB /* NCScan+CollectionView.swift */; }; @@ -1533,8 +1533,8 @@ F7AE00F4230D5F9E007ACF8A /* NCLoginWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCLoginWeb.swift; sourceTree = ""; }; F7AE00F7230E81CB007ACF8A /* NCBrowserWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCBrowserWeb.swift; sourceTree = ""; }; F7AE00F9230E81EB007ACF8A /* NCBrowserWeb.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCBrowserWeb.storyboard; sourceTree = ""; }; - F7AEEAA52C11DBAF00011412 /* NCManageAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCManageAccountView.swift; sourceTree = ""; }; - F7AEEAA72C11DBFD00011412 /* NCManageAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCManageAccountModel.swift; sourceTree = ""; }; + F7AEEAA52C11DBAF00011412 /* NCAccountSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountSettingsView.swift; sourceTree = ""; }; + F7AEEAA72C11DBFD00011412 /* NCAccountSettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAccountSettingsModel.swift; sourceTree = ""; }; F7AF7632246BEDFE00B86E3C /* TOPasscodeViewController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TOPasscodeViewController.framework; path = Carthage/Build/iOS/TOPasscodeViewController.framework; sourceTree = ""; }; F7B1076C25D3CF2800E72DE2 /* BackgroundTasks.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BackgroundTasks.framework; path = System/Library/Frameworks/BackgroundTasks.framework; sourceTree = SDKROOT; }; F7B1A7761EBB3C8000BFB6D1 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; @@ -2620,13 +2620,13 @@ path = BrowserWeb; sourceTree = ""; }; - F7AEEAA92C11DC0600011412 /* Manage Account */ = { + F7AEEAA92C11DC0600011412 /* Account Settings */ = { isa = PBXGroup; children = ( - F7AEEAA52C11DBAF00011412 /* NCManageAccountView.swift */, - F7AEEAA72C11DBFD00011412 /* NCManageAccountModel.swift */, + F7AEEAA52C11DBAF00011412 /* NCAccountSettingsView.swift */, + F7AEEAA72C11DBFD00011412 /* NCAccountSettingsModel.swift */, ); - path = "Manage Account"; + path = "Account Settings"; sourceTree = ""; }; F7BAAD951ED5A63D00B7EAD4 /* Data */ = { @@ -2787,7 +2787,7 @@ F7CB68942541670D0050EC94 /* More */ = { isa = PBXGroup; children = ( - F7AEEAA92C11DC0600011412 /* Manage Account */, + F7AEEAA92C11DC0600011412 /* Account Settings */, F3BB46502A39EC2D00461F6E /* Cells */, F7CB68992541676B0050EC94 /* NCMore.storyboard */, F73F537E1E929C8500F8678D /* NCMore.swift */, @@ -4326,7 +4326,7 @@ F769CA192966EA3C00039397 /* ComponentView.swift in Sources */, F7C9B91D2B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */, AF93474C27E34120002537EE /* NCUtility+Image.swift in Sources */, - F7AEEAA62C11DBAF00011412 /* NCManageAccountView.swift in Sources */, + F7AEEAA62C11DBAF00011412 /* NCAccountSettingsView.swift in Sources */, F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */, AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */, F7C30DFD291BD0B80017149B /* NCNetworkingE2EEDelete.swift in Sources */, @@ -4376,7 +4376,7 @@ D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */, F745B253222D88AE00346520 /* NCLoginQRCode.swift in Sources */, F769454822E9F20D000A798A /* NCShareNetworking.swift in Sources */, - F7AEEAA82C11DBFD00011412 /* NCManageAccountModel.swift in Sources */, + F7AEEAA82C11DBFD00011412 /* NCAccountSettingsModel.swift in Sources */, F749B64A297B0CBB00087535 /* NCManageDatabase+Share.swift in Sources */, F7C9555521F0C5470024296E /* NCActivity.swift in Sources */, F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */, diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 7cd109f437..8a59c1532e 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -631,9 +631,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "person.crop.circle", colors: [NCBrandColor.shared.iconImageColor])) { _ in - let manageAccountView = NCManageAccountView(model: NCManageAccountModel(controller: self.tabBarController as? NCMainTabBarController)) - let manageAccountController = UIHostingController(rootView: manageAccountView) - self.present(manageAccountController, animated: true, completion: nil) + let accountSettingsView = NCAccountSettingsView(model: NCAccountSettingsModel(controller: self.tabBarController as? NCMainTabBarController)) + let accountSettingsController = UIHostingController(rootView: accountSettingsView) + self.present(accountSettingsController, animated: true, completion: nil) } let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: [addAccountAction, settingsAccountAction]) diff --git a/iOSClient/More/Manage Account/NCManageAccountModel.swift b/iOSClient/More/Account Settings/NCAccountSettingsModel.swift similarity index 96% rename from iOSClient/More/Manage Account/NCManageAccountModel.swift rename to iOSClient/More/Account Settings/NCAccountSettingsModel.swift index e5c275d541..eff0b4b40f 100644 --- a/iOSClient/More/Manage Account/NCManageAccountModel.swift +++ b/iOSClient/More/Account Settings/NCAccountSettingsModel.swift @@ -1,5 +1,5 @@ // -// NCManageAccountModel.swift +// NCAccountSettingsModel.swift // Nextcloud // // Created by Marino Faggiana on 06/06/24. @@ -24,8 +24,12 @@ import Foundation import UIKit +protocol NCAccountSettingsModelDelegate: AnyObject { + func accountSettingsDismiss() +} + /// A model that allows the user to configure the account -class NCManageAccountModel: ObservableObject, ViewOnAppearHandling { +class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { /// AppDelegate let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! /// Root View Controller diff --git a/iOSClient/More/Manage Account/NCManageAccountView.swift b/iOSClient/More/Account Settings/NCAccountSettingsView.swift similarity index 98% rename from iOSClient/More/Manage Account/NCManageAccountView.swift rename to iOSClient/More/Account Settings/NCAccountSettingsView.swift index 5e1335dab6..d92feafb04 100644 --- a/iOSClient/More/Manage Account/NCManageAccountView.swift +++ b/iOSClient/More/Account Settings/NCAccountSettingsView.swift @@ -1,5 +1,5 @@ // -// NCManageAccountView.swift +// NCAccountSettingsView.swift // Nextcloud // // Created by Marino Faggiana on 06/06/24. @@ -23,8 +23,8 @@ import SwiftUI -struct NCManageAccountView: View { - @ObservedObject var model: NCManageAccountModel +struct NCAccountSettingsView: View { + @ObservedObject var model: NCAccountSettingsModel @State private var showUserStatus = false @State private var showServerCertificate = false @@ -257,5 +257,5 @@ struct NCManageAccountView: View { } #Preview { - NCManageAccountView(model: NCManageAccountModel(controller: nil)) + NCAccountSettingsView(model: NCAccountSettingsModel(controller: nil)) } diff --git a/iOSClient/More/NCMore.swift b/iOSClient/More/NCMore.swift index 730b2398e9..f7501a0abf 100644 --- a/iOSClient/More/NCMore.swift +++ b/iOSClient/More/NCMore.swift @@ -287,12 +287,6 @@ class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { } } - @objc func tapImageLogoManageAccount() { - let manageAccountView = NCManageAccountView(model: NCManageAccountModel(controller: tabBarController as? NCMainTabBarController)) - let manageAccountController = UIHostingController(rootView: manageAccountView) - navigationController?.pushViewController(manageAccountController, animated: true) - } - // MARK: - func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { From 8bbadec111ad7f1034e70d83c98e2992c95dedc5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 11:51:49 +0200 Subject: [PATCH 46/57] coding Signed-off-by: Marino Faggiana --- iOSClient/Files/NCFiles.swift | 13 ++++++++++++ .../NCCollectionViewCommon.swift | 8 +++++--- .../NCAccountSettingsModel.swift | 20 ++++++------------- .../NCAccountSettingsView.swift | 5 ++++- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index 70ff01d645..191beb7f64 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -290,4 +290,17 @@ class NCFiles: NCCollectionViewCommon { } } } + + // MARK: - NCAccountSettingsModelDelegate + + override func accountSettingsDidDismiss(tableAccount: tableAccount?) { + if NCManageDatabase.shared.getAllAccount().isEmpty { + appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) + } else if let account = tableAccount?.account, account != appDelegate.account { + appDelegate.changeAccount(account, userProfile: nil) + } else if isRoot { + titleCurrentFolder = getNavigationTitle() + navigationItem.title = titleCurrentFolder + } + } } diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 8a59c1532e..72f74053b1 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -28,7 +28,7 @@ import NextcloudKit import EasyTipView import JGProgressHUD -class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, NCSectionFooterDelegate, NCSectionHeaderEmptyDataDelegate, UIAdaptivePresentationControllerDelegate, UIContextMenuInteractionDelegate { +class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, NCSectionFooterDelegate, NCSectionHeaderEmptyDataDelegate, NCAccountSettingsModelDelegate, UIAdaptivePresentationControllerDelegate, UIContextMenuInteractionDelegate { @IBOutlet weak var collectionView: UICollectionView! @@ -631,7 +631,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "person.crop.circle", colors: [NCBrandColor.shared.iconImageColor])) { _ in - let accountSettingsView = NCAccountSettingsView(model: NCAccountSettingsModel(controller: self.tabBarController as? NCMainTabBarController)) + let accountSettingsModel = NCAccountSettingsModel(controller: self.tabBarController as? NCMainTabBarController, delegate: self) + let accountSettingsView = NCAccountSettingsView(model: accountSettingsModel) let accountSettingsController = UIHostingController(rootView: accountSettingsView) self.present(accountSettingsController, animated: true, completion: nil) } @@ -778,7 +779,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } func getNavigationTitle() -> String { - let activeAccount = NCManageDatabase.shared.getActiveAccount() guard let userAlias = activeAccount?.alias, !userAlias.isEmpty else { return NCBrandOptions.shared.brand @@ -786,6 +786,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS return userAlias } + func accountSettingsDidDismiss(tableAccount: tableAccount?) { } + // MARK: - SEARCH func searchController(enabled: Bool) { diff --git a/iOSClient/More/Account Settings/NCAccountSettingsModel.swift b/iOSClient/More/Account Settings/NCAccountSettingsModel.swift index eff0b4b40f..c7a857b86c 100644 --- a/iOSClient/More/Account Settings/NCAccountSettingsModel.swift +++ b/iOSClient/More/Account Settings/NCAccountSettingsModel.swift @@ -24,8 +24,9 @@ import Foundation import UIKit +/// Protocol for know when the Account Settings has dimissed protocol NCAccountSettingsModelDelegate: AnyObject { - func accountSettingsDismiss() + func accountSettingsDidDismiss(tableAccount: tableAccount?) } /// A model that allows the user to configure the account @@ -36,8 +37,8 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { var controller: NCMainTabBarController? /// All account var accounts: [tableAccount] = [] - /// Timer change account - var timerChanheAccount: Timer? + /// Delegate + weak var delegate: NCAccountSettingsModelDelegate? /// Account now active @Published var tableAccount: tableAccount? /// Index @@ -50,8 +51,9 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { @Published var dismissView = false /// Initialization code to set up the ViewModel with the active account - init(controller: NCMainTabBarController?) { + init(controller: NCMainTabBarController?, delegate: NCAccountSettingsModelDelegate?) { self.controller = controller + self.delegate = delegate if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { NCManageDatabase.shared.previewCreateDB() } @@ -117,15 +119,6 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { self.tableAccount = tableAccount self.alias = tableAccount.alias - /// Change active account - timerChanheAccount?.invalidate() - timerChanheAccount = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(changeAccount), userInfo: nil, repeats: false) - } - } - - @objc func changeAccount() { - if let tableAccount = self.tableAccount { - self.appDelegate.changeAccount(tableAccount.account, userProfile: nil) } } @@ -137,7 +130,6 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { appDelegate.changeAccount(tableAccount.account, userProfile: nil) } else { dismissView = true - appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) } onViewAppear() } diff --git a/iOSClient/More/Account Settings/NCAccountSettingsView.swift b/iOSClient/More/Account Settings/NCAccountSettingsView.swift index d92feafb04..8f4066dd04 100644 --- a/iOSClient/More/Account Settings/NCAccountSettingsView.swift +++ b/iOSClient/More/Account Settings/NCAccountSettingsView.swift @@ -253,9 +253,12 @@ struct NCAccountSettingsView: View { presentationMode.wrappedValue.dismiss() } } + .onDisappear { + model.delegate?.accountSettingsDidDismiss(tableAccount: model.tableAccount) + } } } #Preview { - NCAccountSettingsView(model: NCAccountSettingsModel(controller: nil)) + NCAccountSettingsView(model: NCAccountSettingsModel(controller: nil, delegate: nil)) } From db502b727cffb222e30ad89817f930cc2bad6f79 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 15:03:54 +0200 Subject: [PATCH 47/57] fix Signed-off-by: Marino Faggiana --- .../NCCollectionViewCommon.swift | 2 +- .../NCAccountSettingsView.swift | 2 +- .../en.lproj/Localizable.strings | 2 +- .../it.lproj/Localizable.strings | Bin 137280 -> 137276 bytes 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 72f74053b1..56c3a9677e 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -630,7 +630,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS self.appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false) } - let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "person.crop.circle", colors: [NCBrandColor.shared.iconImageColor])) { _ in + let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "gear", colors: [NCBrandColor.shared.iconImageColor])) { _ in let accountSettingsModel = NCAccountSettingsModel(controller: self.tabBarController as? NCMainTabBarController, delegate: self) let accountSettingsView = NCAccountSettingsView(model: accountSettingsModel) let accountSettingsController = UIHostingController(rootView: accountSettingsView) diff --git a/iOSClient/More/Account Settings/NCAccountSettingsView.swift b/iOSClient/More/Account Settings/NCAccountSettingsView.swift index 8f4066dd04..56749ad16a 100644 --- a/iOSClient/More/Account Settings/NCAccountSettingsView.swift +++ b/iOSClient/More/Account Settings/NCAccountSettingsView.swift @@ -127,7 +127,7 @@ struct NCAccountSettingsView: View { /// Change alias VStack { HStack { - Text(NSLocalizedString("_alias_", comment: "")) + Text(NSLocalizedString("_alias_", comment: "") + ":") .font(.system(size: 17)) .fontWeight(.medium) Spacer() diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 0440fffbdb..3bedb557df 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -196,7 +196,7 @@ "_account_request_" = "Request account"; "_settings_account_request_" = "Request account at startup"; "_print_" = "Print"; -"_alias_" = "Alias :"; +"_alias_" = "Alias"; "_alias_placeholder_" = "Write the alias"; "_alias_footer_" = "Give your account names a descriptive name such as Home, Office, School …"; "_chunk_size_mb_" = "Chunk size in MB"; diff --git a/iOSClient/Supporting Files/it.lproj/Localizable.strings b/iOSClient/Supporting Files/it.lproj/Localizable.strings index 57c205706beda16aba6ef2ac480721db3bf4388a..212db46c89a61a3100d9dc7cb123fe93c74d0aed 100644 GIT binary patch delta 22 ecmX@Gfn(1Gjtyx+lTQVSH8%upZwO*Ma1;P~d Date: Thu, 20 Jun 2024 15:09:51 +0200 Subject: [PATCH 48/57] fix Signed-off-by: Marino Faggiana --- .../ar.lproj/Localizable.strings | Bin 127442 -> 127296 bytes .../de.lproj/Localizable.strings | Bin 140194 -> 140382 bytes .../fr.lproj/Localizable.strings | Bin 142194 -> 142862 bytes .../ga.lproj/Localizable.strings | Bin 128416 -> 139112 bytes .../gl.lproj/Localizable.strings | Bin 137280 -> 137280 bytes .../it.lproj/Localizable.strings | Bin 137276 -> 137346 bytes .../pt-BR.lproj/Localizable.strings | Bin 135148 -> 135404 bytes .../sr.lproj/Localizable.strings | Bin 132434 -> 132634 bytes .../sv.lproj/Localizable.strings | Bin 130634 -> 130626 bytes .../tr.lproj/Localizable.strings | Bin 133230 -> 133304 bytes .../zh_HK.lproj/Localizable.strings | Bin 96876 -> 95486 bytes 11 files changed, 0 insertions(+), 0 deletions(-) diff --git a/iOSClient/Supporting Files/ar.lproj/Localizable.strings b/iOSClient/Supporting Files/ar.lproj/Localizable.strings index d0e08d4a9d746a81e0d2dd252a2853e7e6515a29..22b88c65c873877c82a0286a3bb6f7acc3cfd5c1 100644 GIT binary patch delta 699 zcmYLHJ4?e*6uuce)lzW~5f_cE?X98qXI*aVy~N_GCPSSk1Ax5PaX9fZakEXc>lI* zEZzj+FbIwK`iV<5@<>vfOtFVtwiODf1lvT!g_ZbPRHrQbElR-S={)w=km=(M;I)wN z;DjD3J*uwcg(-aa)5tp}sRpA*hkaShb198lNjB|986DUn{EnW$2y(B*vK{1sUp;(ja{Zra|y%qoBS&#F>@s2hJACHt;Wmb#T%V|z!a4?07y9I?>c%X#3dRyp0rzms2 zIVL#U=^SGfl>uIsA&B&JbS=-%Yh28M_h3goE0{l%$3vEn2>&rQI+@~BBr_T$hgexp gug(@-aV^for8pNCI3umUJTdN6u|dO^iBV4e1H{&C4*&oF delta 1190 zcma)+%Zd|G6h%*sdg4SBnuy3n9EuOn59qNG!4?E@Qk|-F2h&v{l?QQB1HV8VTfRko8<1{%QxHw&I+q+Zc|nPpEI8)>`R-lo^m?mzOVteBTftc3y)fI)A+1kTqeEe z57~}9@ra-SvmCdab!91`R&L&=P3=U$zI=PvtB*)F;r2DwLkCj<Z8cl%8^gR8E-LZF}2dCcyu{ZX|g`POl|^VAB{#t zcayN&wD!rAI@~}-YzsB=*W7--b6^&bOX~)|u&E@@T@9hlop-ReyV3!~(KG+AdV19i zuNgymrk=b4RBpAZP-s*@@%btsm8c>(a&0;NyD;MIV>}dTmv^V^DbeJw)GC=j+3Fox z#aWG`hKe=))Shq>Rhhdgm4nh_sEJe^UDIsWkt_s9UD6AxGga2iW5n31mOA!sS75Ps zBLKZyY^*bP{i}co8J}QZ7Y|$&^}kv{tflA5%Q|p|b`Ln1Hx=7{A|$^)EknW!V_2sj blUs*vqo@TI@^xz2dU=(6zPNFnJiGrJ{cYw2 diff --git a/iOSClient/Supporting Files/de.lproj/Localizable.strings b/iOSClient/Supporting Files/de.lproj/Localizable.strings index 940666c053302baa937c07a7b03114016e18a0dd..e6450296fb8e197818079bada319ce5e97ecccab 100644 GIT binary patch delta 901 zcmZ`%J#W)c6unj%Qc4G!T9HMe4+c=hXO<2uG)O^0hz){}kdV_PjpfEEc0(n^K*i2- z2ag~M3oyV`F?xcDA3z~h5kCMJI%VLT=U9TFvY!2Xzt6en<)_l{bLsu%OkZR(^MSM_ zmVrdFA_<;#+&i!toIoPod+X`1`k|-IY`d8`Ul!}Pr3YsVP6qXn+(L3uU`Y#!Sg^`E%a1lDEgA~Kdoh-CA&tm0`S_8g*n)|wRkbZ^UZ{4{eMSC_t) zrdu}ENKMvcE&b4S%K9gsb!*7ZT@j%8wql~yk7Yf)^X$BDYjVzxjLG5xsumL+W`hZ40V_|G$ zqew=G8vJ9ujj_idHm9~{y{tw`j5Kj$HY@%=vXMKw+3<9@HFwq^i&P#2kiEuz)1$AP z@5)FQwD5 zQcM0>WiDAt%wXl@G1lofm4!mYRzL6^C}zFeI5w3tw~wxoR=-zHkq-(Ma+VXOjxSjV h#!k delta 1203 zcmZ{kv1%JZ5Qaxd3b!GcU~q9&s$eHYQlyGg8v-HVCe2BAvIX*;(4Aziy23ADaN*Km zNT1HQROP%x@(zB0fWLoME6G7Z+}-Z%%s>D9JEOn9w{GsYetnuLeN`FXeIssdz_P@kXTP0u!HgI*aMrqFMr6 zQ-_ewt5t4NErqVif2!NSFMRbnPeCtek64Oms%cIkQ(&#_Lk^HG?P!CNo0Ze0W)70F zs)1Fq3KF3&m0ax;F0Vqt5*2i&$XLSqwg{*DM5x1`mN{3l<=_}N0VuUPW|?kPMU|*g z(u9SMesAxv1QjN(N#&#zrLmH_%Q0GM8SKK*5Vg7OB$}Bn$!iA*;EQ2K*VtQOngan{ zQy8lgkNm%PqT-w8y638lKf^?mpsFQkgL%SN<1NOMd9%jBko@|u>3bv6yjKs;pS^mm UY;srkPd!xgpWXia*SUN12+_~!9{>OV diff --git a/iOSClient/Supporting Files/fr.lproj/Localizable.strings b/iOSClient/Supporting Files/fr.lproj/Localizable.strings index d6871e45134170543a32da65eecf62dfef97177e..a86ed00807f96386dfd68d1591aadb82f928dc4f 100644 GIT binary patch delta 1710 zcmbtUZA@Eb6n;->fpx5w+gsW~fiiGgC@>h47&j;Q5nNPo!5A|tvCs~h@HJYxusEGr z#Qj)+ah9DWnvE^SIkQDfC;U-jGB-b>3;yxX5KtC`B@jk5Dl^3MzU_4I*WBEj_uhLx zp7WgNoaG-=`zBI{4b?ck$%w1ZX5ec_bR4O!!09t)^t_>=b+0+rSAEk>b3k4GV zIs@)!sB#dD5T>_|gAFIISaIl5>O=FQLxhEg@1W=s9h6rO+1M~*rrTRU+c3{x)n7Up z122AYH6vE|(H#xPiVE=cV`(Wt_UsnzSoXQCEFiWDzi8*XRrIKM9uZ)Fk7(k^e*V%T zO8D*NM8*)F?{i_n87B_cX5#X!hPR_u{Bz7g7w&-W2(wu?yZA*&L^#Z0c5M|wgm-L7 z3>AOKa^RO08Q55?CwYVq51!A$-^Mg=kiELtc71A}*vwzUiNCd?MwG<*$Lft#>V-@+ zT+?ZP1(>;FS#PKC;}bJ^wlLQe;3kM_*PMcphmU{dimhIEC((C1!MsuO5@oI;%*n}tEZp|JP7`;*NlP{0#OZG> zG)thzKK!OdH&t<_wGY67#mZ3vRY4JiDB~93W z*+G4`ppd@41ck5_%ZgpFj&X+^f;#q%6Dw(!5&j3YIrb7I8Y!Ho6|0inZu+?sTjACgKoR!OWYN`+S;s>Q zpl7Lq6grtCt~8!Oc3y+cxNEyANsh!?jB2|j9Ge+aJKwU6GF$=+?VAESHTH1M=_G@* zTIP{uNcl@HLh2+XD`$D#WOEqVM?XIs`5EC$rVNQ7wcUek?|&V7Q6ZG=h$;*rPQhkt z8-#HAgkMEHtX<1)cuhXh@^VI+nVez6a6Cd9LEnQlWC6@H=fX z8LDa81!*R~Xl6uyli@i&cJVRB#|=*@LnyaXL$YBv?s>^VOZy=; oTlTd_F?OGXu-fzyUQKPIpC%h>3sU4f?-f805dk{UjP6A delta 2475 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 delta 25 hcmX@Gf#bjij)pCak3KUOF(ghtYbd$>-)BZA6#$(#3yJ^$ diff --git a/iOSClient/Supporting Files/it.lproj/Localizable.strings b/iOSClient/Supporting Files/it.lproj/Localizable.strings index 212db46c89a61a3100d9dc7cb123fe93c74d0aed..88385023956637499f249da0e7777d19f8e92f3d 100644 GIT binary patch delta 753 zcmZuvziU%b6h60DNQH*BX^@IBiKUd57~4s~K{7a~ph=fHIP^7rjSpV)9?5HlQYiF4 zkULx~jzUG3NQW+>e?yiggV5q+aS#NN3`M{1zW$)#aDSY0&-b10+;cv)6WbpX?ahU~ zuM1`0g!k3Rq$j@Qusmsri_@0?_KLmJA4qNQ;g`Fw%)5$uyx%UXgE#YKyfzS369=aw zb%}s)z?;KKzAA7H>xu9d=={Bux#g=dJ5+Megs!=8sh37OPLhy$SNXPRbGm#|912G>1-m~ zwEiRbJ>aOEx>tZ;t)71Uc1DjMjV(594J|}5C3zz34M-r)vHUq$ta%-~e=g1yimq61 z{gj#I#YJU$c~vmCt7>}K1r?K$%+sA`Y18VfWIBYqj|bmo#-HKtqTKALD|f6#RqRV( zI#*QcTFnMh+$9!D!;3Gcy|(W@na}*~A59LC6Ql z9_Esd*bp$6Aby2GyqF(Q;$8H;>Ya6?F^B1y?y7qA>Q(i;-J3rg&yQcXs`9S6Hu`vf zp&B2WOILE~$QB+eiQEvk|Du&8)yjJ_7g%{LnQW>hhEFWX{;v=B-Zfu|ldkj-5X0D$ z9B)FzvWOqsIq2=)x#R-+PRV+=hlazSWoAG0<7*Vo`1CR z`pxhL$k{qLoU@?QN_2D#rj3EU3o0r4>gGK2>iD|}?obRW|4ip#S~E`Eq)Y$kF*-hK z4B3}Ri*xuY(F>v%$m%DE**FJY{{ks9R81QrYtH9Ybo;yx4*{~N{Uc=Ei#pw`Y`)w6 z0_94nDJzKXYK!}z9)q?oCq~Jf3HG@j_*qGaOPNC%#OZh6sxec7B+j%fA6$X!QaB diff --git a/iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings b/iOSClient/Supporting Files/pt-BR.lproj/Localizable.strings index 43fc3524603b78c58aed32c1a9d47ed688adb477..79328bc0671759ed05b94effbc8aaa44003e598a 100644 GIT binary patch delta 1270 zcmb_cOGs2<6#oBobW#~johhA!d$R{Lm;1R?0?m|d8MI1j>V5x8nq z9q0!aO^J&P1i{GA2!v=8nTBASP|1jVENa`rzH{$X1}$T_=br!m=kcBIoHH94`^F>t zcw>O(#&Yw+qF;OxacT)P+g8LiVJQ8&bWc1DJW12|Nk>gwB!njVL`ZatxJZf~^PGYV zi7>wKZJ}1E_2DK$--2#E0Zrpm)|Nez!Vqbk`|(6org%q%>`@&v(k)}E_M_A%TvHF^ zJ)>l2Ol+El5qdXOO&_KM>S3uYsSm?XL&Uh~#XDr;>CGb0M7xNY=%Tnwh!k|rnSixU zCzdKEk}nRra{MBx{9Do~!=!uM)OjabRbkb_jM+J`yXfWfY zruRkka-nX*w{R+540cc(*9lwEqw2S0l{#}sx+pg0P;)~vSB;#Pk^9rqLBUJq__}AZ zu0>uL;$G_gz@?e^Sz}xVGHYhEF32d&1k0%XauKcGsFYs%vE;7O#8udK!7_p;37tJS zPAE$l9e=j>7hO7&avE3vseG-*XLgS}=m&zYsGlo0kbqM#+i{??I7}<)mu2ewtSl$r zVY|orx&j;S2+!z%>CLmk6T{QmZPmnGY2&HXFkYMHtu?#Wv~vHs?jGRa>FLMMnr{t= zn9CGo1Ug%ATqdGT%}>f&bWx+G5jzboR_?MAv&^ms>CH|jhv1TUgslJ|nCge!Hcokj zibtK*z0f%6_9Xuro(}E}*UKq1Q7eu@MiHJdCQ(PiWR2_Ros5~avb1K3=B%l!R60d#3b8~^|S delta 1974 zcmcIlJ8KkC82v89Bx+$WtVs%Ch?WwKVj-k3i!n+R9}#SVFuOaOjM?4U>?>I;rnVEO z7_bQ`1Q8Tvg@D@m14Oa5v)UD6VQ1kv_s-33$i_~Vxp(K@?{U8KJ*KlY+}Rv{Gm}2H zC^d1VBsr`V$wl+&`J=9Eh%ZH{OEGe%##*n_FB{Rwui>x&p{6)cSrHF=8ShzH#k!35 zDo*NHJs5K&vq#c}Y#FD%~bWl^YTOiK8vxP72ZQ4>zNoPlJ~n_=N@SE30?onMjx5+ky8wV#z|H zieDaYMAB?M{y2LgOv5t+U53*DSLDl)*(9jDP|E8-svu@bCUNJ(hyy7PvOdIJ+us+| z%(M8(mKq2RnarW7CkvRq0(iDIm^wyifDC;?pifZagG+B0a zW!f5JebFmR#&$pZnloX4F&$8$q2*MYAkV!edr%A5A+om#%oyrTXA#y*C?6XNVX|n7 z2$R{Y$wk}5_jmhZFOvr|$J*h5<*23M3U*aadSVC_&b< z5_&S>uxB!G&XHz~a~|tCjp4|;;&Ts?aAr}4X) zH4^`6tE)pk?5;>Hp6jT&p({|U$ZEWHO^wDcI_iA1^XN#biMk*|MHuJ5CSZHpKRRmY F^j}k&lUV=& diff --git a/iOSClient/Supporting Files/sr.lproj/Localizable.strings b/iOSClient/Supporting Files/sr.lproj/Localizable.strings index b00b153bf40fbea4155418f7cd1a188bb3627cf5..4948bbf308b2aa6d3871f28f091ce5f9ecc05301 100644 GIT binary patch delta 1434 zcma)6O-NKx7=2f7rjwZYGfhq7yip`f8{ddJ(;Mgc-ppvWiLxL|7v-WLq=snGF55QXnN0;Oe;A)&S~X=_c|qJp4OC@3Ou)1pOmzIzq3T*UD1ynEmGcg}ad`|5J>?JLD& zUtNEMr@4h+inn5Qv8H%}i=S>*-ul8Sgc%Kt4|?CuUw`Zi#d(JJ@iuN6ov^j>mR38P zJG@V_E>`4h%h>5nGOI-H^b0LX6y~l%r3XU*>0+Z=6qDWg@qQivvk6 z%u~fXDRYZ*%kWOTd&puM89Y=~8@`c+E$7c7)6AqThKGD2F7-ITeVEpjZk81I8kVj&0Cjj)#G&GbNvj#pbIBn;aESY8Dkj~i&qc|#Pg%jls znNcLzAuc@%3Ttk_3EF!H>EKpDSS;cMhqp;qqfc;JI zp7jYPdh1k(6~f}ngb}f8DQnb}X_o(oxO$S&-z|+Aq#Ana0N*syA`-6_)=XJ2!8;V| z)WnnmmcfaVqWI7dZq|M301f>Lq6YtG-&RItrS7n-%`^W#nwmA^ft{av9ZiX0^PN4Uz4Y9~}(*u@MB zsXDMr!He!6N=^PWZ!I|YRO7wnG9Any+Ax3*bUl#FVpu7Wu3e8B5!Z`z8_#NItCsC4 zsJ^ZUb6SzA#ZH)8(bb^%-W!l7hgsQ1M^_}T6&6&B=;Zbi(@>Wjrtsht3szCBAq3Vu z)9vJN`RpU>#x+?G=hDBxveLC#sXX1peDcBqdns)r zx~cy_Az;;wKcJi94-i^+BHEQp@tk|-HBD{YNywX-_wL8J_nv#-+RLHOFNWTJyK;0v z8WKoVma*2czRKlCujBoRl%yg}{FB|-JKnA4zBhtAHe;zt83HZwq54n?c-HV8$|I~R z_>QsD#9DwkUzYkL1IX5}TaqGH)2Agmho#Q;-LY|g5fGn`@h_>rrR3**FEc{3b!>C( z{(iUSom{|s1Hy9>!MzXRf}WS9v-N&1=eCP#hiF3;F^}}J2yZ^{HgOU{ImWMuuQGlu zIn{adaiaU|!>`PdMajz5&hz!LwlBFfkXukFD)<=5pag?s3YKwF#XHk5iSL`KTSnmP zS%BmaEj1WHNrBLY#njN96<9O7QJS!NTUK#ILua8@#d8(U8URovQuh%+`A9@bf!H3k z7!`FW$?DKOp*HXjb!ARgwX)2MtFcwC3=5$oGn?LU#szAyQ@KuiJ=5LY8i_B=f)&E}^PXO$pb=24fmu`Mi+kq{SgMnqufTb!>>a>({R?|Q!=*YwxGl2otJ=&-{ zw96po_0mS(_A_x1v)y#)=eA9h{ROK4N)>zvZluVGiZrNb*@@Hj=Dh)QA4u^w*}<8~ z=}EhFb;iMAM5A*u#2PFHf(S|A88ux9hqtbsPC;W}3%6l}vz7+v+Gdq=_jf>x=y}fD+7lDD8qw`0R=$IB%#CGv1rNJtkRu+RSE|+||*? z6xeZB1MPAEAJ(X$W(5<_rWGeN6WYRd6VFgn>+YXD8fyA^Ik;hR;BLXWjbTPh;`832 zdm~6Xa^!(#hBsjHdfPic+J7G=U$(vcF}oNF&^JoZMl!kM?f7@nc8P&D)|6G?jc+aW Lzj5)ax0C$?I>3dm diff --git a/iOSClient/Supporting Files/sv.lproj/Localizable.strings b/iOSClient/Supporting Files/sv.lproj/Localizable.strings index ba80a79661ebad851e3b89675f58f935679b86e1..43cfe17379b6cface76af40e7360afdc7b377cae 100644 GIT binary patch delta 505 zcmXw0Jxjw-6uplY8w-Naid2VI9f}`_i=$}7P23a|iWp3_rEMCMSgeES9}wggQV0Ko zHHw>pPKx5J4tB7s3W6>jJTI+;-22XXmvhg(@4gwjX@*WqXFO30t0rlbqcl1A4N8zr zMJga`KqY!d)WJzy@}o&+yRucMyPsELpfiojBCS(~k1{d-x()_RYVg5Czc=RP1@EVV z?qNkJT}9f&XHXV$4X&Lp@Jw2nl-L0O-zE<&S+@Z`4>pC{1Wsji$ia#Z3${0P(db#p zq0FM~woeW2OduI`6w0Zrws?vLA!2}$5;lzksW>~n8Cj=+k_#;*Hl`HOR3MXds*pxD zrOCjzfI2~I*i)!2bV}F_TE)NkAEXX!0o@EGu{(UJq*GBTWhe)xjoQR=6m;~Yl1^pP zJ)lbaxY%80KA}}ve{Hm8GJd-6^4UN|DUTGIVwa&{^0TY?nNByU=rVIcAsk<+9)pVp z?-EWD;8|EnR5C}UHg)~w<1Z&(k!~{oN{oWQW`NL;%m6c^vW}x(_|cX3*VGxps-9%X zgz}EkFG!0xx3Od=1vN)EFZP=3hMzb5Jo-G%Tbo|q8uIXi$I05~Q_`ByDXV7Syu5t3 zvhv@6YF@o-=axAOUI_X5&Y-t$&a%0xnt1o` w#Kr9^i-_DI>*_I}T*NO&3DNt;K1P-hUk0);ZaF{$##vpa1{> diff --git a/iOSClient/Supporting Files/tr.lproj/Localizable.strings b/iOSClient/Supporting Files/tr.lproj/Localizable.strings index d5085e5e1035f1960dfa46a9c565949d3a833337..6fb4f6ef6945d29cc1fc3f7f4a70705615f97324 100644 GIT binary patch delta 606 zcmZvYL1+_E5Qb+ohfvd4n}*bbWV@}3rG%svDb-R}2pH%=^jgr>Y$dcwLy}k6(1S-$ z()yqS#ZyleJP0|&USfMxu(q@ZuVTH5C-Klq|M%)iWZBtyJKy~8pZT#IeYX;Q8}qoK zyS@DRJXOe{S@Nk#^W+PMoN6t4FO<$Ud-X`ZU*3G;o=F2$0nJfB4S)gFsAOB~r0`Yr z1aA?914f~$Kq;ISDUh!fzC55H;Lrkomw^>2$7#-S#kM>)(&7zsqSa}yvFyC&Sjs5* z6k60lJc7l5Lj8F*t(P|MSZM5DXo2cz@ey-817i)elws9O7vNl^QtNngFO~G*(de7G zFt{yY{QI1^>OjG;CEHU*K0_|R8nPlD6H$|g2b|K=2UqmVpKkXEfDq%&;p$VJ)oqR> z{&>M^5U_x_jMj$J#Yn$x53A`MAnKoTsN4F89dRC63AX2adNp1wON;U*-Db%Qv2o+gsdq?g)Ev=_YlN zE9oR()At7YB=ZXbtJ%0bKjf_J_HyKGNJ`!xa{j^tIIRC&sBstS7tD6 zyPLyM3zVZ2TpMJNL(630&Ou+IBxC}50Tvh1q8MI_e~=Q`9IQ6QA^mt}l9czDY|0?g zfu6$g86<4XB=u!RH0Zb`>Z_SOPpd48SEVDNUJ`+32cQYcq6otaW_L;*oJ|h>TH{E} zvbSZ?nUxi#!7*{Y8~U?$UH2-YO%ZR8{s4JD7@3xEs9b-bJb`cFsI8u6J##3!)XPYf kGLnI^JSFuPFzwUmmCG*RYw)ryw8EML9SxPzZ(_Xj8;)t8+yDRo diff --git a/iOSClient/Supporting Files/zh_HK.lproj/Localizable.strings b/iOSClient/Supporting Files/zh_HK.lproj/Localizable.strings index 65e81e151588eb376d778be3f4370558823cf553..d0acc6bb1db3b98bdb9f964ab40282a760f33579 100644 GIT binary patch delta 733 zcmaF!h4tS{)(v4sERtE%@+PMlxv(&#t4B^=Fi&jrIio$HlLaoYn4C=1DCMr=kFWRF zC~YYVkNoDx@xLi@PI_~+V8Ex?&gi=xYJM8wR{p%{8DU(0?}If;Isb1q>-1xs{J@We zgQ1pXa!QO;?c{k~K0*>*ER&~Xd1QQwWz9>OCXh5gXtP%L3H}5ggP!;g!7z)=gEpk{ z8m#WPloVRaWN^AmBV0y7w`*3ktb(pze5gigb2QI?wGj89vQn51jc|~Dr!@8$#lovO zi?Vd`41i{&7rGaTB~9zJo-w&^mc(R%Sv;E)=3EL90=a-U#IQ1>MzE5Hq^}7n%{B~8`^@mxJoNW>3J;A4g=Rarq(fGzrkVDQiYC!s&(s=$uoL3rv?7YHw_aY{P7=}Cs5KhS!i{$x#y6Z)K4u2vK zIGDYYt_C^PCS~*dhgpR%2I9w_5Qrh@)`F}&-ZL|GbAUzv`{2I~%<0ViNkCK8{6zeu zCRoIs&sJbCWH4Y*U|&diSE95Pb$n@bUaF54bkgnE@?j zzo#YS{GN7xBEscQn;JXAXL)wR9I2nC76J;h@8O^@TaoZS_^BT#1@RadP3W7(YoP0Q zA$hicOWD)Zo-R;?Fc~N@STk@jC^5t{q%dSoe;dbW4oZI0jp7+ySi~X^bWZOAv3}(i qHBD|%6Pf-dp3#8iBak;;C4td}2W0l|n!?%@Gi)-pcO)=AkpuwWM;wm; delta 1952 zcmcIlO=uHA6rM#ZrAV#X9~wL?MFc@=EqLjvg%m2pR&47}?PZ&6VlYiYHfhXhJxW0; zjIip-lLzro$UzVO-b6fk^5(^hAhw8S@%!fOv`tNpQZn0_dGoz*-uvF0Ki|84{O;Pk zGTt|@s>)MEmBCoSsF%i*y%#aLt@3JB)$r4k_Xe9U$6qamNvs8`tP0p~C>KX>Dj(l6 z=4o{cV-E8GD>aNh;9RxRV(G!QjMco#VwCelqH`kUK_xJh3h*KbLJu}Ny>T>39(4K+ z6TG6<%-DQ>ch*VF6}hN5oLN;)>dlC}a6(g<1fDdltz*sBWh*iwIeG@#!+JlWiQ z{CQzw8Y=RjAS#Bg$|hE%C8SG61vV!|W9zF4Sn3B`g%i_YN@l#vexvBg1t+1eZ5`9w zKS%WacRkIO?Jv2x1zb(y%S?)<>?P>E1P&Ik26$dNk5%TXXoMr2;xp0flrwamakfcf zav5_g5ei63!8(o;tKZHHcMu8%F&D=c=>#@q@gK4|h~&0Or@2+<{LPJ;Vqif`0U%@U zE`m1ws1%_D zZ#HI5RusT0$WU;cNr_(Vp!$wF51BFcO?FV?R*W;Y4Urg~QyWre0T`4J1n%*qy+Zp6 zmff>B(Xo<4fUw^ZfUc!eS$F@IwI4T3QaY!`FiH?=CJ2Ec#Z#;hJ_x%Nv9}e_f>BSa z&{xAQ>tO}Xs|G}BfyFMpcUMVLn9{MCCaIZyN&$|29*E2K+pa{@CMuOlxMBUWKQo{W zEZ6X5iy~urgLY(S!q2C{wh~u+8^;q&FRdx{HFJ`sO-V%0t~<%z);BNug|&X^|MGg! z7f(bJOHQ&U1+*N5R8{)Useb+R^jLQipcOoh(MK4#i*daKpv#BOM-uq#R554VUL Date: Thu, 20 Jun 2024 15:44:03 +0200 Subject: [PATCH 49/57] divide Signed-off-by: Marino Faggiana --- .../NCAccountSettingsView.swift | 161 +++++++++--------- 1 file changed, 85 insertions(+), 76 deletions(-) diff --git a/iOSClient/More/Account Settings/NCAccountSettingsView.swift b/iOSClient/More/Account Settings/NCAccountSettingsView.swift index 56749ad16a..49259c432a 100644 --- a/iOSClient/More/Account Settings/NCAccountSettingsView.swift +++ b/iOSClient/More/Account Settings/NCAccountSettingsView.swift @@ -39,82 +39,7 @@ struct NCAccountSettingsView: View { Section(content: { TabView(selection: $model.indexActiveAccount) { ForEach(0.. Date: Thu, 20 Jun 2024 16:58:18 +0200 Subject: [PATCH 50/57] move code Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 2 +- .../{More => }/Account Settings/NCAccountSettingsModel.swift | 0 .../{More => }/Account Settings/NCAccountSettingsView.swift | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename iOSClient/{More => }/Account Settings/NCAccountSettingsModel.swift (100%) rename iOSClient/{More => }/Account Settings/NCAccountSettingsView.swift (100%) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 0d34fcdd55..8daa7116d8 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -2787,7 +2787,6 @@ F7CB68942541670D0050EC94 /* More */ = { isa = PBXGroup; children = ( - F7AEEAA92C11DC0600011412 /* Account Settings */, F3BB46502A39EC2D00461F6E /* Cells */, F7CB68992541676B0050EC94 /* NCMore.storyboard */, F73F537E1E929C8500F8678D /* NCMore.swift */, @@ -2911,6 +2910,7 @@ F769CA1B2966EF4F00039397 /* GUI */, F70211F31BAC56E9003FC03E /* Main */, F7CA213725F1372B00826ABB /* Account Request */, + F7AEEAA92C11DC0600011412 /* Account Settings */, F7A321621E9E37960069AD1B /* Activity */, F76687042B7D067400779E3F /* AudioRecorder */, F3A0478E2BD2668800658E7B /* Assistant */, diff --git a/iOSClient/More/Account Settings/NCAccountSettingsModel.swift b/iOSClient/Account Settings/NCAccountSettingsModel.swift similarity index 100% rename from iOSClient/More/Account Settings/NCAccountSettingsModel.swift rename to iOSClient/Account Settings/NCAccountSettingsModel.swift diff --git a/iOSClient/More/Account Settings/NCAccountSettingsView.swift b/iOSClient/Account Settings/NCAccountSettingsView.swift similarity index 100% rename from iOSClient/More/Account Settings/NCAccountSettingsView.swift rename to iOSClient/Account Settings/NCAccountSettingsView.swift From b78fefa3c6ed9ed400dcbe6c262721de5d902dfd Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 17:34:22 +0200 Subject: [PATCH 51/57] add animation Signed-off-by: Marino Faggiana --- iOSClient/Account Settings/NCAccountSettingsView.swift | 3 +++ iOSClient/Data/NCManageDatabase.swift | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iOSClient/Account Settings/NCAccountSettingsView.swift b/iOSClient/Account Settings/NCAccountSettingsView.swift index 49259c432a..e4e61f12be 100644 --- a/iOSClient/Account Settings/NCAccountSettingsView.swift +++ b/iOSClient/Account Settings/NCAccountSettingsView.swift @@ -26,6 +26,7 @@ import SwiftUI struct NCAccountSettingsView: View { @ObservedObject var model: NCAccountSettingsModel + @State private var isExpanded: Bool = false @State private var showUserStatus = false @State private var showServerCertificate = false @State private var showPushCertificate = false @@ -45,8 +46,10 @@ struct NCAccountSettingsView: View { .font(.system(size: 14)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .frame(height: model.getTableViewHeight()) + .animation(.easeIn(duration: 0.4), value: isExpanded) .onChange(of: model.indexActiveAccount) { index in model.setAccount(account: model.accounts[index].account) + isExpanded.toggle() } /// /// Change alias diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift index daf5df2fbb..cd01e706f3 100644 --- a/iOSClient/Data/NCManageDatabase.swift +++ b/iOSClient/Data/NCManageDatabase.swift @@ -303,8 +303,6 @@ class NCManageDatabase: NSObject { NCManageDatabase.shared.setAccountUserProfile(account: account, userProfile: userProfile) let userProfile2 = NKUserProfile() userProfile2.displayName = "Mario Rossi" - userProfile2.phone = "+49 (711) 252 428 - 90" - userProfile2.address = "Hirschstrasse 26, 70192 Stuttgart, Germany" userProfile2.email = "cloudtest@nextcloud.com" NCManageDatabase.shared.setAccountUserProfile(account: account2, userProfile: userProfile2) } From b557ef144e37f8a1c245aeca96a9e616edb8151c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 18:15:57 +0200 Subject: [PATCH 52/57] + animation Signed-off-by: Marino Faggiana --- iOSClient/Account Settings/NCAccountSettingsView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOSClient/Account Settings/NCAccountSettingsView.swift b/iOSClient/Account Settings/NCAccountSettingsView.swift index e4e61f12be..cf6e8940e5 100644 --- a/iOSClient/Account Settings/NCAccountSettingsView.swift +++ b/iOSClient/Account Settings/NCAccountSettingsView.swift @@ -46,7 +46,7 @@ struct NCAccountSettingsView: View { .font(.system(size: 14)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .frame(height: model.getTableViewHeight()) - .animation(.easeIn(duration: 0.4), value: isExpanded) + .animation(.easeIn, value: isExpanded) .onChange(of: model.indexActiveAccount) { index in model.setAccount(account: model.accounts[index].account) isExpanded.toggle() From bdf03eb0075d951b60c89d00bfb588e22b6ee457 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 20 Jun 2024 18:20:36 +0200 Subject: [PATCH 53/57] cleaning Signed-off-by: Marino Faggiana --- iOSClient/Account Settings/NCAccountSettingsView.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iOSClient/Account Settings/NCAccountSettingsView.swift b/iOSClient/Account Settings/NCAccountSettingsView.swift index cf6e8940e5..765d11f626 100644 --- a/iOSClient/Account Settings/NCAccountSettingsView.swift +++ b/iOSClient/Account Settings/NCAccountSettingsView.swift @@ -46,10 +46,9 @@ struct NCAccountSettingsView: View { .font(.system(size: 14)) .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) .frame(height: model.getTableViewHeight()) - .animation(.easeIn, value: isExpanded) + .animation(.easeIn, value: model.getTableViewHeight()) .onChange(of: model.indexActiveAccount) { index in model.setAccount(account: model.accounts[index].account) - isExpanded.toggle() } /// /// Change alias From ad3ea5f352043a81fdd4c90b7f39bd26291c86b5 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 21 Jun 2024 10:04:01 +0200 Subject: [PATCH 54/57] Advanced techniques Signed-off-by: Marino Faggiana --- .../NCAccountSettingsModel.swift | 77 +++++++++++++---- .../NCAccountSettingsView.swift | 82 ++++++++++--------- iOSClient/Data/NCManageDatabase+Account.swift | 1 - 3 files changed, 103 insertions(+), 57 deletions(-) diff --git a/iOSClient/Account Settings/NCAccountSettingsModel.swift b/iOSClient/Account Settings/NCAccountSettingsModel.swift index c7a857b86c..fe6733c95a 100644 --- a/iOSClient/Account Settings/NCAccountSettingsModel.swift +++ b/iOSClient/Account Settings/NCAccountSettingsModel.swift @@ -23,6 +23,7 @@ import Foundation import UIKit +import RealmSwift /// Protocol for know when the Account Settings has dimissed protocol NCAccountSettingsModelDelegate: AnyObject { @@ -39,8 +40,10 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { var accounts: [tableAccount] = [] /// Delegate weak var delegate: NCAccountSettingsModelDelegate? + /// Timer change user + var timerChangeAccount: Timer? /// Account now active - @Published var tableAccount: tableAccount? + @Published var activeAccount: tableAccount? /// Index @Published var indexActiveAccount: Int = 0 /// Current alias @@ -49,6 +52,8 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { @Published var accountRequest: Bool = false /// Set true for dismiss the view @Published var dismissView = false + /// + private var notificationToken: NotificationToken? /// Initialization code to set up the ViewModel with the active account init(controller: NCMainTabBarController?, delegate: NCAccountSettingsModelDelegate?) { @@ -58,6 +63,36 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { NCManageDatabase.shared.previewCreateDB() } onViewAppear() + observeTableAccount() + } + + deinit { + timerChangeAccount?.invalidate() + timerChangeAccount = nil + notificationToken?.invalidate() + notificationToken = nil + } + + /// Reload the view when change the tableAccount + func observeTableAccount() { + do { + let realm = try Realm() + let results = realm.objects(tableAccount.self) + notificationToken = results.observe { [weak self] (changes: RealmCollectionChange) in + switch changes { + case .initial: + break + case .update(let results, let deletions, let insertions, let modifications): + DispatchQueue.main.async { + self?.objectWillChange.send() + } + case .error(let error): + break + } + } + } catch let error as NSError { + NSLog("Could not access database: ", error) + } } /// Triggered when the view appears. @@ -72,7 +107,7 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { self.indexActiveAccount = 0 for (index, account) in accounts.enumerated() { if account.active { - self.tableAccount = account + self.activeAccount = account self.indexActiveAccount = index self.alias = account.alias } @@ -81,20 +116,20 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { /// Func to get the user display name + alias func getUserName() -> String { - guard let tableAccount else { return "" } - NCManageDatabase.shared.setAccountAlias(tableAccount.account, alias: alias) + guard let activeAccount else { return "" } + NCManageDatabase.shared.setAccountAlias(activeAccount.account, alias: alias) if alias.isEmpty { - return tableAccount.displayName + return activeAccount.displayName } else { - return tableAccount.displayName + " (\(alias))" + return activeAccount.displayName + " (\(alias))" } } /// Function to update the user data func getUserStatus() -> (statusImage: UIImage, statusMessage: String, descriptionMessage: String) { - guard let tableAccount else { return (UIImage(), "", "") } + guard let activeAccount else { return (UIImage(), "", "") } if NCGlobal.shared.capabilityUserStatusEnabled, - let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", tableAccount.account)) { + let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", activeAccount.account)) { return NCUtility().getUserStatus(userIcon: tableAccount.userStatusIcon, userStatus: tableAccount.userStatusStatus, userMessage: tableAccount.userStatusMessage) } return (UIImage(), "", "") @@ -102,10 +137,10 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { /// Function to know the height of "account" data func getTableViewHeight() -> CGFloat { - guard let tableAccount else { return 0 } + guard let activeAccount else { return 0 } var height: CGFloat = 190 if NCGlobal.shared.capabilityUserStatusEnabled, - let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", tableAccount.account)) { + let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", activeAccount.account)) { if !tableAccount.email.isEmpty { height += 30 } if !tableAccount.phone.isEmpty { height += 30 } if !tableAccount.address.isEmpty { height += 30 } @@ -116,18 +151,28 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { /// Function to change account func setAccount(account: String) { - if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.tableAccount?.account != tableAccount.account { - self.tableAccount = tableAccount + if let tableAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)), self.activeAccount?.account != tableAccount.account { + self.activeAccount = tableAccount self.alias = tableAccount.alias + /// Change active account + timerChangeAccount?.invalidate() + timerChangeAccount = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(changeAccount), userInfo: nil, repeats: false) + + } + } + + @objc func changeAccount() { + if let activeAccount { + self.appDelegate.changeAccount(activeAccount.account, userProfile: nil) } } /// Function to delete the current account func deleteAccount() { - if let tableAccount { - appDelegate.deleteAccount(tableAccount.account, wipe: false) - if let tableAccount = NCManageDatabase.shared.getAllAccount().first { - appDelegate.changeAccount(tableAccount.account, userProfile: nil) + if let activeAccount { + appDelegate.deleteAccount(activeAccount.account, wipe: false) + if let account = NCManageDatabase.shared.getAllAccount().first?.account { + appDelegate.changeAccount(account, userProfile: nil) } else { dismissView = true } diff --git a/iOSClient/Account Settings/NCAccountSettingsView.swift b/iOSClient/Account Settings/NCAccountSettingsView.swift index 765d11f626..ff3ed39d73 100644 --- a/iOSClient/Account Settings/NCAccountSettingsView.swift +++ b/iOSClient/Account Settings/NCAccountSettingsView.swift @@ -114,7 +114,7 @@ struct NCAccountSettingsView: View { .font(.system(size: 14)) }) .sheet(isPresented: $showServerCertificate) { - if let url = URL(string: model.tableAccount?.urlBase), let host = url.host { + if let url = URL(string: model.activeAccount?.urlBase), let host = url.host { certificateDetailsView(host: host, title: NSLocalizedString("_certificate_view_", comment: "")) } } @@ -181,7 +181,7 @@ struct NCAccountSettingsView: View { } } .onDisappear { - model.delegate?.accountSettingsDidDismiss(tableAccount: model.tableAccount) + model.delegate?.accountSettingsDidDismiss(tableAccount: model.activeAccount) } } } @@ -223,48 +223,50 @@ struct TabContentView: View { .frame(height: 20) /// /// Personal data - if let tableAccount = model.tableAccount, !tableAccount.email.isEmpty { - HStack { - Image(systemName: "mail") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - Text(tableAccount.email) - .lineLimit(1) - .truncationMode(.middle) - .frame(maxWidth: .infinity, alignment: .leading) + if let activeAccount = model.activeAccount { + if !activeAccount.email.isEmpty { + HStack { + Image(systemName: "mail") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + Text(activeAccount.email) + .lineLimit(1) + .truncationMode(.middle) + .frame(maxWidth: .infinity, alignment: .leading) + } + .frame(maxWidth: .infinity, maxHeight: 30) } - .frame(maxWidth: .infinity, maxHeight: 30) - } - if let tableAccount = model.tableAccount, !tableAccount.phone.isEmpty { - HStack { - Image(systemName: "phone") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - Text(tableAccount.phone) - .lineLimit(1) - .truncationMode(.middle) - .frame(maxWidth: .infinity, alignment: .leading) + if !activeAccount.phone.isEmpty { + HStack { + Image(systemName: "phone") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + Text(activeAccount.phone) + .lineLimit(1) + .truncationMode(.middle) + .frame(maxWidth: .infinity, alignment: .leading) + } + .frame(maxWidth: .infinity, maxHeight: 30) } - .frame(maxWidth: .infinity, maxHeight: 30) - } - if let tableAccount = model.tableAccount, !tableAccount.address.isEmpty { - HStack { - Image(systemName: "house") - .resizable() - .scaledToFit() - .font(Font.system(.body).weight(.light)) - .frame(width: 20, height: 20) - Text(tableAccount.address) - .lineLimit(1) - .truncationMode(.middle) - .frame(maxWidth: .infinity, alignment: .leading) + if !activeAccount.address.isEmpty { + HStack { + Image(systemName: "house") + .resizable() + .scaledToFit() + .font(Font.system(.body).weight(.light)) + .frame(width: 20, height: 20) + Text(activeAccount.address) + .lineLimit(1) + .truncationMode(.middle) + .frame(maxWidth: .infinity, alignment: .leading) + } + .frame(maxWidth: .infinity, maxHeight: 30) } - .frame(maxWidth: .infinity, maxHeight: 30) } } } diff --git a/iOSClient/Data/NCManageDatabase+Account.swift b/iOSClient/Data/NCManageDatabase+Account.swift index d19a8374ea..1cd4b0c36d 100644 --- a/iOSClient/Data/NCManageDatabase+Account.swift +++ b/iOSClient/Data/NCManageDatabase+Account.swift @@ -26,7 +26,6 @@ import RealmSwift import NextcloudKit class tableAccount: Object, NCUserBaseUrl { - @objc dynamic var account = "" @objc dynamic var active: Bool = false @objc dynamic var address = "" From 32af40c096e4b2f614fbcb7a4224754697a0508e Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 21 Jun 2024 10:07:43 +0200 Subject: [PATCH 55/57] code cleaning Signed-off-by: Marino Faggiana --- iOSClient/Account Settings/NCAccountSettingsModel.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iOSClient/Account Settings/NCAccountSettingsModel.swift b/iOSClient/Account Settings/NCAccountSettingsModel.swift index fe6733c95a..f384745b32 100644 --- a/iOSClient/Account Settings/NCAccountSettingsModel.swift +++ b/iOSClient/Account Settings/NCAccountSettingsModel.swift @@ -52,7 +52,7 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { @Published var accountRequest: Bool = false /// Set true for dismiss the view @Published var dismissView = false - /// + /// Token observe tableAccount private var notificationToken: NotificationToken? /// Initialization code to set up the ViewModel with the active account @@ -82,11 +82,11 @@ class NCAccountSettingsModel: ObservableObject, ViewOnAppearHandling { switch changes { case .initial: break - case .update(let results, let deletions, let insertions, let modifications): + case .update: DispatchQueue.main.async { self?.objectWillChange.send() } - case .error(let error): + case .error: break } } From f9fa8019becfd01aa55c812fd0034996feccdc60 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 21 Jun 2024 11:17:25 +0200 Subject: [PATCH 56/57] cleaning Signed-off-by: Marino Faggiana --- .../Networking/NCNetworking+WebDAV.swift | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/iOSClient/Networking/NCNetworking+WebDAV.swift b/iOSClient/Networking/NCNetworking+WebDAV.swift index 56733b41c8..29afb1d7f2 100644 --- a/iOSClient/Networking/NCNetworking+WebDAV.swift +++ b/iOSClient/Networking/NCNetworking+WebDAV.swift @@ -693,26 +693,6 @@ extension NCNetworking { }) } - // MARK: - Download Preview - - func downloadPreview(fileNamePathOrFileId: String, - fileNamePreviewLocalPath: String, - widthPreview: Int, - heightPreview: Int, - fileNameIconLocalPath: String? = nil, - sizeIcon: Int = 0, - etag: String? = nil, - endpointTrashbin: Bool = false, - useInternalEndpoint: Bool = true, - options: NKRequestOptions = NKRequestOptions()) async -> (account: String, imagePreview: UIImage?, imageIcon: UIImage?, imageOriginal: UIImage?, etag: String?, error: NKError) { - - await withUnsafeContinuation({ continuation in - NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePathOrFileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, widthPreview: widthPreview, heightPreview: heightPreview, fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: sizeIcon, etag: etag, options: options) { account, imagePreview, imageIcon, imageOriginal, etag, error in - continuation.resume(returning: (account: account, imagePreview: imagePreview, imageIcon: imageIcon, imageOriginal: imageOriginal, etag: etag, error: error)) - } - }) - } - // MARK: - Search /// WebDAV search From 84a55b74f326aa97e10aa076a51f29dfd051e1ac Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Fri, 21 Jun 2024 11:54:59 +0200 Subject: [PATCH 57/57] new preview api Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 4 ++-- Widget/Files/FilesData.swift | 4 ++-- iOSClient/Activity/NCActivityTableViewCell.swift | 14 +++----------- .../NCCollectionViewDownloadThumbnail.swift | 6 ++---- iOSClient/Media/NCMediaDownloadThumbnaill.swift | 6 ++---- iOSClient/Trash/NCTrash+Networking.swift | 16 +++++++--------- .../Viewer/NCViewerMedia/NCViewerMedia.swift | 5 ++--- 7 files changed, 20 insertions(+), 35 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 8daa7116d8..0b5893c632 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -5698,8 +5698,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/nextcloud/NextcloudKit"; requirement = { - kind = exactVersion; - version = 3.0.1; + branch = develop; + kind = branch; }; }; F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = { diff --git a/Widget/Files/FilesData.swift b/Widget/Files/FilesData.swift index 0d49dd3272..19180076ff 100644 --- a/Widget/Files/FilesData.swift +++ b/Widget/Files/FilesData.swift @@ -219,11 +219,11 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi if let result = utility.createFilePreviewImage(ocId: file.ocId, etag: file.etag, fileNameView: file.fileName, classFile: file.classFile, status: 0, createPreviewMedia: false) { image = result } else if file.hasPreview { - let fileNamePathOrFileId = utilityFileSystem.getFileNamePath(file.fileName, serverUrl: file.serverUrl, urlBase: file.urlBase, userId: file.userId) + let fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(file.ocId, etag: file.etag) let fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(file.ocId, etag: file.etag) let sizePreview = NCUtility().getSizePreview(width: Int(file.width), height: Int(file.height)) - let (_, _, imageIcon, _, _, _) = await NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePathOrFileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, widthPreview: Int(sizePreview.width), heightPreview: Int(sizePreview.height), fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, options: options) + let (_, _, imageIcon, _, _, _) = await NextcloudKit.shared.downloadPreview(fileId: file.fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, fileNameIconLocalPath: fileNameIconLocalPath, widthPreview: Int(sizePreview.width), heightPreview: Int(sizePreview.height), sizeIcon: NCGlobal.shared.sizeIcon, options: options) if let result = imageIcon { image = result } diff --git a/iOSClient/Activity/NCActivityTableViewCell.swift b/iOSClient/Activity/NCActivityTableViewCell.swift index 5662d92fcb..4286b25902 100644 --- a/iOSClient/Activity/NCActivityTableViewCell.swift +++ b/iOSClient/Activity/NCActivityTableViewCell.swift @@ -199,7 +199,7 @@ extension NCActivityTableViewCell: UICollectionViewDataSource { cell.fileId = fileId if !FileManager.default.fileExists(atPath: fileNamePath) { if NCNetworking.shared.downloadThumbnailActivityQueue.operations.filter({ ($0 as? NCOperationDownloadThumbnailActivity)?.fileId == fileId }).isEmpty { - NCNetworking.shared.downloadThumbnailActivityQueue.addOperation(NCOperationDownloadThumbnailActivity(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, fileId: fileId, cell: cell, collectionView: collectionView)) + NCNetworking.shared.downloadThumbnailActivityQueue.addOperation(NCOperationDownloadThumbnailActivity(fileId: fileId, fileNamePreviewLocalPath: fileNamePath, cell: cell, collectionView: collectionView)) } } } @@ -231,12 +231,10 @@ class NCOperationDownloadThumbnailActivity: ConcurrentOperation { var cell: NCActivityCollectionViewCell? var collectionView: UICollectionView? - var fileNamePathOrFileId: String var fileNamePreviewLocalPath: String var fileId: String - init(fileNamePathOrFileId: String, fileNamePreviewLocalPath: String, fileId: String, cell: NCActivityCollectionViewCell?, collectionView: UICollectionView?) { - self.fileNamePathOrFileId = fileNamePathOrFileId + init(fileId: String, fileNamePreviewLocalPath: String, cell: NCActivityCollectionViewCell?, collectionView: UICollectionView?) { self.fileNamePreviewLocalPath = fileNamePreviewLocalPath self.fileId = fileId self.cell = cell @@ -244,15 +242,9 @@ class NCOperationDownloadThumbnailActivity: ConcurrentOperation { } override func start() { - guard !isCancelled else { return self.finish() } - - NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePathOrFileId, + NextcloudKit.shared.downloadPreview(fileId: fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, - widthPreview: 0, - heightPreview: 0, - etag: nil, - useInternalEndpoint: false, options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, _, error in if error == .success, let imagePreview = imagePreview { diff --git a/iOSClient/Main/Collection Common/NCCollectionViewDownloadThumbnail.swift b/iOSClient/Main/Collection Common/NCCollectionViewDownloadThumbnail.swift index 7f10df306d..7b455cb415 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewDownloadThumbnail.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewDownloadThumbnail.swift @@ -32,7 +32,6 @@ class NCCollectionViewDownloadThumbnail: ConcurrentOperation { var metadata: tableMetadata var cell: NCCellProtocol? var collectionView: UICollectionView? - var fileNamePath: String var fileNamePreviewLocalPath: String var fileNameIconLocalPath: String let utilityFileSystem = NCUtilityFileSystem() @@ -41,7 +40,6 @@ class NCCollectionViewDownloadThumbnail: ConcurrentOperation { self.metadata = tableMetadata.init(value: metadata) self.cell = cell self.collectionView = collectionView - self.fileNamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId) self.fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag) self.fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag) } @@ -56,11 +54,11 @@ class NCCollectionViewDownloadThumbnail: ConcurrentOperation { etagResource = metadata.etagResource } - NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, + NextcloudKit.shared.downloadPreview(fileId: metadata.fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, + fileNameIconLocalPath: fileNameIconLocalPath, widthPreview: Int(sizePreview.width), heightPreview: Int(sizePreview.height), - fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, etag: etagResource, options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, _, imageIcon, _, etag, error in diff --git a/iOSClient/Media/NCMediaDownloadThumbnaill.swift b/iOSClient/Media/NCMediaDownloadThumbnaill.swift index 6ec3c154b4..bfc1304625 100644 --- a/iOSClient/Media/NCMediaDownloadThumbnaill.swift +++ b/iOSClient/Media/NCMediaDownloadThumbnaill.swift @@ -29,7 +29,6 @@ class NCMediaDownloadThumbnaill: ConcurrentOperation { var metadata: tableMetadata var media: NCMedia - var fileNamePath: String var fileNamePreviewLocalPath: String var fileNameIconLocalPath: String let utilityFileSystem = NCUtilityFileSystem() @@ -37,7 +36,6 @@ class NCMediaDownloadThumbnaill: ConcurrentOperation { init(metadata: tableMetadata, media: NCMedia) { self.metadata = tableMetadata.init(value: metadata) self.media = media - self.fileNamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId) self.fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag) self.fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag) } @@ -52,11 +50,11 @@ class NCMediaDownloadThumbnaill: ConcurrentOperation { etagResource = metadata.etagResource } - NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, + NextcloudKit.shared.downloadPreview(fileId: metadata.fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, + fileNameIconLocalPath: fileNameIconLocalPath, widthPreview: Int(sizePreview.width), heightPreview: Int(sizePreview.height), - fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, etag: etagResource, options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, etag, error in diff --git a/iOSClient/Trash/NCTrash+Networking.swift b/iOSClient/Trash/NCTrash+Networking.swift index af08ebcf31..b52a673e8a 100644 --- a/iOSClient/Trash/NCTrash+Networking.swift +++ b/iOSClient/Trash/NCTrash+Networking.swift @@ -104,15 +104,13 @@ class NCOperationDownloadThumbnailTrash: ConcurrentOperation { let fileNamePreviewLocalPath = NCUtilityFileSystem().getDirectoryProviderStoragePreviewOcId(tableTrash.fileId, etag: tableTrash.fileName) let fileNameIconLocalPath = NCUtilityFileSystem().getDirectoryProviderStorageIconOcId(tableTrash.fileId, etag: tableTrash.fileName) - NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: tableTrash.fileId, - fileNamePreviewLocalPath: fileNamePreviewLocalPath, - widthPreview: NCGlobal.shared.sizePreview, - heightPreview: NCGlobal.shared.sizePreview, - fileNameIconLocalPath: fileNameIconLocalPath, - sizeIcon: NCGlobal.shared.sizeIcon, - etag: nil, - endpointTrashbin: true, - options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, _, error in + NextcloudKit.shared.downloadTrashPreview(fileId: tableTrash.fileId, + fileNamePreviewLocalPath: fileNamePreviewLocalPath, + fileNameIconLocalPath: fileNameIconLocalPath, + widthPreview: NCGlobal.shared.sizePreview, + heightPreview: NCGlobal.shared.sizePreview, + sizeIcon: NCGlobal.shared.sizeIcon, + options: NKRequestOptions(queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)) { _, imagePreview, _, _, _, error in if error == .success, let imagePreview = imagePreview { DispatchQueue.main.async { diff --git a/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift b/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift index 13308923a1..721fa02d9b 100644 --- a/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift +++ b/iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift @@ -300,16 +300,15 @@ class NCViewerMedia: UIViewController { if utilityFileSystem.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag) { return completion(UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag))) } else { - let fileNamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId) let fileNamePreviewLocalPath = utilityFileSystem.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag) let fileNameIconLocalPath = utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag) let sizePreview = NCUtility().getSizePreview(width: metadata.width, height: metadata.height) - NextcloudKit.shared.downloadPreview(fileNamePathOrFileId: fileNamePath, + NextcloudKit.shared.downloadPreview(fileId: metadata.fileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, + fileNameIconLocalPath: fileNameIconLocalPath, widthPreview: Int(sizePreview.width), heightPreview: Int(sizePreview.height), - fileNameIconLocalPath: fileNameIconLocalPath, sizeIcon: NCGlobal.shared.sizeIcon, options: NKRequestOptions(queue: .main)) { _, imagePreview, _, _, etag, error in