From af745b0c7a356434ea31cd11ca3621afb99869ec Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Thu, 21 Mar 2024 16:43:59 +0200 Subject: [PATCH 01/15] Changed the description text for the alert that changes the profile and banner picture. --- .../ViewController/PublicArchiveViewController.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift b/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift index db8977e0..dcf5f18a 100644 --- a/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift +++ b/Permanent/Modules/PublicProfile/ViewController/PublicArchiveViewController.swift @@ -228,7 +228,11 @@ extension PublicArchiveViewController: PublicArchiveChildDelegate { extension PublicArchiveViewController: MyFilesViewModelPickerDelegate { func myFilesVMDidPickFile(viewModel: MyFilesViewModel, file: FileModel) { dismiss(animated: true) { - let alert = UIAlertController(title: "Updating...".localized(), message: "Please wait while your banner is being updated".localized(), preferredStyle: .alert) + var alertDescription: String = "Please wait while your banner is updated." + if self.isPickingProfilePicture { + alertDescription = "Please wait while your profile picture is updated." + } + let alert = UIAlertController(title: "Updating...", message: alertDescription, preferredStyle: .alert) self.present(alert, animated: true, completion: { if self.isPickingProfilePicture { self.viewModel?.updateProfilePicture(file: file, then: { status in From c276981bd3f59f057c038abee533476557303345 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Wed, 27 Mar 2024 10:08:18 +0200 Subject: [PATCH 02/15] Added PrivacyInfo for upcoming third-party SDK requirements update. --- Permanent.xcodeproj/project.pbxproj | 8 ++++++ Permanent/App/PrivacyInfo.xcprivacy | 43 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 Permanent/App/PrivacyInfo.xcprivacy diff --git a/Permanent.xcodeproj/project.pbxproj b/Permanent.xcodeproj/project.pbxproj index 05896b29..17c23b61 100644 --- a/Permanent.xcodeproj/project.pbxproj +++ b/Permanent.xcodeproj/project.pbxproj @@ -415,6 +415,9 @@ 5ED581CC25EFC3A100A5A79E /* FileDetailsBottomCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5ED581CA25EFC3A100A5A79E /* FileDetailsBottomCollectionViewCell.xib */; }; 5ED73B252613C30E002F9861 /* TagEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED73B242613C30E002F9861 /* TagEndpoint.swift */; }; 5ED73B3826143ED5002F9861 /* TagLinkVO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED73B3726143ED5002F9861 /* TagLinkVO.swift */; }; + 5ED9B6582BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 5ED9B6572BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy */; }; + 5ED9B6592BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 5ED9B6572BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy */; }; + 5ED9B65A2BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 5ED9B6572BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy */; }; 5EDDAE5A2A9E312E00415D9A /* EditDateAndTimeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EDDAE592A9E312E00415D9A /* EditDateAndTimeView.swift */; }; 5EDDAE5E2A9F4A3E00415D9A /* EditDateAndTimeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EDDAE5D2A9F4A3E00415D9A /* EditDateAndTimeViewModel.swift */; }; 5EE0ADB325F8216D008ABDC6 /* TagVO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EE0ADB225F8216D008ABDC6 /* TagVO.swift */; }; @@ -1230,6 +1233,7 @@ 5ED581CA25EFC3A100A5A79E /* FileDetailsBottomCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FileDetailsBottomCollectionViewCell.xib; sourceTree = ""; }; 5ED73B242613C30E002F9861 /* TagEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagEndpoint.swift; sourceTree = ""; }; 5ED73B3726143ED5002F9861 /* TagLinkVO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagLinkVO.swift; sourceTree = ""; }; + 5ED9B6572BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 5EDDAE592A9E312E00415D9A /* EditDateAndTimeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditDateAndTimeView.swift; sourceTree = ""; }; 5EDDAE5D2A9F4A3E00415D9A /* EditDateAndTimeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditDateAndTimeViewModel.swift; sourceTree = ""; }; 5EE0ADB225F8216D008ABDC6 /* TagVO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagVO.swift; sourceTree = ""; }; @@ -2366,6 +2370,7 @@ 5E3E124A2A431F9600682DE5 /* EnvVars.generated.swift */, 5E2C5D1A24D98EE100E2B95F /* AppDelegate.swift */, F5551D87261C559B00A7C540 /* EnvVars.stencil */, + 5ED9B6572BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy */, ); path = App; sourceTree = ""; @@ -4009,6 +4014,7 @@ 5ED0856D24E4257100CDB4D3 /* OpenSans-Regular.ttf in Resources */, 5EBDBD4D26F1F698002142DB /* ArchiveScreenSectionTitleTableViewCell.xib in Resources */, 5E4E4CD029826F4000FEF292 /* ArchiveSettingsTagsHeaderCollectionView.xib in Resources */, + 5ED9B6582BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy in Resources */, 5E62F7CF27FB10610046F6C8 /* PublicGalleryCellCollectionViewCell.xib in Resources */, BCF906672587B12000DF1B64 /* Members.storyboard in Resources */, 5EADF804262475D500D14E9C /* TagCollectionViewCell.xib in Resources */, @@ -4134,6 +4140,7 @@ 5ECF1DC62B7520E20086EF21 /* Usual-Regular.ttf in Resources */, F5ADBF3E290BBFA00007A516 /* ArchiveScreenPendingArchiveDetailsTableViewCell.xib in Resources */, 5ECF1DB82B7520E20086EF21 /* Usual-ExtraBoldItalic.ttf in Resources */, + 5ED9B65A2BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy in Resources */, 5ECF1DBE2B7520E20086EF21 /* Usual-Italic.ttf in Resources */, 5ECF1DB62B7520E20086EF21 /* Usual-Bold.ttf in Resources */, F55252A12907F1EA0005E011 /* EmptyFolderView.xib in Resources */, @@ -4152,6 +4159,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5ED9B6592BB34D0A00A2F6F3 /* PrivacyInfo.xcprivacy in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Permanent/App/PrivacyInfo.xcprivacy b/Permanent/App/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..d0b54821 --- /dev/null +++ b/Permanent/App/PrivacyInfo.xcprivacy @@ -0,0 +1,43 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + 3B52.1 + DDA9.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + E174.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + AC6B.1 + + + + + From 495b0e9b28fa6687ead9524c294aae58e7459b30 Mon Sep 17 00:00:00 2001 From: flaviuvsp Date: Mon, 15 Apr 2024 14:21:27 +0300 Subject: [PATCH 03/15] Add loading indicator while gathering metadata --- Permanent.xcodeproj/project.pbxproj | 12 ++- .../Base/SwiftUIViews/SectionView.swift | 9 +- .../Base/SwiftUIViews/SnackBarView.swift | 43 ++++++++++ .../ViewModels/FilesMetadataViewModel.swift | 6 +- .../EditMetadata/Views/MetadataEditView.swift | 82 +++++++++++-------- 5 files changed, 108 insertions(+), 44 deletions(-) create mode 100644 Permanent/Common/Base/SwiftUIViews/SnackBarView.swift diff --git a/Permanent.xcodeproj/project.pbxproj b/Permanent.xcodeproj/project.pbxproj index 17c23b61..c42fedef 100644 --- a/Permanent.xcodeproj/project.pbxproj +++ b/Permanent.xcodeproj/project.pbxproj @@ -464,6 +464,7 @@ 924F16312A459C2E00B75D4E /* FlowGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 924F16302A459C2E00B75D4E /* FlowGrid.swift */; }; 924F16352A45CBD800B75D4E /* TextExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 924F16342A45CBD800B75D4E /* TextExtension.swift */; }; 924F16372A45CC6200B75D4E /* TextViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 924F16362A45CC6200B75D4E /* TextViewModifiers.swift */; }; + 9262736A2BCD31DC00D824CE /* SnackBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 926273692BCD31DC00D824CE /* SnackBarView.swift */; }; 927AE0C52A260D7700BDF26A /* BannerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927AE0C42A260D7700BDF26A /* BannerType.swift */; }; 927AE0C92A262EA100BDF26A /* BannerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 927AE0C82A262EA100BDF26A /* BannerView.xib */; }; 927AE0CB2A2634CA00BDF26A /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927AE0CA2A2634CA00BDF26A /* GradientView.swift */; }; @@ -1276,6 +1277,7 @@ 924F16302A459C2E00B75D4E /* FlowGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowGrid.swift; sourceTree = ""; }; 924F16342A45CBD800B75D4E /* TextExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextExtension.swift; sourceTree = ""; }; 924F16362A45CC6200B75D4E /* TextViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewModifiers.swift; sourceTree = ""; }; + 926273692BCD31DC00D824CE /* SnackBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackBarView.swift; sourceTree = ""; }; 927AE0C42A260D7700BDF26A /* BannerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerType.swift; sourceTree = ""; }; 927AE0C82A262EA100BDF26A /* BannerView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BannerView.xib; sourceTree = ""; }; 927AE0CA2A2634CA00BDF26A /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = ""; }; @@ -2873,6 +2875,7 @@ 5E181B862AF2EAF5002DE69A /* CustomStepperView.swift */, 5EA70D8A2B2C78E200175D9C /* NewBadgeView.swift */, 5EA70D8E2B2C793A00175D9C /* GradientCustomBarView.swift */, + 926273692BCD31DC00D824CE /* SnackBarView.swift */, ); path = SwiftUIViews; sourceTree = ""; @@ -4469,6 +4472,7 @@ BC6E70F3252C74B600113D5F /* PermanentLocalAuthentication.swift in Sources */, BCA120C6256279C100ECAD7B /* SortOption.swift in Sources */, 06B0EB2A24E67EC4003D90C6 /* Constants.swift in Sources */, + 9262736A2BCD31DC00D824CE /* SnackBarView.swift in Sources */, 5EC9C694290B323000AD2E37 /* LoginViewController.swift in Sources */, 5E048FD7292308B10023C929 /* ShareMangementAdditionalOptionCollectionViewCell.swift in Sources */, 5E62F7BA27F5E5910046F6C8 /* PublicGalleryHeaderCollectionViewCell.swift in Sources */, @@ -5275,7 +5279,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.3; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5306,7 +5310,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.3; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -5713,7 +5717,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.3; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5798,7 +5802,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.3; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/Permanent/Common/Base/SwiftUIViews/SectionView.swift b/Permanent/Common/Base/SwiftUIViews/SectionView.swift index da536d94..0d2db01e 100644 --- a/Permanent/Common/Base/SwiftUIViews/SectionView.swift +++ b/Permanent/Common/Base/SwiftUIViews/SectionView.swift @@ -13,6 +13,7 @@ struct SectionView: View { var rightButtonView: RightButtonView? var haveRightSection: Bool = true var divider: Divider? = nil + var isLoading: Bool = false var body: some View { VStack { @@ -21,14 +22,16 @@ struct SectionView: View { Text(title) .textStyle(SmallRegularTextStyle()) Spacer() - if haveRightSection { + if isLoading { + ProgressView() + } else if haveRightSection { rightButtonView } } divider - .padding(.top, 24) + .padding(.top, 20) } - .padding(.top, 24) + .padding(.top, 20) } } diff --git a/Permanent/Common/Base/SwiftUIViews/SnackBarView.swift b/Permanent/Common/Base/SwiftUIViews/SnackBarView.swift new file mode 100644 index 00000000..7ffbcc35 --- /dev/null +++ b/Permanent/Common/Base/SwiftUIViews/SnackBarView.swift @@ -0,0 +1,43 @@ +// +// SnackBarView.swift +// Permanent +// +// Created by Flaviu Silaghi on 15.04.2024. + +import SwiftUI + +struct SnackBarView: View { + @Binding var show: Bool + private var messsage: String + + init(message: String, show: Binding) { + self.messsage = message + _show = show + } + + var body: some View { + VStack { + Spacer() + if show { + Text(messsage) + .textStyle(SmallRegularTextStyle()) + .foregroundColor(Color.middleGray) + .frame(minWidth: 240, minHeight: 64) + .padding(.horizontal, 12) + .padding(.vertical, 4) + .background(Color.white) + .cornerRadius(32) + .shadow(color: .black.opacity(0.08), radius: 8, x: 0, y: 16) + .padding(.bottom, 32) + + // Optionally add a button to dismiss + } + } + .animation(.spring(), value: show) // Animation for showing/hiding + .edgesIgnoringSafeArea(.bottom) // Overlay the whole window + } +} + +#Preview { + SnackBarView(message: "Hello", show: .constant(true)) +} diff --git a/Permanent/Modules/EditMetadata/ViewModels/FilesMetadataViewModel.swift b/Permanent/Modules/EditMetadata/ViewModels/FilesMetadataViewModel.swift index c696b975..2168fbbe 100644 --- a/Permanent/Modules/EditMetadata/ViewModels/FilesMetadataViewModel.swift +++ b/Permanent/Modules/EditMetadata/ViewModels/FilesMetadataViewModel.swift @@ -9,6 +9,8 @@ import Foundation class FilesMetadataViewModel: ObservableObject { + @Published var isLoading: Bool = false + @Published var selectedFiles: [FileModel] = [] { didSet { let tags = Array(Set(selectedFiles.flatMap{ $0.tagVOS ?? [] }.map{ TagVO(tagVO: $0)})) @@ -75,6 +77,7 @@ class FilesMetadataViewModel: ObservableObject { } func refreshFiles() { + isLoading = true Task {[weak self] in guard let strongSelf = self else { return } let records = try await strongSelf.selectedFiles.asyncMap(strongSelf.getRecord) @@ -87,7 +90,8 @@ class FilesMetadataViewModel: ObservableObject { } return nil } - + + strongSelf.isLoading = false } } } diff --git a/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift b/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift index c24509e9..4b6236c3 100644 --- a/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift +++ b/Permanent/Modules/EditMetadata/Views/MetadataEditView.swift @@ -10,7 +10,7 @@ import SwiftUI struct MetadataEditView: View { @Environment(\.presentationMode) var presentationMode @StateObject var viewModel: FilesMetadataViewModel - + @State var showAddNewTag: Bool = false @State var showEditFilenames: Bool = false @State var showSetLocation: Bool = false @@ -26,13 +26,14 @@ struct MetadataEditView: View { Color.whiteGray .frame(maxWidth: .infinity, maxHeight: .infinity) .edgesIgnoringSafeArea(.all) + SnackBarView(message: "Gathering file metadata...", show: $viewModel.isLoading) ScrollView(showsIndicators: false) { LazyVStack { Group { SectionHeaderView(selectedFiles: $viewModel.selectedFiles) Divider() .padding(.horizontal, 0) - .padding(.top, 24) + .padding(.top, 20) } Group { VStack(alignment: .leading) { @@ -43,34 +44,37 @@ struct MetadataEditView: View { text: "Enter Description", action: { } ), - haveRightSection: false + haveRightSection: false, + isLoading: viewModel.isLoading ) - - ZStack { - RoundedRectangle(cornerRadius: 2) - .fill(Color.white) - .overlay( - RoundedRectangle(cornerRadius: 2) - .inset(by: 0.5) - .stroke(Color.galleryGray, lineWidth: 1) - ) - TextView(text: $viewModel.inputText, - didSaved: $viewModel.didSaved, - textStyle: TextFontStyle.style39, - textColor: .middleGray) - .padding(.all, 5) - .frame(maxHeight: 72) - } - .frame(height: 72) - .foregroundColor(.clear) - if viewModel.haveDiffDescription { - Text("Some files already have descriptions.") - .textStyle(SmallXXRegularTextStyle()) - .foregroundColor(.lightRed) - .padding(.top, 5) - Divider() - .padding(.top, 0) + if !viewModel.isLoading { + ZStack { + RoundedRectangle(cornerRadius: 2) + .fill(Color.white) + .overlay( + RoundedRectangle(cornerRadius: 2) + .inset(by: 0.5) + .stroke(Color.galleryGray, lineWidth: 1) + ) + TextView(text: $viewModel.inputText, + didSaved: $viewModel.didSaved, + textStyle: TextFontStyle.style39, + textColor: .middleGray) + .padding(.all, 5) + .frame(maxHeight: 72) + } + .frame(height: 72) + .foregroundColor(.clear) + if viewModel.haveDiffDescription { + Text("Some files already have descriptions.") + .textStyle(SmallXXRegularTextStyle()) + .foregroundColor(.lightRed) + .padding(.top, 5) + } } + + Divider() + .padding(.top, 20) } } Group { @@ -84,12 +88,15 @@ struct MetadataEditView: View { viewModel.assignAllTagsToAll() } ), - haveRightSection: viewModel.havePartialTags + haveRightSection: viewModel.havePartialTags, + isLoading: viewModel.isLoading ) - .padding(.top, -10) - TagsView(viewModel: viewModel, showAddNewTagView: $showAddNewTag) - Spacer(minLength: 24) + if !viewModel.isLoading { + TagsView(viewModel: viewModel, showAddNewTagView: $showAddNewTag) + } + Divider() + .padding(.top, 20) } SectionView( assetName: "metadataFileNames", @@ -100,7 +107,8 @@ struct MetadataEditView: View { showEditFilenames.toggle() } ), - divider: Divider.init() + divider: Divider.init(), + isLoading: viewModel.isLoading ) SectionView( assetName: "metadataDateAndTime", @@ -111,7 +119,8 @@ struct MetadataEditView: View { showEditDataTime.toggle() } ), - divider: Divider.init() + divider: Divider.init(), + isLoading: viewModel.isLoading ) SectionView( assetName: "metadataLocations", @@ -121,7 +130,8 @@ struct MetadataEditView: View { action: { showSetLocation.toggle() } - ) + ), + isLoading: viewModel.isLoading ) Spacer(minLength: 50) } @@ -150,7 +160,7 @@ struct MetadataEditView: View { AddLocationView(viewModel: AddLocationViewModel(selectedFiles: viewModel.selectedFiles, commonLocation: viewModel.commonLocation)) } .sheet(isPresented: $showEditDataTime) { - EditDateAndTimeView(viewModel: EditDateAndTimeViewModel(selectedFiles: viewModel.selectedFiles, hasUpdates: $viewModel.hasUpdates)) + EditDateAndTimeView(viewModel: EditDateAndTimeViewModel(selectedFiles: viewModel.selectedFiles, hasUpdates: $viewModel.hasUpdates)) } .onAppear { viewModel.refreshFiles() From bb9ab54ec251d9a0ed8403ea4ad38c281671e265 Mon Sep 17 00:00:00 2001 From: flaviuvsp Date: Mon, 15 Apr 2024 16:44:15 +0300 Subject: [PATCH 04/15] Update Fastfile --- fastlane/Fastfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index cd9df72a..88823bd4 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -49,7 +49,8 @@ platform :ios do match(type: "adhoc", app_identifier: "org.permanent.permanent.staging", git_url: "https://oauth2:#{ENV['FASTLANE_MATCH_TOKEN']}@github.com/PermanentOrg/permanent-ios-certs.git", - force_for_new_devices: true + force_for_new_devices: true, + verbose: true ) match(type: "adhoc", app_identifier: "org.permanent.permanent.staging.PushExtension", From 5eb8109980a2b167d22f76ef87c32f635e32aac4 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Tue, 21 May 2024 17:34:55 +0300 Subject: [PATCH 05/15] Resolved an issue where the app tries to scroll to a null position. --- .../Shares/ViewController/SharesViewController.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Permanent/Modules/Shares/ViewController/SharesViewController.swift b/Permanent/Modules/Shares/ViewController/SharesViewController.swift index 876ad78d..424cc0d5 100644 --- a/Permanent/Modules/Shares/ViewController/SharesViewController.swift +++ b/Permanent/Modules/Shares/ViewController/SharesViewController.swift @@ -1236,7 +1236,14 @@ extension SharesViewController { return } + guard index >= 0 && index < collectionView.numberOfItems(inSection: 0) else { + // Handle the case where the index is out of bounds + print("Index out of bounds") + return + } + let indexPath = IndexPath(row: index, section: 0) + collectionView.selectItem(at: indexPath, animated: true, scrollPosition: []) } } From ea36d9962a278fd82c8d92c6e695d1901930ffc8 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Tue, 21 May 2024 17:42:06 +0300 Subject: [PATCH 06/15] Removed print statement. --- .../Modules/Shares/ViewController/SharesViewController.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Permanent/Modules/Shares/ViewController/SharesViewController.swift b/Permanent/Modules/Shares/ViewController/SharesViewController.swift index 424cc0d5..e8841fc5 100644 --- a/Permanent/Modules/Shares/ViewController/SharesViewController.swift +++ b/Permanent/Modules/Shares/ViewController/SharesViewController.swift @@ -1238,7 +1238,6 @@ extension SharesViewController { guard index >= 0 && index < collectionView.numberOfItems(inSection: 0) else { // Handle the case where the index is out of bounds - print("Index out of bounds") return } From 64144a2fc7929b358f817ef1728fca1b36321c25 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Mon, 27 May 2024 12:46:44 +0300 Subject: [PATCH 07/15] Changed app version. --- Permanent.xcodeproj/project.pbxproj | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Permanent.xcodeproj/project.pbxproj b/Permanent.xcodeproj/project.pbxproj index c42fedef..f59709fb 100644 --- a/Permanent.xcodeproj/project.pbxproj +++ b/Permanent.xcodeproj/project.pbxproj @@ -5279,7 +5279,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.3; + MARKETING_VERSION = 1.10.4; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5310,7 +5310,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.3; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -5332,7 +5332,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5353,7 +5353,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5374,7 +5374,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5395,7 +5395,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5524,7 +5524,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5558,7 +5558,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5592,7 +5592,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5626,7 +5626,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5717,7 +5717,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.3; + MARKETING_VERSION = 1.10.4; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5802,7 +5802,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.3; + MARKETING_VERSION = 1.10.4; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5830,7 +5830,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -5855,7 +5855,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -5880,7 +5880,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -5905,7 +5905,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.2; + MARKETING_VERSION = 1.10.4; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; From 3e4cd888edd7159f174532fdf736e9c6677232bb Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Mon, 19 Aug 2024 17:09:05 +0300 Subject: [PATCH 08/15] A new error message was added when user logged in with a wrong account. --- Permanent/Common/Authentication/ViewModel/AuthViewModel.swift | 3 ++- Permanent/Common/Managers/AuthenticationManager.swift | 2 ++ .../Authentication/ViewController/LoginViewController.swift | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Permanent/Common/Authentication/ViewModel/AuthViewModel.swift b/Permanent/Common/Authentication/ViewModel/AuthViewModel.swift index a5e590c6..d0a7d948 100644 --- a/Permanent/Common/Authentication/ViewModel/AuthViewModel.swift +++ b/Permanent/Common/Authentication/ViewModel/AuthViewModel.swift @@ -95,7 +95,7 @@ class AuthViewModel: ViewModelInterface { AuthenticationManager.shared.login(withUsername: email, password: password) { status in switch status { - case .success, .mfaToken: + case .success, .mfaToken, .unknown: handler(status) case .error(message: _): @@ -190,6 +190,7 @@ class AuthViewModel: ViewModelInterface { enum LoginStatus: Equatable { case success case mfaToken + case unknown case error(message: String?) } diff --git a/Permanent/Common/Managers/AuthenticationManager.swift b/Permanent/Common/Managers/AuthenticationManager.swift index 081134af..8c359d0d 100644 --- a/Permanent/Common/Managers/AuthenticationManager.swift +++ b/Permanent/Common/Managers/AuthenticationManager.swift @@ -89,6 +89,8 @@ class AuthenticationManager { if loginError == .mfaToken { mfaSession = MFASession(email: username, methodType: CodeVerificationType.mfa) handler(.mfaToken) + } else if loginError == .unknown { + handler(.unknown) } else { handler(.error(message: loginError.description)) } diff --git a/Permanent/Modules/Authentication/ViewController/LoginViewController.swift b/Permanent/Modules/Authentication/ViewController/LoginViewController.swift index 34f4cdde..1c7cf9e4 100644 --- a/Permanent/Modules/Authentication/ViewController/LoginViewController.swift +++ b/Permanent/Modules/Authentication/ViewController/LoginViewController.swift @@ -96,6 +96,8 @@ class LoginViewController: BaseViewController { let verificationCodeVC = UIViewController.create(withIdentifier: .verificationCode, from: .authentication) as! CodeVerificationController self?.present(verificationCodeVC, animated: true) self?.trackEvents() + case .unknown: + self?.showAlert(title: .error, message: .incorrectCredentials) case .error(message: let message): self?.showAlert(title: .error, message: message) } From a58c3e96428a32310d2faa2946f63737010bb87d Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Mon, 19 Aug 2024 17:18:17 +0300 Subject: [PATCH 09/15] Updated Marketing Version to 1.10.5 --- Permanent.xcodeproj/project.pbxproj | 44 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Permanent.xcodeproj/project.pbxproj b/Permanent.xcodeproj/project.pbxproj index f59709fb..52db37b3 100644 --- a/Permanent.xcodeproj/project.pbxproj +++ b/Permanent.xcodeproj/project.pbxproj @@ -5269,7 +5269,7 @@ CODE_SIGN_ENTITLEMENTS = Permanent/Resources/Assets/Entitlements/Permanent.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 159; DEVELOPMENT_TEAM = C8YKZNBVWT; ENV_VARS_FILENAME = "env-vars.sh"; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; @@ -5279,7 +5279,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5300,7 +5300,7 @@ CODE_SIGN_ENTITLEMENTS = Permanent/Resources/Assets/Entitlements/PermanentRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 159; DEVELOPMENT_TEAM = C8YKZNBVWT; ENV_VARS_FILENAME = "env-vars.sh"; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; @@ -5310,7 +5310,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -5332,7 +5332,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5353,7 +5353,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5374,7 +5374,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5395,7 +5395,7 @@ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.7; - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PermanentUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; @@ -5421,6 +5421,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -5445,6 +5446,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -5469,6 +5471,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -5493,6 +5496,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = com.vsp.PermanentTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -5524,7 +5528,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5558,7 +5562,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5592,7 +5596,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5626,7 +5630,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5707,7 +5711,7 @@ CODE_SIGN_ENTITLEMENTS = "Permanent/Resources/Assets/Entitlements/PermanentDEV-Debug.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 159; DEVELOPMENT_TEAM = C8YKZNBVWT; ENV_VARS_FILENAME = "env-vars-staging.sh"; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; @@ -5717,7 +5721,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5792,7 +5796,7 @@ CODE_SIGN_ENTITLEMENTS = "Permanent/Resources/Assets/Entitlements/Permanent-Staging.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 159; DEVELOPMENT_TEAM = C8YKZNBVWT; ENV_VARS_FILENAME = "env-vars-staging.sh"; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; @@ -5802,7 +5806,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; OTHER_SWIFT_FLAGS = "-D COCOAPODS -DSTAGING_ENVIRONMENT"; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5830,7 +5834,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -5855,7 +5859,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -5880,7 +5884,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.PermanentArchive.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -5905,7 +5909,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.10.4; + MARKETING_VERSION = 1.10.5; PRODUCT_BUNDLE_IDENTIFIER = org.permanent.permanent.staging.PushExtension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; From 3bf21e478350fbc7712b9a9f05757b5bc4a0ecc9 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Tue, 20 Aug 2024 15:49:39 +0300 Subject: [PATCH 10/15] Non-profit archive type was removed from Create new archive. --- .../Archives/ViewController/ArchivesViewController.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift b/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift index 63a758d9..4f505ba1 100644 --- a/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift +++ b/Permanent/Modules/Archives/ViewController/ArchivesViewController.swift @@ -97,7 +97,11 @@ class ArchivesViewController: BaseViewController { // MARK: - Actions @IBAction func createNewArchiveAction(_ sender: Any) { - let archiveTypes = ArchiveType.allCases.map { $0.archiveName } + var archiveTypes = ArchiveType.allCases.map{$0.archiveName} + + if let removeItemIdx = archiveTypes.firstIndex(of: ArchiveType.nonProfit.archiveName) { + archiveTypes.remove(at: removeItemIdx) + } self.showActionDialog( styled: .inputWithDropdown, From 18627c7e3e508ad1591cf21c76698cd8cca1d1a4 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Fri, 6 Sep 2024 11:19:42 +0300 Subject: [PATCH 11/15] The new redesigned login screen was added. --- Permanent.xcodeproj/project.pbxproj | 16 +++++ .../Screens/AuthenticatorContainerView.swift | 24 +++++++ .../Authentication/Screens/LoginView.swift | 17 +++++ .../ViewController/SignUpViewController.swift | 10 ++- .../Storyboards/Authentication.storyboard | 62 +++++++++++++++++-- 5 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift create mode 100644 Permanent/Modules/Authentication/Screens/LoginView.swift diff --git a/Permanent.xcodeproj/project.pbxproj b/Permanent.xcodeproj/project.pbxproj index aa30bb4b..f3bde700 100644 --- a/Permanent.xcodeproj/project.pbxproj +++ b/Permanent.xcodeproj/project.pbxproj @@ -317,6 +317,8 @@ 5EB620252784871B001B9AFD /* EmailProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB620242784871B001B9AFD /* EmailProfileItem.swift */; }; 5EB620272784B01D001B9AFD /* GenderProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB620262784B01D001B9AFD /* GenderProfileItem.swift */; }; 5EB620292784B038001B9AFD /* BirthInfoProfileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB620282784B038001B9AFD /* BirthInfoProfileItem.swift */; }; + 5EB66F022C872875000D4C82 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB66F012C872875000D4C82 /* LoginView.swift */; }; + 5EB66F042C872888000D4C82 /* AuthenticatorContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB66F032C872888000D4C82 /* AuthenticatorContainerView.swift */; }; 5EB721132B35C9DC0036B28F /* RedeemVO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB721122B35C9DC0036B28F /* RedeemVO.swift */; }; 5EB721152B35CDAB0036B28F /* KeyboardResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EB721142B35CDAB0036B28F /* KeyboardResponder.swift */; }; 5EBA2B8326009D92005C7B12 /* FileDetailsMapViewCellCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5EBA2B8126009D92005C7B12 /* FileDetailsMapViewCellCollectionViewCell.swift */; }; @@ -1186,6 +1188,8 @@ 5EB620242784871B001B9AFD /* EmailProfileItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailProfileItem.swift; sourceTree = ""; }; 5EB620262784B01D001B9AFD /* GenderProfileItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenderProfileItem.swift; sourceTree = ""; }; 5EB620282784B038001B9AFD /* BirthInfoProfileItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BirthInfoProfileItem.swift; sourceTree = ""; }; + 5EB66F012C872875000D4C82 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; + 5EB66F032C872888000D4C82 /* AuthenticatorContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticatorContainerView.swift; sourceTree = ""; }; 5EB721122B35C9DC0036B28F /* RedeemVO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedeemVO.swift; sourceTree = ""; }; 5EB721142B35CDAB0036B28F /* KeyboardResponder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardResponder.swift; sourceTree = ""; }; 5EBA2B8126009D92005C7B12 /* FileDetailsMapViewCellCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDetailsMapViewCellCollectionViewCell.swift; sourceTree = ""; }; @@ -2570,6 +2574,7 @@ 5E4739AE2A40FA6000A20D85 /* Authentication */ = { isa = PBXGroup; children = ( + 5EB66F052C873474000D4C82 /* Screens */, BC6D3B3F251363D600390927 /* ViewController */, ); path = Authentication; @@ -3043,6 +3048,15 @@ path = ButtonViews; sourceTree = ""; }; + 5EB66F052C873474000D4C82 /* Screens */ = { + isa = PBXGroup; + children = ( + 5EB66F032C872888000D4C82 /* AuthenticatorContainerView.swift */, + 5EB66F012C872875000D4C82 /* LoginView.swift */, + ); + path = Screens; + sourceTree = ""; + }; 5ECBAF9F2A1B5F0200FACFDF /* LegacyPlanning */ = { isa = PBXGroup; children = ( @@ -4535,6 +4549,7 @@ 5E66730D2A7927E3001C49CC /* CustomButtonStyle.swift in Sources */, BC42EDC725C011010031B965 /* Invite.swift in Sources */, BC1C7B39254861E7008E9A0D /* DateUtils.swift in Sources */, + 5EB66F042C872888000D4C82 /* AuthenticatorContainerView.swift in Sources */, F5551D88261C559B00A7C540 /* EnvVars.stencil in Sources */, BC6AF9B6259343BE00483BBA /* AccountVM.swift in Sources */, 06819AA624EC208F003D0EB0 /* CustomTextField.swift in Sources */, @@ -4664,6 +4679,7 @@ 5E5DFA6C27463602000D9924 /* ProfilePageHeaderCollectionViewCell.swift in Sources */, BC8E7947257A787D008ED0F5 /* LinkTextField.swift in Sources */, BC11C80225594ABD008BDEFA /* Model.swift in Sources */, + 5EB66F022C872875000D4C82 /* LoginView.swift in Sources */, BC752BCF253EE53000EF7941 /* FABView.swift in Sources */, 5ED3B3B029F7E0BC000CFF48 /* LegacyPlanningViewModel.swift in Sources */, F52D2B84292D44D60008D047 /* ShareManagementSharedWithCollectionViewCell.swift in Sources */, diff --git a/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift b/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift new file mode 100644 index 00000000..d392855c --- /dev/null +++ b/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift @@ -0,0 +1,24 @@ +// +// AuthenticatorContainerView.swift +// Permanent +// +// Created by Lucian Cerbu on 03.09.2024. + +import SwiftUI + +struct AuthenticatorContainerView: View { + var body: some View { + ZStack { + Gradient.darkLightBlueGradient + VStack() { + Text("Hello, World!") + .foregroundColor(.white) + } + } + .ignoresSafeArea(.all) + } +} + +#Preview { + AuthenticatorContainerView() +} diff --git a/Permanent/Modules/Authentication/Screens/LoginView.swift b/Permanent/Modules/Authentication/Screens/LoginView.swift new file mode 100644 index 00000000..82c41551 --- /dev/null +++ b/Permanent/Modules/Authentication/Screens/LoginView.swift @@ -0,0 +1,17 @@ +// +// LoginView.swift +// Permanent +// +// Created by Lucian Cerbu on 03.09.2024. + +import SwiftUI + +struct LoginView: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +#Preview { + LoginView() +} diff --git a/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift b/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift index 2e59a09d..1c071cbc 100644 --- a/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift +++ b/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift @@ -21,6 +21,7 @@ class SignUpViewController: BaseViewController { @IBOutlet weak var loginLabel: UILabel! @IBOutlet weak var separatorView: UIView! @IBOutlet weak var separatorViewHeight: NSLayoutConstraint! + @IBOutlet weak var theContainer: UIView! override func viewDidLoad() { super.viewDidLoad() @@ -29,7 +30,14 @@ class SignUpViewController: BaseViewController { viewModel = AuthViewModel() - initUI() + //initUI() + let childView = UIHostingController(rootView: AuthenticatorContainerView()) + addChild(childView) + childView.view.frame = theContainer.bounds + theContainer.addSubview(childView.view) + childView.didMove(toParent: self) + + setupNotifications() NotificationCenter.default.addObserver(forName: AccountDeleteViewModel.accountDeleteSuccessNotification, object: nil, queue: nil) { [weak self] notif in diff --git a/Permanent/Resources/Storyboards/Authentication.storyboard b/Permanent/Resources/Storyboards/Authentication.storyboard index a9cad76b..c442e9fb 100644 --- a/Permanent/Resources/Storyboards/Authentication.storyboard +++ b/Permanent/Resources/Storyboards/Authentication.storyboard @@ -1,8 +1,9 @@ - + - + + @@ -1087,12 +1088,13 @@ Cg + - + @@ -1432,6 +1434,56 @@ Cg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1439,10 +1491,10 @@ Cg - + - + From 546f6b0a6e7a9b728e7000c9a8af334a1e5b8a59 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Fri, 13 Sep 2024 17:16:31 +0300 Subject: [PATCH 12/15] New implementation using swiftUI was added for the new redesigned sign in. --- Permanent.xcodeproj/project.pbxproj | 56 +++++++ .../RoundButtonRightImageView.swift | 8 +- .../SmallRoundButtonImageView.swift | 6 +- .../TextFields/CustomBorderTextField.swift | 4 +- .../Screens/AuthLeftSideView.swift | 24 +++ .../Screens/AuthenticatorContainerView.swift | 33 +++- .../Authentication/Screens/LoginView.swift | 153 +++++++++++++++++- .../Styles/NoTapAnimationStyle.swift | 16 ++ .../ViewController/SignUpViewController.swift | 2 +- .../AuthenticatorContainerViewModel.swift | 19 +++ .../ViewModels/LoginViewModel.swift | 92 +++++++++++ .../Views/CustomLoginFormView.swift | 86 ++++++++++ .../Views/ErrorBannerView.swift | 77 +++++++++ .../Images/Authentication/Contents.json | 6 + .../authLogo.imageset/Contents.json | 12 ++ .../authLogo.imageset/authLogo.svg | 9 ++ .../Contents.json | 12 ++ .../authNotificationError.svg | 3 + .../iconauthUserPlus.imageset/Contents.json | 12 ++ .../iconauthUserPlus.svg | 3 + 20 files changed, 618 insertions(+), 15 deletions(-) create mode 100644 Permanent/Modules/Authentication/Screens/AuthLeftSideView.swift create mode 100644 Permanent/Modules/Authentication/Styles/NoTapAnimationStyle.swift create mode 100644 Permanent/Modules/Authentication/ViewModels/AuthenticatorContainerViewModel.swift create mode 100644 Permanent/Modules/Authentication/ViewModels/LoginViewModel.swift create mode 100644 Permanent/Modules/Authentication/Views/CustomLoginFormView.swift create mode 100644 Permanent/Modules/Authentication/Views/ErrorBannerView.swift create mode 100644 Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/Contents.json create mode 100644 Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/Contents.json create mode 100644 Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/authLogo.svg create mode 100644 Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/Contents.json create mode 100644 Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/authNotificationError.svg create mode 100644 Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/Contents.json create mode 100644 Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/iconauthUserPlus.svg diff --git a/Permanent.xcodeproj/project.pbxproj b/Permanent.xcodeproj/project.pbxproj index de393e7b..f415fbe3 100644 --- a/Permanent.xcodeproj/project.pbxproj +++ b/Permanent.xcodeproj/project.pbxproj @@ -49,6 +49,9 @@ 5E086BE62BEBEC91007B1AF3 /* OnboardingChartYourPathView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E086BE52BEBEC91007B1AF3 /* OnboardingChartYourPathView.swift */; }; 5E086BE82BED2572007B1AF3 /* OnboardingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E086BE72BED2572007B1AF3 /* OnboardingPath.swift */; }; 5E086BEA2BEE4408007B1AF3 /* OnboardingItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E086BE92BEE4408007B1AF3 /* OnboardingItemView.swift */; }; + 5E0AA7EF2C937561003FBCF2 /* CustomLoginFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E0AA7EE2C937561003FBCF2 /* CustomLoginFormView.swift */; }; + 5E0AA7F12C937714003FBCF2 /* ErrorBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E0AA7F02C937714003FBCF2 /* ErrorBannerView.swift */; }; + 5E0AA7F42C937747003FBCF2 /* NoTapAnimationStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E0AA7F32C937747003FBCF2 /* NoTapAnimationStyle.swift */; }; 5E0ADB8D279052A500F39E7E /* PublicProfileLocationSetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E0ADB8C279052A500F39E7E /* PublicProfileLocationSetViewController.swift */; }; 5E0B1BD42B961CE800B10BB5 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E0B1BD32B961CE800B10BB5 /* OnboardingView.swift */; }; 5E0E3C2E2886DBCA001C7F10 /* ShareExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E0E3C2D2886DBCA001C7F10 /* ShareExtensionTests.swift */; }; @@ -259,6 +262,9 @@ 5E7AE8B3291E97DA00F2A41D /* ShareManagementLinkAndShowSettingsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7AE8B1291E97DA00F2A41D /* ShareManagementLinkAndShowSettingsCollectionViewCell.swift */; }; 5E7AE8B4291E97DB00F2A41D /* ShareManagementLinkAndShowSettingsCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5E7AE8B2291E97DA00F2A41D /* ShareManagementLinkAndShowSettingsCollectionViewCell.xib */; }; 5E7C852029A39F84000DF3CA /* FABTagsManagementActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E7C851F29A39F84000DF3CA /* FABTagsManagementActionSheet.swift */; }; + 5E814A432C8F27B0005FF97C /* AuthenticatorContainerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E814A422C8F27B0005FF97C /* AuthenticatorContainerViewModel.swift */; }; + 5E814A462C8F29E3005FF97C /* LoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E814A452C8F29E3005FF97C /* LoginViewModel.swift */; }; + 5E814A482C8F34E4005FF97C /* AuthLeftSideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E814A472C8F34E4005FF97C /* AuthLeftSideView.swift */; }; 5E83CC47286C5F8D00A5775B /* ExtensionUploadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E83CC46286C5F8D00A5775B /* ExtensionUploadManager.swift */; }; 5E83CC49286C601C00A5775B /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC97A4682518E73300E43205 /* StringExtension.swift */; }; 5E83CC4A286C602000A5775B /* FileInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC62D57C254180D300E84DA9 /* FileInfo.swift */; }; @@ -987,6 +993,9 @@ 5E086BE52BEBEC91007B1AF3 /* OnboardingChartYourPathView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingChartYourPathView.swift; sourceTree = ""; }; 5E086BE72BED2572007B1AF3 /* OnboardingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingPath.swift; sourceTree = ""; }; 5E086BE92BEE4408007B1AF3 /* OnboardingItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingItemView.swift; sourceTree = ""; }; + 5E0AA7EE2C937561003FBCF2 /* CustomLoginFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomLoginFormView.swift; sourceTree = ""; }; + 5E0AA7F02C937714003FBCF2 /* ErrorBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorBannerView.swift; sourceTree = ""; }; + 5E0AA7F32C937747003FBCF2 /* NoTapAnimationStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoTapAnimationStyle.swift; sourceTree = ""; }; 5E0ADB8C279052A500F39E7E /* PublicProfileLocationSetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicProfileLocationSetViewController.swift; sourceTree = ""; }; 5E0B1BD32B961CE800B10BB5 /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = ""; }; 5E0E3C2D2886DBCA001C7F10 /* ShareExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareExtensionTests.swift; sourceTree = ""; }; @@ -1141,6 +1150,9 @@ 5E7AE8B1291E97DA00F2A41D /* ShareManagementLinkAndShowSettingsCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareManagementLinkAndShowSettingsCollectionViewCell.swift; sourceTree = ""; }; 5E7AE8B2291E97DA00F2A41D /* ShareManagementLinkAndShowSettingsCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShareManagementLinkAndShowSettingsCollectionViewCell.xib; sourceTree = ""; }; 5E7C851F29A39F84000DF3CA /* FABTagsManagementActionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FABTagsManagementActionSheet.swift; sourceTree = ""; }; + 5E814A422C8F27B0005FF97C /* AuthenticatorContainerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticatorContainerViewModel.swift; sourceTree = ""; }; + 5E814A452C8F29E3005FF97C /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = ""; }; + 5E814A472C8F34E4005FF97C /* AuthLeftSideView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthLeftSideView.swift; sourceTree = ""; }; 5E83CC46286C5F8D00A5775B /* ExtensionUploadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionUploadManager.swift; sourceTree = ""; }; 5E86DE93272852EA009A0A18 /* PasswordUpdateViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordUpdateViewController.swift; sourceTree = ""; }; 5E8A3E4A24F3AB4300812361 /* BasePageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasePageViewController.swift; sourceTree = ""; }; @@ -1856,6 +1868,23 @@ path = Pages; sourceTree = ""; }; + 5E0AA7ED2C93753F003FBCF2 /* Views */ = { + isa = PBXGroup; + children = ( + 5E0AA7EE2C937561003FBCF2 /* CustomLoginFormView.swift */, + 5E0AA7F02C937714003FBCF2 /* ErrorBannerView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 5E0AA7F22C937735003FBCF2 /* Styles */ = { + isa = PBXGroup; + children = ( + 5E0AA7F32C937747003FBCF2 /* NoTapAnimationStyle.swift */, + ); + path = Styles; + sourceTree = ""; + }; 5E0B1BD22B961CCE00B10BB5 /* Views */ = { isa = PBXGroup; children = ( @@ -2581,7 +2610,10 @@ 5E4739AE2A40FA6000A20D85 /* Authentication */ = { isa = PBXGroup; children = ( + 5E0AA7F22C937735003FBCF2 /* Styles */, + 5E0AA7ED2C93753F003FBCF2 /* Views */, 5EB66F052C873474000D4C82 /* Screens */, + 5E814A442C8F28D3005FF97C /* ViewModels */, BC6D3B3F251363D600390927 /* ViewController */, ); path = Authentication; @@ -2935,6 +2967,22 @@ path = Billing; sourceTree = ""; }; + 5E814A442C8F28D3005FF97C /* ViewModels */ = { + isa = PBXGroup; + children = ( + 5E814A422C8F27B0005FF97C /* AuthenticatorContainerViewModel.swift */, + 5E814A452C8F29E3005FF97C /* LoginViewModel.swift */, + ); + path = ViewModels; + sourceTree = ""; + }; + 5E814A492C90DDA6005FF97C /* Container */ = { + isa = PBXGroup; + children = ( + ); + path = Container; + sourceTree = ""; + }; 5E92165D2C0DC118002AACA3 /* LabelViews */ = { isa = PBXGroup; children = ( @@ -3059,7 +3107,9 @@ 5EB66F052C873474000D4C82 /* Screens */ = { isa = PBXGroup; children = ( + 5E814A492C90DDA6005FF97C /* Container */, 5EB66F032C872888000D4C82 /* AuthenticatorContainerView.swift */, + 5E814A472C8F34E4005FF97C /* AuthLeftSideView.swift */, 5EB66F012C872875000D4C82 /* LoginView.swift */, ); path = Screens; @@ -4502,6 +4552,7 @@ BCEECD8025ADC87500A4520E /* SharebyURLVOTokenPayload.swift in Sources */, 5EA03CA527832D0300CE0320 /* BasicProfileItem.swift in Sources */, 5E744F9327E38DB900A47D27 /* LoadingScreenViewController.swift in Sources */, + 5E814A462C8F29E3005FF97C /* LoginViewModel.swift in Sources */, 5E1C3C5228F0772A007C1A63 /* ManageTagsViewModel.swift in Sources */, 06644A8924EA78F5003CD359 /* ViewModelDelegateInterface.swift in Sources */, BC6E70EF252C6F5200113D5F /* ILocalAuthentication.swift in Sources */, @@ -4608,6 +4659,7 @@ 5E086BE82BED2572007B1AF3 /* OnboardingPath.swift in Sources */, F5853D2026E9FA5A0050E377 /* Permission.swift in Sources */, 5E181B822AF10100002DE69A /* GiftStorageViewModel.swift in Sources */, + 5E0AA7F12C937714003FBCF2 /* ErrorBannerView.swift in Sources */, 5E9977B0285098FD003E0C46 /* AVCaptureDeviceExtension.swift in Sources */, BCB0726225235DB9003E2F66 /* NavigationBarView.swift in Sources */, 5E1582C12C5CD7D200103EA8 /* OnboardingWhatsImportantViewModel.swift in Sources */, @@ -4926,6 +4978,7 @@ 5E37F2D52AA75248004F00E8 /* CustomDialogView.swift in Sources */, 92C73E462A14D530000EF633 /* RoundedView.swift in Sources */, F502C48926D6132F00657D37 /* AlbumCollectionViewCell.swift in Sources */, + 5E814A432C8F27B0005FF97C /* AuthenticatorContainerViewModel.swift in Sources */, 5E6CCEDF2B72BA0200D192FF /* AccountInfoViewControllerRepresentable.swift in Sources */, BC2E3BB2255AE7D700301C07 /* UISearchBarExtension.swift in Sources */, BC6AF9B32593434500483BBA /* AccessRole.swift in Sources */, @@ -4940,6 +4993,7 @@ BC4526E8251CACDF00E24A51 /* CodableHelper.swift in Sources */, 92C73E402A13BDC8000EF633 /* LegacyAccountStatusCell.swift in Sources */, BC97A4692518E73300E43205 /* StringExtension.swift in Sources */, + 5E0AA7F42C937747003FBCF2 /* NoTapAnimationStyle.swift in Sources */, 06B0EB2824E67E6A003D90C6 /* UIColor.swift in Sources */, 5E8A3E5124F3AFCE00812361 /* PageViewModelDelegateInterface.swift in Sources */, 5E7C852029A39F84000DF3CA /* FABTagsManagementActionSheet.swift in Sources */, @@ -4956,10 +5010,12 @@ 927AE0C52A260D7700BDF26A /* BannerType.swift in Sources */, 06644A8524EA7156003CD359 /* RoundedButton.swift in Sources */, 5E4455D32A08F0BB00A56235 /* TrustedStewardViewController.swift in Sources */, + 5E0AA7EF2C937561003FBCF2 /* CustomLoginFormView.swift in Sources */, BCC4067125A86E9C00E29CC4 /* AccountStatus.swift in Sources */, F54201C5265E8C4D0001444C /* RequestLinkAccessNotificationPayload.swift in Sources */, F502C48E26D6220300657D37 /* PhotoTabBarViewController.swift in Sources */, 374557E26C431EDBB0B56D68 /* FloatingActionIslandViewController.swift in Sources */, + 5E814A482C8F34E4005FF97C /* AuthLeftSideView.swift in Sources */, 5ECD1DA12C1346810049A03F /* GradientSemiCirclesLoaderView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Permanent/Common/Base/SwiftUIViews/ButtonViews/RoundButtonRightImageView.swift b/Permanent/Common/Base/SwiftUIViews/ButtonViews/RoundButtonRightImageView.swift index fb5ad006..a77bb56b 100644 --- a/Permanent/Common/Base/SwiftUIViews/ButtonViews/RoundButtonRightImageView.swift +++ b/Permanent/Common/Base/SwiftUIViews/ButtonViews/RoundButtonRightImageView.swift @@ -17,6 +17,8 @@ struct RoundButtonRightImageView: View { let text: String var rightImage: Image = Image(.rightArrowShort) let action: () -> Void + var ignoreDeviceType: Bool = false + var isPhone: Bool = true var body: some View { Button(action: action, label: { @@ -26,7 +28,7 @@ struct RoundButtonRightImageView: View { Color(.white) HStack(spacing: 16) { Spacer() - if Constants.Design.isPhone { + if Constants.Design.isPhone || (ignoreDeviceType && isPhone){ Text(text) .textStyle(UsualSmallXMediumTextStyle()) .foregroundColor(.blue700) @@ -58,7 +60,7 @@ struct RoundButtonRightImageView: View { case .noColor: ZStack { HStack() { - if Constants.Design.isPhone { + if Constants.Design.isPhone || (ignoreDeviceType && isPhone){ Text(text) .textStyle(UsualSmallXMediumTextStyle()) .foregroundColor(.white) @@ -96,7 +98,7 @@ struct RoundButtonRightImageView: View { ZStack { HStack() { Spacer() - if Constants.Design.isPhone { + if Constants.Design.isPhone || (ignoreDeviceType && isPhone){ Text(text) .textStyle(UsualSmallXMediumTextStyle()) .foregroundColor(.white) diff --git a/Permanent/Common/Base/SwiftUIViews/ButtonViews/SmallRoundButtonImageView.swift b/Permanent/Common/Base/SwiftUIViews/ButtonViews/SmallRoundButtonImageView.swift index 8e497bdc..d773c5bb 100644 --- a/Permanent/Common/Base/SwiftUIViews/ButtonViews/SmallRoundButtonImageView.swift +++ b/Permanent/Common/Base/SwiftUIViews/ButtonViews/SmallRoundButtonImageView.swift @@ -23,6 +23,8 @@ struct SmallRoundButtonImageView: View { var image: Image = Image(.rightArrowShort) var hasSpacer: Bool = false let action: () -> Void + var ignoreDeviceType: Bool = false + var isPhone: Bool = true var body: some View { Button(action: action, label: { @@ -36,7 +38,7 @@ struct SmallRoundButtonImageView: View { .frame(width: 24, height: 24, alignment: .center) .accentColor(.blue700) } - if Constants.Design.isPhone { + if Constants.Design.isPhone || (ignoreDeviceType && isPhone){ Text(text) .textStyle(UsualSmallXMediumTextStyle()) .foregroundColor(.blue700) @@ -77,7 +79,7 @@ struct SmallRoundButtonImageView: View { Spacer() } } - if Constants.Design.isPhone { + if Constants.Design.isPhone || (ignoreDeviceType && isPhone){ Text(text) .textStyle(UsualSmallXMediumTextStyle()) .foregroundColor(.white) diff --git a/Permanent/Common/Base/TextFields/CustomBorderTextField.swift b/Permanent/Common/Base/TextFields/CustomBorderTextField.swift index 6788486f..4f1e62ef 100644 --- a/Permanent/Common/Base/TextFields/CustomBorderTextField.swift +++ b/Permanent/Common/Base/TextFields/CustomBorderTextField.swift @@ -11,9 +11,11 @@ struct CustomBorderTextField: View { var placeholder: String = "Enter your text here" var preText: String = "The" var afterText: String = "Archive" + var ignoreDeviceType: Bool = false + var isPhone: Bool = true var body: some View { - if Constants.Design.isPhone { + if Constants.Design.isPhone || (ignoreDeviceType && isPhone) { HStack(alignment: .center, spacing: 8) { Text("\(preText)") .textStyle(UsualRegularTextStyle()) diff --git a/Permanent/Modules/Authentication/Screens/AuthLeftSideView.swift b/Permanent/Modules/Authentication/Screens/AuthLeftSideView.swift new file mode 100644 index 00000000..e7199572 --- /dev/null +++ b/Permanent/Modules/Authentication/Screens/AuthLeftSideView.swift @@ -0,0 +1,24 @@ +// +// AuthLeftSideView.swift +// Permanent +// +// Created by Lucian Cerbu on 09.09.2024. + +import SwiftUI + +struct AuthLeftSideView: View { + var body: some View { + VStack { + HStack { + Text("Show image") + .foregroundStyle(.white) + + } + } + + } +} + +#Preview { + AuthLeftSideView() +} diff --git a/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift b/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift index d392855c..c0a8668d 100644 --- a/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift +++ b/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift @@ -7,18 +7,39 @@ import SwiftUI struct AuthenticatorContainerView: View { + @ObservedObject var viewModel: AuthenticatorContainerViewModel + + @State private var isBack = false + @Environment(\.presentationMode) var presentationMode + var body: some View { - ZStack { - Gradient.darkLightBlueGradient - VStack() { - Text("Hello, World!") - .foregroundColor(.white) + GeometryReader { geometry in + ZStack { + Gradient.darkLightBlueGradient + HStack(spacing: 0) { + if !Constants.Design.isPhone { + AuthLeftSideView() + .frame(width: (geometry.size.width / 3) * 2) + } + LoginView(viewModel: LoginViewModel(containerViewModel: viewModel), loginSuccess: { + dismissView() + }) + .frame(maxWidth: .infinity) + } + LoadingOverlay() + .opacity(viewModel.isLoading ? 1 : 0) + .animation(.easeInOut(duration: 0.5), value: viewModel.isLoading) + .allowsHitTesting(viewModel.isLoading) } } .ignoresSafeArea(.all) } + + func dismissView() { + presentationMode.wrappedValue.dismiss() + } } #Preview { - AuthenticatorContainerView() + AuthenticatorContainerView(viewModel: AuthenticatorContainerViewModel()) } diff --git a/Permanent/Modules/Authentication/Screens/LoginView.swift b/Permanent/Modules/Authentication/Screens/LoginView.swift index 82c41551..ded4c6f0 100644 --- a/Permanent/Modules/Authentication/Screens/LoginView.swift +++ b/Permanent/Modules/Authentication/Screens/LoginView.swift @@ -7,11 +7,160 @@ import SwiftUI struct LoginView: View { + @StateObject var viewModel: LoginViewModel + @State var showEmptySpace: Bool = true + @FocusState var focusedField: LoginFocusField? + @State var keyboardOpenend: Bool = false + + var loginSuccess: (() -> Void) + var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + ZStack { + VStack(spacing: 32) { + HStack() { + Image(.authLogo) + Spacer() + } + HStack() { + Text("Sign in to\nPermanent") + .font( + .custom( + "Usual-Regular", + size: 32) + ) + .fontWeight(.light) + .lineSpacing(8) + .foregroundStyle(.white) + Spacer() + + } + .layoutPriority(1) + if showEmptySpace { + Spacer() + } + VStack(spacing: 16) { + CustomLoginFormView(username: $viewModel.username, password: $viewModel.password, focusedField: _focusedField) { + + signIn() + } + RoundButtonRightImageView(text: "Sign in", action: { + signIn() + }) + } + Button(action: { + + }, label: { + Text("Forgot password?") + .font( + .custom("Usual-Regular", size: 14) + .weight(.medium) + ) + .multilineTextAlignment(.center) + .foregroundColor(.white) + }) + HStack(spacing: 20) { + Rectangle() + .foregroundColor(.clear) + .frame(height: 1) + .background(Color(red: 0.54, green: 0.55, blue: 0.64)) + .layoutPriority(0.5) + Text("New to Permanent?".uppercased()) + .font( + .custom("Usual-Regular", size: 10)) + .kerning(1.6) + .lineLimit(1) + .multilineTextAlignment(.center) + .foregroundColor(Color(red: 0.72, green: 0.73, blue: 0.79)) + .layoutPriority(1) + Rectangle() + .foregroundColor(.clear) + .frame(height: 1) + .background(Color(red: 0.54, green: 0.55, blue: 0.64)) + .layoutPriority(0.5) + + } + SmallRoundButtonImageView(type: .noColor, imagePlace: .onRight, text: "Register", image: Image(.iconauthUserPlus), action: { + }) + .buttonStyle(NoTapAnimationStyle()) + + if !showEmptySpace { + Spacer() + .layoutPriority(0.5) + } + } + .padding(Constants.Design.isPhone ? 32 : 64) + .padding(.top, 32) + ErrorBannerView(message: viewModel.bannerErrorMessage, isVisible: $viewModel.showErrorBanner) + .padding(32) + } + .onChange(of: viewModel.loginStatus, perform: { status in + if let _ = status { + switch status { + case .success: + if AuthenticationManager.shared.session?.account.defaultArchiveID != nil { + AppDelegate.shared.rootViewController.setDrawerRoot() + } else { + let screenView = OnboardingView(viewModel: OnboardingContainerViewModel(username: viewModel.username, password: viewModel.password)) + let host = UIHostingController(rootView: screenView) + host.modalPresentationStyle = .fullScreen + AppDelegate.shared.rootViewController.present(host, animated: true) + } + viewModel.trackEvents() + loginSuccess() + + case .mfaToken: + break + default: + break + } + } + }) + .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardDidShowNotification)) { event in + if let keyboardSize = event.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { + if keyboardSize.size.height > 120 { + if !keyboardOpenend { + keyboardOpenend = true + withAnimation { + showEmptySpace = false + } + } + } + } + }.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardDidHideNotification)) { event in + if let keyboardSize = event.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { + if keyboardSize.size.height > 120 { + if keyboardOpenend && self.focusedField == nil{ + keyboardOpenend = false + withAnimation { + showEmptySpace = true + } + } + } + } + } + .onTapGesture { + withAnimation { + showEmptySpace = true + } + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + } + } + + private func signIn() { + withAnimation { + showEmptySpace = true + } + UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) + viewModel.attemptLogin() } } #Preview { - LoginView() + ZStack { + Gradient.darkLightBlueGradient + LoginView(viewModel: LoginViewModel(containerViewModel: AuthenticatorContainerViewModel()), loginSuccess: { + + }) + } + .ignoresSafeArea() } diff --git a/Permanent/Modules/Authentication/Styles/NoTapAnimationStyle.swift b/Permanent/Modules/Authentication/Styles/NoTapAnimationStyle.swift new file mode 100644 index 00000000..4377a36f --- /dev/null +++ b/Permanent/Modules/Authentication/Styles/NoTapAnimationStyle.swift @@ -0,0 +1,16 @@ +// +// NoTapAnimationStyle.swift +// Permanent +// +// Created by Lucian Cerbu on 12.09.2024. + +import SwiftUI + +struct NoTapAnimationStyle: PrimitiveButtonStyle { + func makeBody(configuration: Configuration) -> some View { + configuration.label + // Make the whole button surface tappable. Without this only content in the label is tappable and not whitespace. Order is important so add it before the tap gesture + .contentShape(Rectangle()) + .onTapGesture(perform: configuration.trigger) + } +} diff --git a/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift b/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift index 1c071cbc..52840e39 100644 --- a/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift +++ b/Permanent/Modules/Authentication/ViewController/SignUpViewController.swift @@ -31,7 +31,7 @@ class SignUpViewController: BaseViewController { viewModel = AuthViewModel() //initUI() - let childView = UIHostingController(rootView: AuthenticatorContainerView()) + let childView = UIHostingController(rootView: AuthenticatorContainerView(viewModel: AuthenticatorContainerViewModel())) addChild(childView) childView.view.frame = theContainer.bounds theContainer.addSubview(childView.view) diff --git a/Permanent/Modules/Authentication/ViewModels/AuthenticatorContainerViewModel.swift b/Permanent/Modules/Authentication/ViewModels/AuthenticatorContainerViewModel.swift new file mode 100644 index 00000000..a5f21824 --- /dev/null +++ b/Permanent/Modules/Authentication/ViewModels/AuthenticatorContainerViewModel.swift @@ -0,0 +1,19 @@ +// +// AuthenticatorContainerViewModel.swift +// Permanent +// +// Created by Lucian Cerbu on 09.09.2024. + +import Foundation +import SwiftUI + +class AuthenticatorContainerViewModel: ObservableObject { + @Published var contentType: AuthContentType = .login + @Published var firstViewContentType: AuthContentType = .login + @Published var isLoading: Bool = false +} + +enum AuthContentType { + case login + case none +} diff --git a/Permanent/Modules/Authentication/ViewModels/LoginViewModel.swift b/Permanent/Modules/Authentication/ViewModels/LoginViewModel.swift new file mode 100644 index 00000000..fa453232 --- /dev/null +++ b/Permanent/Modules/Authentication/ViewModels/LoginViewModel.swift @@ -0,0 +1,92 @@ +// +// LoginViewModel.swift +// Permanent +// +// Created by Lucian Cerbu on 09.09.2024. + +import Foundation +import SwiftUI + +class LoginViewModel: ObservableObject { + @Published var username: String = "" + @Published var password: String = "" + @Published var loginStatus: LoginStatus? + @Published var bannerErrorMessage: ErrorBannerMessage = .none + @Published var showErrorBanner: Bool = false + + var containerViewModel: AuthenticatorContainerViewModel + + init(containerViewModel: AuthenticatorContainerViewModel) { + self.containerViewModel = containerViewModel + } + + func areFieldsValid(emailField: String?, passwordField: String?) -> Bool { + return (emailField?.isNotEmpty ?? false) && (emailField?.isValidEmail ?? false) && (passwordField?.count ?? 0 >= 8) + } + + func attemptLogin() { + self.loginStatus = nil + if !areFieldsValid(emailField: username, passwordField: password) { + loginStatus = LoginStatus.error(message: "The entered data is invalid") + displayErrorBanner(bannerErrorMessage: .invalidData) + return + } + + containerViewModel.isLoading = true + login(withUsername: username, password: password, then: {[weak self] newStatus in + self?.loginStatus = newStatus + self?.containerViewModel.isLoading = false + switch newStatus { + case .error(message: let message): + self?.displayErrorBanner(bannerErrorMessage: .error) + case .unknown: + self?.displayErrorBanner(bannerErrorMessage: .invalidCredentials) + default: + break + } + }) + } + + func login(withUsername username: String?, password: String?, then handler: @escaping (LoginStatus) -> Void) { + guard let email = username, let password = password, areFieldsValid(emailField: email, passwordField: password) else { + handler(.error(message: .invalidFields)) + return + } + + AuthenticationManager.shared.login(withUsername: email, password: password) { status in + switch status { + case .success, .mfaToken, .unknown: + handler(status) + + case .error(message: _): + handler(.error(message: .errorMessage)) + } + } + } + + func trackEvents() { + EventsManager.setUserProfile(id: AuthenticationManager.shared.session?.account.accountID, + email: AuthenticationManager.shared.session?.account.primaryEmail) + EventsManager.trackEvent(event: .SignIn) + } + + func displayErrorBanner(bannerErrorMessage: ErrorBannerMessage) { + if showErrorBanner { + withAnimation { + showErrorBanner = false + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + self.bannerErrorMessage = bannerErrorMessage + withAnimation { + self.showErrorBanner = true + } + } + } else { + self.bannerErrorMessage = bannerErrorMessage + withAnimation { + showErrorBanner = true + } + } + } +} diff --git a/Permanent/Modules/Authentication/Views/CustomLoginFormView.swift b/Permanent/Modules/Authentication/Views/CustomLoginFormView.swift new file mode 100644 index 00000000..916d5d50 --- /dev/null +++ b/Permanent/Modules/Authentication/Views/CustomLoginFormView.swift @@ -0,0 +1,86 @@ +// +// CustomLoginForm.swift +// Permanent +// +// Created by Lucian Cerbu on 12.09.2024. + +import SwiftUI + +enum LoginFocusField: Hashable { + case username, password +} + +struct CustomLoginFormView: View { + @Binding var username: String + @Binding var password: String + @FocusState var focusedField: LoginFocusField? + + var onSubmit: () -> Void + + var body: some View { + VStack(spacing: 20) { + TextField("Username", text: $username) + .textStyle(UsualRegularMediumTextStyle()) + .placeholder(when: username.isEmpty) { + Text("Email address".uppercased()) + .font(.custom("Usual", size: 10)) + .kerning(1.6) + .foregroundColor(.white) + .lineLimit(1) + } + .foregroundColor(.white) + .padding(.horizontal, 24) + .padding(.vertical, 0) + .frame(height: 56, alignment: .leading) + .background(.white.opacity(0.04)) + .cornerRadius(12) + .autocorrectionDisabled() + .textInputAutocapitalization(.never) + .textContentType(.emailAddress) + .overlay( + RoundedRectangle(cornerRadius: 12) + .inset(by: 0.5) + .stroke(.white.opacity(0.16), lineWidth: 1) + ) + .focused($focusedField, equals: .username) + .submitLabel(.next) + .onSubmit { + focusedField = .password + } + .clipShape(.rect(cornerRadius: 4)) + .onTapGesture { + focusedField = .username + } + + SecureField("Password", text: $password) + .foregroundColor(.white) + .placeholder(when: password.isEmpty) { + Text("Password".uppercased()) + .font(.custom("Usual", size: 10)) + .kerning(1.6) + .foregroundColor(.white) + .lineLimit(1) + } + .padding(.horizontal, 24) + .padding(.vertical, 0) + .textContentType(.password) + .frame(height: 56, alignment: .leading) + .background(.white.opacity(0.04)) + .cornerRadius(12) + .overlay( + RoundedRectangle(cornerRadius: 12) + .inset(by: 0.5) + .stroke(.white.opacity(0.16), lineWidth: 1) + ) + .focused($focusedField, equals: .password) + .submitLabel(.continue) + .onSubmit { + onSubmit() + } + .clipShape(.rect(cornerRadius: 4)) + .onTapGesture { + focusedField = .password + } + } + } +} diff --git a/Permanent/Modules/Authentication/Views/ErrorBannerView.swift b/Permanent/Modules/Authentication/Views/ErrorBannerView.swift new file mode 100644 index 00000000..2df1c2af --- /dev/null +++ b/Permanent/Modules/Authentication/Views/ErrorBannerView.swift @@ -0,0 +1,77 @@ +// +// ErrorBannerView.swift +// Permanent +// +// Created by Lucian Cerbu on 12.09.2024. + +import SwiftUI + +enum ErrorBannerMessage { + case invalidData + case invalidCredentials + case error + case none + + var text: String { + switch self { + case .invalidData: + return "The entered data is invalid" + case .invalidCredentials: + return "Incorrect email or password." + case .error: + return .errorMessage + case .none: + return "" + } + } +} + +struct ErrorBannerView: View { + let message: ErrorBannerMessage + @Binding var isVisible: Bool + + var body: some View { + VStack(alignment: .leading) { + Spacer() + .disabled(true) + + if isVisible { + HStack(spacing: 0) { + HStack { + Group { + Image(.authNotificationError) + // Body/Regular + Text("\(message.text)") + + .font(.custom("Usual-Regular", size: 14)) + .foregroundColor(Color(red: 0.94, green: 0.27, blue: 0.22)) + } + } + Spacer() + Button(action: { + withAnimation { + isVisible = false + } + }, label: { + Text("OK") + .font(.custom("Usual-Regular", size: 14) + .weight(.medium) + ) + .foregroundColor(Color(red: 0.07, green: 0.11, blue: 0.29)) + }) + } + .padding(24) + .frame(maxWidth: .infinity) + .frame(height: 72) + .background(Color(red: 1, green: 0.89, blue: 0.89)) + .cornerRadius(12) + .shadow(color: Color(red: 0.07, green: 0.11, blue: 0.29).opacity(0.12), radius: 16, x: 0, y: 24) + .transition(.move(edge: .bottom)) // Slide in from the bottom + .animation(.easeInOut(duration: 0.3), value: isVisible) // Smooth animation + + + } + } + // .padding(.bottom, 50) // Adjust this padding as needed for the notification's position + } +} diff --git a/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/Contents.json b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/Contents.json b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/Contents.json new file mode 100644 index 00000000..cb272bfb --- /dev/null +++ b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "authLogo.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/authLogo.svg b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/authLogo.svg new file mode 100644 index 00000000..f31a777d --- /dev/null +++ b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authLogo.imageset/authLogo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/Contents.json b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/Contents.json new file mode 100644 index 00000000..5cb17c2d --- /dev/null +++ b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "authNotificationError.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/authNotificationError.svg b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/authNotificationError.svg new file mode 100644 index 00000000..ec2f0361 --- /dev/null +++ b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/authNotificationError.imageset/authNotificationError.svg @@ -0,0 +1,3 @@ + + + diff --git a/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/Contents.json b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/Contents.json new file mode 100644 index 00000000..66cc04c0 --- /dev/null +++ b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "iconauthUserPlus.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/iconauthUserPlus.svg b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/iconauthUserPlus.svg new file mode 100644 index 00000000..e8e2f5c8 --- /dev/null +++ b/Permanent/Resources/Assets/Assets.xcassets/Images/Authentication/iconauthUserPlus.imageset/iconauthUserPlus.svg @@ -0,0 +1,3 @@ + + + From 0cf8f7afa1c766a28889443baea00d62b6ee6bb3 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Mon, 16 Sep 2024 12:46:12 +0300 Subject: [PATCH 13/15] Resolved some of the issues regarding the space when keyboard appears. --- .../Screens/AuthenticatorContainerView.swift | 2 +- .../Authentication/Screens/LoginView.swift | 35 ++++++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift b/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift index c0a8668d..e3a0997e 100644 --- a/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift +++ b/Permanent/Modules/Authentication/Screens/AuthenticatorContainerView.swift @@ -19,7 +19,7 @@ struct AuthenticatorContainerView: View { HStack(spacing: 0) { if !Constants.Design.isPhone { AuthLeftSideView() - .frame(width: (geometry.size.width / 3) * 2) + .frame(width: geometry.size.width * 0.61) } LoginView(viewModel: LoginViewModel(containerViewModel: viewModel), loginSuccess: { dismissView() diff --git a/Permanent/Modules/Authentication/Screens/LoginView.swift b/Permanent/Modules/Authentication/Screens/LoginView.swift index ded4c6f0..5dfbff80 100644 --- a/Permanent/Modules/Authentication/Screens/LoginView.swift +++ b/Permanent/Modules/Authentication/Screens/LoginView.swift @@ -22,17 +22,28 @@ struct LoginView: View { Spacer() } HStack() { - Text("Sign in to\nPermanent") - .font( - .custom( - "Usual-Regular", - size: 32) - ) - .fontWeight(.light) - .lineSpacing(8) - .foregroundStyle(.white) + if Constants.Design.isPhone { + Text("Sign in to\nPermanent") + .font( + .custom( + "Usual-Regular", + size: 32) + ) + .fontWeight(.light) + .lineSpacing(8) + .foregroundStyle(.white) + } else { + Text("Sign in to Permanent") + .font( + .custom( + "Usual-Regular", + size: 32) + ) + .fontWeight(.light) + .lineSpacing(8) + .foregroundStyle(.white) + } Spacer() - } .layoutPriority(1) if showEmptySpace { @@ -89,9 +100,9 @@ struct LoginView: View { } } .padding(Constants.Design.isPhone ? 32 : 64) - .padding(.top, 32) + .padding(.top, Constants.Design.isPhone ? 32 : 0) ErrorBannerView(message: viewModel.bannerErrorMessage, isVisible: $viewModel.showErrorBanner) - .padding(32) + .padding(Constants.Design.isPhone ? 32 : 64) } .onChange(of: viewModel.loginStatus, perform: { status in if let _ = status { From c5a83156f9aaf97a6e55ac3eafbb586353d3cca0 Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Mon, 16 Sep 2024 15:48:53 +0300 Subject: [PATCH 14/15] Resolved a small issue where the bottom animation wasn't displayed correctly. --- .../Authentication/Screens/LoginView.swift | 1 - .../Views/ErrorBannerView.swift | 61 ++++++++++--------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Permanent/Modules/Authentication/Screens/LoginView.swift b/Permanent/Modules/Authentication/Screens/LoginView.swift index 5dfbff80..92fde937 100644 --- a/Permanent/Modules/Authentication/Screens/LoginView.swift +++ b/Permanent/Modules/Authentication/Screens/LoginView.swift @@ -102,7 +102,6 @@ struct LoginView: View { .padding(Constants.Design.isPhone ? 32 : 64) .padding(.top, Constants.Design.isPhone ? 32 : 0) ErrorBannerView(message: viewModel.bannerErrorMessage, isVisible: $viewModel.showErrorBanner) - .padding(Constants.Design.isPhone ? 32 : 64) } .onChange(of: viewModel.loginStatus, perform: { status in if let _ = status { diff --git a/Permanent/Modules/Authentication/Views/ErrorBannerView.swift b/Permanent/Modules/Authentication/Views/ErrorBannerView.swift index 2df1c2af..ae34de9b 100644 --- a/Permanent/Modules/Authentication/Views/ErrorBannerView.swift +++ b/Permanent/Modules/Authentication/Views/ErrorBannerView.swift @@ -34,44 +34,45 @@ struct ErrorBannerView: View { VStack(alignment: .leading) { Spacer() .disabled(true) - if isVisible { - HStack(spacing: 0) { - HStack { - Group { - Image(.authNotificationError) - // Body/Regular - Text("\(message.text)") + VStack(spacing: 0) { + HStack(spacing: 0) { + HStack { + Group { + Image(.authNotificationError) + // Body/Regular + Text("\(message.text)") - .font(.custom("Usual-Regular", size: 14)) - .foregroundColor(Color(red: 0.94, green: 0.27, blue: 0.22)) + .font(.custom("Usual-Regular", size: 14)) + .foregroundColor(Color(red: 0.94, green: 0.27, blue: 0.22)) + } } + Spacer() + Button(action: { + withAnimation { + isVisible = false + } + }, label: { + Text("OK") + .font(.custom("Usual-Regular", size: 14) + .weight(.medium) + ) + .foregroundColor(Color(red: 0.07, green: 0.11, blue: 0.29)) + }) } - Spacer() - Button(action: { - withAnimation { - isVisible = false - } - }, label: { - Text("OK") - .font(.custom("Usual-Regular", size: 14) - .weight(.medium) - ) - .foregroundColor(Color(red: 0.07, green: 0.11, blue: 0.29)) - }) + .padding(24) + .frame(maxWidth: .infinity) + .frame(height: 72) + .background(Color(red: 1, green: 0.89, blue: 0.89)) + .cornerRadius(12) + .shadow(color: Color(red: 0.07, green: 0.11, blue: 0.29).opacity(0.12), radius: 16, x: 0, y: 24) + Color.clear + .frame(height: Constants.Design.isPhone ? 32 : 64) } - .padding(24) - .frame(maxWidth: .infinity) - .frame(height: 72) - .background(Color(red: 1, green: 0.89, blue: 0.89)) - .cornerRadius(12) - .shadow(color: Color(red: 0.07, green: 0.11, blue: 0.29).opacity(0.12), radius: 16, x: 0, y: 24) .transition(.move(edge: .bottom)) // Slide in from the bottom .animation(.easeInOut(duration: 0.3), value: isVisible) // Smooth animation - - } } - // .padding(.bottom, 50) // Adjust this padding as needed for the notification's position + .padding(.horizontal, Constants.Design.isPhone ? 32 : 64) // Adjust this padding as needed for the notification's position } } From c9cd53441b55dfef5e4ad873769dcaabfb015b1c Mon Sep 17 00:00:00 2001 From: Lucian Cerbu Date: Mon, 16 Sep 2024 16:04:41 +0300 Subject: [PATCH 15/15] Added "Authentication-Redesign" branch for deploy in GitHub actions. --- .github/workflows/deployStaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deployStaging.yml b/.github/workflows/deployStaging.yml index be24b93d..b44993d5 100644 --- a/.github/workflows/deployStaging.yml +++ b/.github/workflows/deployStaging.yml @@ -3,7 +3,7 @@ name: Deploy Firebase Beta on: workflow_dispatch: push: - branches: [ "main", "feature/Onboarding-Redesign" ] + branches: [ "main", "feature/Onboarding-Redesign", "feature/Authentication-Redesign" ] jobs: build: