diff --git a/Mail/Views/Settings/Appearance/SettingsAutoAdvanceView.swift b/Mail/Views/Settings/Appearance/SettingsAutoAdvanceView.swift new file mode 100644 index 000000000..e8b29ecb8 --- /dev/null +++ b/Mail/Views/Settings/Appearance/SettingsAutoAdvanceView.swift @@ -0,0 +1,68 @@ +/* + Infomaniak Mail - iOS App + Copyright (C) 2022 Infomaniak Network SA + + 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 InfomaniakCoreUI +import InfomaniakDI +import MailCore +import MailResources +import SwiftUI + +enum AutoAdvanceSection: CaseIterable { + case compact + case regular + + var options: [AutoAdvance] { + switch self { + case .compact: + return [.previousThread, .followingThread, .listOfThread] + case .regular: + return [.previousThread, .followingThread] + } + } +} + +struct SettingsAutoAdvanceView: View { + @LazyInjectService private var matomo: MatomoUtils + + @AppStorage(UserDefaults.shared.key(.autoAdvance)) private var autoAdvance = DefaultPreferences.autoAdvance + + var section: AutoAdvanceSection + + var body: some View { + VStack { + List { + SettingsSectionTitleView(title: MailResourcesStrings.Localizable.settingsAutoAdvanceDescription) + .settingsCell() + + ForEach(section.options, id: \.rawValue) { option in + SettingsOptionCell(value: option, isSelected: option == autoAdvance, isLast: option == section.options.last) { + matomo.track(eventWithCategory: .settingsAutoAdvance, name: option.rawValue) + autoAdvance = option + } + } + } + .listStyle(.plain) + } + .background(MailResourcesAsset.backgroundColor.swiftUIColor) + .navigationTitle(MailResourcesStrings.Localizable.settingsAutoAdvanceTitle) + } +} + +#Preview { + SettingsAutoAdvanceView(section: .compact) +} diff --git a/Mail/Views/Settings/SettingsSubMenuCell.swift b/Mail/Views/Settings/SettingsSubMenuCell.swift index 2bf1ced47..a2d5387e1 100644 --- a/Mail/Views/Settings/SettingsSubMenuCell.swift +++ b/Mail/Views/Settings/SettingsSubMenuCell.swift @@ -35,6 +35,7 @@ struct SettingsSubMenuLabel: View { if let subtitle { Text(subtitle) .textStyle(.bodySmallTertiary) + .multilineTextAlignment(.leading) } } .frame(maxWidth: .infinity, alignment: .leading) diff --git a/Mail/Views/Settings/SettingsView.swift b/Mail/Views/Settings/SettingsView.swift index 5af7a142f..f5528f079 100644 --- a/Mail/Views/Settings/SettingsView.swift +++ b/Mail/Views/Settings/SettingsView.swift @@ -31,12 +31,15 @@ struct SettingsView: View { @EnvironmentObject private var mailboxManager: MailboxManager + @Environment(\.isCompactWindow) private var isCompactWindow + @AppStorage(UserDefaults.shared.key(.aiEngine)) private var aiEngine = DefaultPreferences.aiEngine @AppStorage(UserDefaults.shared.key(.threadDensity)) private var density = DefaultPreferences.threadDensity @AppStorage(UserDefaults.shared.key(.theme)) private var theme = DefaultPreferences.theme @AppStorage(UserDefaults.shared.key(.accentColor)) private var accentColor = DefaultPreferences.accentColor @AppStorage(UserDefaults.shared.key(.externalContent)) private var externalContent = DefaultPreferences.externalContent @AppStorage(UserDefaults.shared.key(.threadMode)) private var threadMode = DefaultPreferences.threadMode + @AppStorage(UserDefaults.shared.key(.autoAdvance)) private var autoAdvance = DefaultPreferences.autoAdvance @State private var isShowingSyncProfile = false @@ -173,6 +176,15 @@ struct SettingsView: View { matomoName: \.rawValue ) } + + // MARK: Auto Advance + + SettingsSubMenuCell( + title: MailResourcesStrings.Localizable.settingsAutoAdvanceTitle, + subtitle: autoAdvance.description + ) { + SettingsAutoAdvanceView(section: isCompactWindow ? .compact : .regular) + } } } } diff --git a/Mail/Views/Thread List/ThreadListCell.swift b/Mail/Views/Thread List/ThreadListCell.swift index 4dba6000c..70bca5d9a 100644 --- a/Mail/Views/Thread List/ThreadListCell.swift +++ b/Mail/Views/Thread List/ThreadListCell.swift @@ -127,8 +127,7 @@ struct ThreadListCell: View { ThreadListCell( viewModel: ThreadListViewModel(mailboxManager: PreviewHelper.sampleMailboxManager, frozenFolder: PreviewHelper.sampleFolder, - selectedThreadOwner: PreviewHelper.mockSelectedThreadOwner, - isCompact: false), + selectedThreadOwner: PreviewHelper.mockSelectedThreadOwner), multipleSelectionViewModel: ThreadListMultipleSelectionViewModel(), thread: PreviewHelper.sampleThread, threadDensity: .large, diff --git a/Mail/Views/Thread List/ThreadListView.swift b/Mail/Views/Thread List/ThreadListView.swift index c44de0ee2..12c0a056a 100644 --- a/Mail/Views/Thread List/ThreadListView.swift +++ b/Mail/Views/Thread List/ThreadListView.swift @@ -58,8 +58,7 @@ struct ThreadListView: View { isCompact: Bool) { _viewModel = StateObject(wrappedValue: ThreadListViewModel(mailboxManager: mailboxManager, frozenFolder: frozenFolder, - selectedThreadOwner: selectedThreadOwner, - isCompact: isCompact)) + selectedThreadOwner: selectedThreadOwner)) _multipleSelectionViewModel = StateObject(wrappedValue: ThreadListMultipleSelectionViewModel()) UITableViewCell.appearance().focusEffect = .none diff --git a/Mail/Views/Thread List/ThreadListViewModel.swift b/Mail/Views/Thread List/ThreadListViewModel.swift index 71f012cb8..84a06eb59 100644 --- a/Mail/Views/Thread List/ThreadListViewModel.swift +++ b/Mail/Views/Thread List/ThreadListViewModel.swift @@ -117,7 +117,6 @@ final class DateSection: Identifiable, Equatable { var filteredThreads = [Thread]() var scrollViewProxy: ScrollViewProxy? - var isCompact: Bool /// Observe a filtered thread var observeFilteredThreadsToken: NotificationToken? @@ -169,14 +168,12 @@ final class DateSection: Identifiable, Equatable { init( mailboxManager: MailboxManager, frozenFolder: Folder, - selectedThreadOwner: SelectedThreadOwnable, - isCompact: Bool + selectedThreadOwner: SelectedThreadOwnable ) { assert(frozenFolder.isFrozen, "ThreadListViewModel.folder should always be frozen") self.mailboxManager = mailboxManager self.frozenFolder = frozenFolder self.selectedThreadOwner = selectedThreadOwner - self.isCompact = isCompact sectionsObserver = sectionsSubject .receive(on: DispatchQueue.main) .sink { [weak self] newSections in @@ -218,11 +215,15 @@ final class DateSection: Identifiable, Equatable { return } - if isCompact { - selectedThreadOwner.selectedThread = nil - } else { + switch UserDefaults.shared.autoAdvance { + case .previousThread: + let validIndex = max(oldSelectedThreadIndex - 1, 0) + selectedThreadOwner.selectedThread = newThreads[validIndex] + case .followingThread: let validIndex = min(oldSelectedThreadIndex, newThreads.count - 1) selectedThreadOwner.selectedThread = newThreads[validIndex] + case .listOfThread: + selectedThreadOwner.selectedThread = nil } } diff --git a/MailCore/Models/Settings/AutoAdvance.swift b/MailCore/Models/Settings/AutoAdvance.swift new file mode 100644 index 000000000..ec557f38c --- /dev/null +++ b/MailCore/Models/Settings/AutoAdvance.swift @@ -0,0 +1,53 @@ +/* + Infomaniak Mail - iOS App + Copyright (C) 2022 Infomaniak Network SA + + 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 MailResources +import SwiftUI + +public enum AutoAdvance: String, CaseIterable, SettingsOptionEnum { + case previousThread + case followingThread + case listOfThread + + public var title: String { + switch self { + case .previousThread: + return MailResourcesStrings.Localizable.settingsAutoAdvancePreviousThreadTitle + case .followingThread: + return MailResourcesStrings.Localizable.settingsAutoAdvanceFollowingThreadTitle + case .listOfThread: + return MailResourcesStrings.Localizable.settingsAutoAdvanceListOfThreadsTitle + } + } + + public var description: String { + switch self { + case .previousThread: + return MailResourcesStrings.Localizable.settingsAutoAdvancePreviousThreadDescription + case .followingThread: + return MailResourcesStrings.Localizable.settingsAutoAdvanceFollowingThreadDescription + case .listOfThread: + return MailResourcesStrings.Localizable.settingsAutoAdvanceListOfThreadsDescription + } + } + + public var image: Image? { + return nil + } +} diff --git a/MailCore/Models/Settings/DefaultPreferences.swift b/MailCore/Models/Settings/DefaultPreferences.swift index 62707a174..252f02529 100644 --- a/MailCore/Models/Settings/DefaultPreferences.swift +++ b/MailCore/Models/Settings/DefaultPreferences.swift @@ -17,6 +17,7 @@ */ import Foundation +import UIKit public enum DefaultPreferences { public static let notificationsEnabled = true @@ -38,4 +39,5 @@ public enum DefaultPreferences { public static let featureFlags: FeatureFlagsManageable.AppFeatureFlags = [:] public static let shouldPresentAIFeature = true public static let aiEngine = AIEngine.falcon + public static let autoAdvance = UIDevice.current.userInterfaceIdiom == .pad ? AutoAdvance.followingThread : AutoAdvance.listOfThread } diff --git a/MailCore/Utils/MailUserDefaults+Extension.swift b/MailCore/Utils/MailUserDefaults+Extension.swift index ce6523f73..e685d44f9 100644 --- a/MailCore/Utils/MailUserDefaults+Extension.swift +++ b/MailCore/Utils/MailUserDefaults+Extension.swift @@ -51,6 +51,7 @@ public extension UserDefaults.Keys { static let shouldPresentSyncDiscovery = UserDefaults.Keys(rawValue: "shouldPresentSyncDiscovery") static let shouldPresentSetAsDefaultDiscovery = UserDefaults.Keys(rawValue: "shouldPresentSetAsDefaultDiscovery") static let aiEngine = UserDefaults.Keys(rawValue: "aiEngine") + static let autoAdvance = UserDefaults.Keys(rawValue: "autoAdvance") } public extension UserDefaults { @@ -313,4 +314,13 @@ public extension UserDefaults { setValue(newValue.rawValue, forKey: key(.aiEngine)) } } + + var autoAdvance: AutoAdvance { + get { + return AutoAdvance(rawValue: string(forKey: key(.autoAdvance)) ?? "") ?? DefaultPreferences.autoAdvance + } + set { + set(newValue.rawValue, forKey: key(.autoAdvance)) + } + } } diff --git a/MailCore/Utils/Matomo+Extension.swift b/MailCore/Utils/Matomo+Extension.swift index 87e51d025..6542697f5 100644 --- a/MailCore/Utils/Matomo+Extension.swift +++ b/MailCore/Utils/Matomo+Extension.swift @@ -86,6 +86,7 @@ public extension MatomoUtils.EventCategory { static let settingsSend = MatomoUtils.EventCategory(displayName: "settingsSend") static let settingsSwipeActions = MatomoUtils.EventCategory(displayName: "settingsSwipeActions") static let settingsThreadMode = MatomoUtils.EventCategory(displayName: "settingsThreadMode") + static let settingsAutoAdvance = MatomoUtils.EventCategory(displayName: "settingsAutoAdvance") } // MARK: - Helpers diff --git a/MailResources/Localizable/de.lproj/Localizable.strings b/MailResources/Localizable/de.lproj/Localizable.strings index ef55b7557..f50b7daf3 100644 --- a/MailResources/Localizable/de.lproj/Localizable.strings +++ b/MailResources/Localizable/de.lproj/Localizable.strings @@ -1103,6 +1103,30 @@ /* loco:627a306b1e32027c033896b2 */ "settingsAppLock" = "App-Sperre"; +/* loco:65b275e7c53c28d1410bf342 */ +"settingsAutoAdvanceDescription" = "Auswählen, was angezeigt werden soll, wenn eine Nachricht archiviert oder gelöscht wird"; + +/* loco:65b27dc325bc06589501c462 */ +"settingsAutoAdvanceFollowingThreadDescription" = "Beim Archivieren oder Löschen folgenden Thread anzeigen\n"; + +/* loco:65b277d399fe1ebac10546a2 */ +"settingsAutoAdvanceFollowingThreadTitle" = "Folgender Thread"; + +/* loco:65b27e2b4f176d33ca06b302 */ +"settingsAutoAdvanceListOfThreadsDescription" = "Liste der Threads beim Archivieren oder Löschen anzeigen"; + +/* loco:65b2780c2b7256da8b038512 */ +"settingsAutoAdvanceListOfThreadsTitle" = "Liste der Themen"; + +/* loco:65b27d1e0565d99b930ae142 */ +"settingsAutoAdvancePreviousThreadDescription" = "Vorheriges Thema beim Archivieren oder Löschen anzeigen"; + +/* loco:65b277b504a5c5b4710041f3 */ +"settingsAutoAdvancePreviousThreadTitle" = "Voriges Thema"; + +/* loco:65b274f8719e4e08b103c7f4 */ +"settingsAutoAdvanceTitle" = "Autovorschuss"; + /* loco:62c693f572adfe66fd2a82b7 */ "settingsCancellationPeriodDescription" = "Sie haben die Möglichkeit, den Versand Ihrer E-Mail bis zu 30 Sekunden abzubrechen"; @@ -1412,6 +1436,9 @@ /* loco:626664d06926336d9e25c462 */ "subjectTitle" = "Thema:"; +/* loco:65ba2326ef9447c160013bf2 */ +"superCollapsedBlock" = "Alle sehen (%d)"; + /* loco:653112b14b84af451706ef56 */ "syncCalendarsAndContactsDescription" = "Sehen Sie sich Ihre Kontakte und Kalender direkt auf Ihrem Gerät an."; diff --git a/MailResources/Localizable/en.lproj/Localizable.strings b/MailResources/Localizable/en.lproj/Localizable.strings index 446fe67d2..787c6bb3b 100644 --- a/MailResources/Localizable/en.lproj/Localizable.strings +++ b/MailResources/Localizable/en.lproj/Localizable.strings @@ -1103,6 +1103,30 @@ /* loco:627a306b1e32027c033896b2 */ "settingsAppLock" = "App lock"; +/* loco:65b275e7c53c28d1410bf342 */ +"settingsAutoAdvanceDescription" = "Select what to display when a message is archived or deleted "; + +/* loco:65b27dc325bc06589501c462 */ +"settingsAutoAdvanceFollowingThreadDescription" = "Display following thread when archiving or deleting\n"; + +/* loco:65b277d399fe1ebac10546a2 */ +"settingsAutoAdvanceFollowingThreadTitle" = "Following thread"; + +/* loco:65b27e2b4f176d33ca06b302 */ +"settingsAutoAdvanceListOfThreadsDescription" = "Display list of threads when archiving or deleting"; + +/* loco:65b2780c2b7256da8b038512 */ +"settingsAutoAdvanceListOfThreadsTitle" = "List of threads"; + +/* loco:65b27d1e0565d99b930ae142 */ +"settingsAutoAdvancePreviousThreadDescription" = "Display previous thread when archiving or deleting"; + +/* loco:65b277b504a5c5b4710041f3 */ +"settingsAutoAdvancePreviousThreadTitle" = "Previous thread"; + +/* loco:65b274f8719e4e08b103c7f4 */ +"settingsAutoAdvanceTitle" = "Auto advance"; + /* loco:62c693f572adfe66fd2a82b7 */ "settingsCancellationPeriodDescription" = "You have the possibility to cancel the sending of your email up to 30 seconds"; @@ -1412,6 +1436,9 @@ /* loco:626664d06926336d9e25c462 */ "subjectTitle" = "Subject:"; +/* loco:65ba2326ef9447c160013bf2 */ +"superCollapsedBlock" = "See all (%d)"; + /* loco:653112b14b84af451706ef56 */ "syncCalendarsAndContactsDescription" = "View your contacts and calendar directly from your device."; diff --git a/MailResources/Localizable/es.lproj/Localizable.strings b/MailResources/Localizable/es.lproj/Localizable.strings index 6ae653090..7f973bcc6 100644 --- a/MailResources/Localizable/es.lproj/Localizable.strings +++ b/MailResources/Localizable/es.lproj/Localizable.strings @@ -1103,6 +1103,30 @@ /* loco:627a306b1e32027c033896b2 */ "settingsAppLock" = "Bloqueo de aplicaciones"; +/* loco:65b275e7c53c28d1410bf342 */ +"settingsAutoAdvanceDescription" = "Seleccione qué mostrar cuando se archiva o elimina un mensaje"; + +/* loco:65b27dc325bc06589501c462 */ +"settingsAutoAdvanceFollowingThreadDescription" = "Mostrar el siguiente hilo al archivar o borrar\n"; + +/* loco:65b277d399fe1ebac10546a2 */ +"settingsAutoAdvanceFollowingThreadTitle" = "Siguiendo el hilo"; + +/* loco:65b27e2b4f176d33ca06b302 */ +"settingsAutoAdvanceListOfThreadsDescription" = "Mostrar lista de hilos al archivar o borrar"; + +/* loco:65b2780c2b7256da8b038512 */ +"settingsAutoAdvanceListOfThreadsTitle" = "Lista de temas"; + +/* loco:65b27d1e0565d99b930ae142 */ +"settingsAutoAdvancePreviousThreadDescription" = "Mostrar el hilo anterior al archivar o borrar"; + +/* loco:65b277b504a5c5b4710041f3 */ +"settingsAutoAdvancePreviousThreadTitle" = "Tema anterior"; + +/* loco:65b274f8719e4e08b103c7f4 */ +"settingsAutoAdvanceTitle" = "Auto advance"; + /* loco:62c693f572adfe66fd2a82b7 */ "settingsCancellationPeriodDescription" = "Tiene la posibilidad de cancelar el envío de su correo electrónico hasta 30 segundos"; @@ -1412,6 +1436,9 @@ /* loco:626664d06926336d9e25c462 */ "subjectTitle" = "Asunto:"; +/* loco:65ba2326ef9447c160013bf2 */ +"superCollapsedBlock" = "Ver todos (%d)"; + /* loco:653112b14b84af451706ef56 */ "syncCalendarsAndContactsDescription" = "Consulta tus contactos y tu calendario directamente desde tu dispositivo."; diff --git a/MailResources/Localizable/fr.lproj/Localizable.strings b/MailResources/Localizable/fr.lproj/Localizable.strings index 55651e603..76452de37 100644 --- a/MailResources/Localizable/fr.lproj/Localizable.strings +++ b/MailResources/Localizable/fr.lproj/Localizable.strings @@ -1103,6 +1103,30 @@ /* loco:627a306b1e32027c033896b2 */ "settingsAppLock" = "Verrouillage de l’application"; +/* loco:65b275e7c53c28d1410bf342 */ +"settingsAutoAdvanceDescription" = "Sélectionnez ce que vous souhaitez afficher lorsqu’un message est archivé ou supprimé "; + +/* loco:65b27dc325bc06589501c462 */ +"settingsAutoAdvanceFollowingThreadDescription" = "Afficher la conversation suivante après archivage ou suppression"; + +/* loco:65b277d399fe1ebac10546a2 */ +"settingsAutoAdvanceFollowingThreadTitle" = "Conversation suivante"; + +/* loco:65b27e2b4f176d33ca06b302 */ +"settingsAutoAdvanceListOfThreadsDescription" = "Afficher la liste des conversations après archivage ou suppression"; + +/* loco:65b2780c2b7256da8b038512 */ +"settingsAutoAdvanceListOfThreadsTitle" = "Liste des conversations"; + +/* loco:65b27d1e0565d99b930ae142 */ +"settingsAutoAdvancePreviousThreadDescription" = "Afficher la conversation précédente après archivage ou suppression"; + +/* loco:65b277b504a5c5b4710041f3 */ +"settingsAutoAdvancePreviousThreadTitle" = "Conversation précédente"; + +/* loco:65b274f8719e4e08b103c7f4 */ +"settingsAutoAdvanceTitle" = "Avance Automatique"; + /* loco:62c693f572adfe66fd2a82b7 */ "settingsCancellationPeriodDescription" = "Vous avez la possibilité d’annuler l’envoi de votre e-mail jusqu’à 30 secondes"; @@ -1412,6 +1436,9 @@ /* loco:626664d06926336d9e25c462 */ "subjectTitle" = "Objet :"; +/* loco:65ba2326ef9447c160013bf2 */ +"superCollapsedBlock" = "Voir tout (%d)"; + /* loco:653112b14b84af451706ef56 */ "syncCalendarsAndContactsDescription" = "Consultez vos contacts et calendriers directement depuis votre appareil."; diff --git a/MailResources/Localizable/it.lproj/Localizable.strings b/MailResources/Localizable/it.lproj/Localizable.strings index 558e2271b..754b1fcfd 100644 --- a/MailResources/Localizable/it.lproj/Localizable.strings +++ b/MailResources/Localizable/it.lproj/Localizable.strings @@ -1103,6 +1103,30 @@ /* loco:627a306b1e32027c033896b2 */ "settingsAppLock" = "Blocco dell’app"; +/* loco:65b275e7c53c28d1410bf342 */ +"settingsAutoAdvanceDescription" = "Selezionare cosa visualizzare quando un messaggio viene archiviato o eliminato"; + +/* loco:65b27dc325bc06589501c462 */ +"settingsAutoAdvanceFollowingThreadDescription" = "Visualizza la seguente discussione quando si archivia o si elimina\n"; + +/* loco:65b277d399fe1ebac10546a2 */ +"settingsAutoAdvanceFollowingThreadTitle" = "Seguendo il filo conduttore"; + +/* loco:65b27e2b4f176d33ca06b302 */ +"settingsAutoAdvanceListOfThreadsDescription" = "Visualizzazione dell’elenco delle discussioni durante l’archiviazione o la cancellazione"; + +/* loco:65b2780c2b7256da8b038512 */ +"settingsAutoAdvanceListOfThreadsTitle" = "Elenco delle discussioni"; + +/* loco:65b27d1e0565d99b930ae142 */ +"settingsAutoAdvancePreviousThreadDescription" = "Visualizzazione della discussione precedente quando si archivia o si elimina"; + +/* loco:65b277b504a5c5b4710041f3 */ +"settingsAutoAdvancePreviousThreadTitle" = "Filo conduttore precedente"; + +/* loco:65b274f8719e4e08b103c7f4 */ +"settingsAutoAdvanceTitle" = "Anticipo auto"; + /* loco:62c693f572adfe66fd2a82b7 */ "settingsCancellationPeriodDescription" = "Avete la possibilità di annullare l’invio della vostra email fino a 30 secondi."; @@ -1412,6 +1436,9 @@ /* loco:626664d06926336d9e25c462 */ "subjectTitle" = "Oggetto:"; +/* loco:65ba2326ef9447c160013bf2 */ +"superCollapsedBlock" = "Vedi tutti (%d)"; + /* loco:653112b14b84af451706ef56 */ "syncCalendarsAndContactsDescription" = "Visualizza i contatti e il calendario direttamente dal dispositivo.";