diff --git a/.locale-state.metadata b/.locale-state.metadata index 06fd79d6ba..ce26be8eb4 100644 --- a/.locale-state.metadata +++ b/.locale-state.metadata @@ -1,4 +1,4 @@ { "project": "apple-mail-new", - "locale": "c6e4f8631d24ac1b10b5a6c3f3e71f8f1cbe68e8" + "locale": "5de0ac2b963308bb91a25e069a2ce18a605a6f40" } \ No newline at end of file diff --git a/Modules/App/Sources/Resources/InfoPlist.xcstrings b/Modules/App/Sources/Resources/InfoPlist.xcstrings index 0af09b3256..c931204760 100644 --- a/Modules/App/Sources/Resources/InfoPlist.xcstrings +++ b/Modules/App/Sources/Resources/InfoPlist.xcstrings @@ -964,6 +964,24 @@ "state" : "translated", "value" : "Required to save files in your Photos app." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Necesario para guardar archivos en tu aplicación Fotos." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nécessaire pour enregistrer des fichiers dans votre application Photos." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "お客様のフォトアプリにファイルを保存するために必要です。" + } } } } diff --git a/Modules/App/Sources/Resources/Localizable.xcstrings b/Modules/App/Sources/Resources/Localizable.xcstrings index 205691f3e7..ec5bcc3963 100644 --- a/Modules/App/Sources/Resources/Localizable.xcstrings +++ b/Modules/App/Sources/Resources/Localizable.xcstrings @@ -203,6 +203,42 @@ "state" : "new", "value" : "%1$@ of %2$@" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ de %2$@" + } + }, + "es-419" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ de %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ De %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%2$@ の中の%1$@" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ van %2$@" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ av %2$@" + } } } }, @@ -5110,6 +5146,112 @@ } } } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@" + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Conversación movida al archivo." + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Conversaciones movidas al archivo." + } + } + } + } + } + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@." + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "La conversation a été déplacée dans les Archives" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Les conversations ont été déplacées dans les Archives." + } + } + } + } + } + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@" + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "会話をアーカイブに移動しました。" + } + } + } + } + } + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@" + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konversation flyttad till arkiv." + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Konversationer flyttade till arkiv." + } + } + } + } + } + } } } }, @@ -10565,6 +10707,112 @@ } } } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@" + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mensaje movido al archivo." + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mensajes movidos al Archivo." + } + } + } + } + } + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@." + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le message a été déplacé dans les Archives." + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Les messages ont été déplacés dans les Archives." + } + } + } + } + } + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@" + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "メッセージをアーカイブに移動しました。" + } + } + } + } + } + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "%#@arg1@" + }, + "substitutions" : { + "arg1" : { + "argNum" : 1, + "formatSpecifier" : "lld", + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meddelande flyttat till arkiv." + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meddelanden flyttade till arkiv." + } + } + } + } + } + } } } }, diff --git a/Modules/App/Sources/State/MailSettingsLiveQuery.swift b/Modules/App/Sources/State/MailSettingsLiveQuery.swift index e8ee3db301..d6d8287a4c 100644 --- a/Modules/App/Sources/State/MailSettingsLiveQuery.swift +++ b/Modules/App/Sources/State/MailSettingsLiveQuery.swift @@ -16,6 +16,7 @@ // along with Proton Mail. If not, see https://www.gnu.org/licenses/. import Combine +import Foundation import InboxCore import proton_app_uniffi @@ -59,6 +60,7 @@ final class MailSettingsLiveQuery: MailSettingLiveQuerying { .map(keyPath) .removeDuplicates() .dropFirst() + .debounce(for: .milliseconds(100), scheduler: DispatchQueue.main) .eraseToAnyPublisher() } diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBar.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbar.swift similarity index 87% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBar.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbar.swift index cd86591995..828220637e 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBar.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbar.swift @@ -21,15 +21,15 @@ import proton_app_uniffi import SwiftUI extension View { - func mailboxActionBar( - state: MailboxActionBarState, - availableActions: AvailableMailboxActionBarActions, + func listActionsToolbar( + state: ListActionsToolbarState, + availableActions: AvailableListToolbarActions, itemTypeForActionBar: MailboxItemType, mailUserSession: MailUserSession, selectedItems: Binding> ) -> some View { modifier( - MailboxActionBarViewModifier( + ListActionBarViewModifier( state: state, availableActions: availableActions, itemTypeForActionBar: itemTypeForActionBar, @@ -39,13 +39,13 @@ extension View { } } -private struct MailboxActionBarViewModifier: ViewModifier { +private struct ListActionBarViewModifier: ViewModifier { @Binding var selectedItems: Set @EnvironmentObject var mailbox: Mailbox @EnvironmentObject var toastStateStore: ToastStateStore - private let state: MailboxActionBarState + private let state: ListActionsToolbarState private let itemTypeForActionBar: MailboxItemType - private let availableActions: AvailableMailboxActionBarActions + private let availableActions: AvailableListToolbarActions private let deleteActions: DeleteActions private let moveToActions: MoveToActions private let mailUserSession: MailUserSession @@ -53,8 +53,8 @@ private struct MailboxActionBarViewModifier: ViewModifier { private let readActionPerformerActions: ReadActionPerformerActions init( - state: MailboxActionBarState, - availableActions: AvailableMailboxActionBarActions, + state: ListActionsToolbarState, + availableActions: AvailableListToolbarActions, starActionPerformerActions: StarActionPerformerActions = .productionInstance, readActionPerformerActions: ReadActionPerformerActions = .productionInstance, deleteActions: DeleteActions = .productionInstance, @@ -76,7 +76,7 @@ private struct MailboxActionBarViewModifier: ViewModifier { func body(content: Content) -> some View { StoreView( - store: MailboxActionBarStateStore( + store: ListActionsToolbarStore( state: state, availableActions: availableActions, starActionPerformerActions: starActionPerformerActions, @@ -96,11 +96,11 @@ private struct MailboxActionBarViewModifier: ViewModifier { .bottomToolbarStyle() .onChange(of: selectedItems) { oldValue, newValue in if oldValue != newValue { - store.handle(action: .mailboxItemsSelectionUpdated(ids: selectedItemsIDs)) + store.handle(action: .listItemsSelectionUpdated(ids: selectedItemsIDs)) } } .onLoad { - store.handle(action: .mailboxItemsSelectionUpdated(ids: selectedItemsIDs)) + store.handle(action: .listItemsSelectionUpdated(ids: selectedItemsIDs)) } .labelAsSheet( mailbox: { mailbox }, @@ -114,7 +114,7 @@ private struct MailboxActionBarViewModifier: ViewModifier { navigation: { _ in } ) .sheet(item: store.binding(\.moreActionSheetPresented)) { state in - MailboxActionBarMoreSheet(state: state) { action in + ListActionsToolbarMoreSheet(state: state) { action in store.handle(action: .moreSheetAction(action, ids: selectedItemsIDs)) } editToolbarTapped: { // FIXME: - Edit toolbar action @@ -141,8 +141,8 @@ private struct MailboxActionBarViewModifier: ViewModifier { } private func toolbarContent( - state: MailboxActionBarState, - store: MailboxActionBarStateStore + state: ListActionsToolbarState, + store: ListActionsToolbarStore ) -> some ToolbarContent { ToolbarItemGroup(placement: .bottomBar) { HStack { @@ -151,7 +151,7 @@ private struct MailboxActionBarViewModifier: ViewModifier { Spacer() } Button(action: { store.handle(action: .actionSelected(action, ids: selectedItemsIDs)) }) { - action.displayData.icon + action.displayData.image .foregroundStyle(DS.Color.Icon.weak) } .accessibilityIdentifier(MailboxActionBarViewIdentifiers.button(index: index)) diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarActionsProvider.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarActionsProvider.swift similarity index 60% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarActionsProvider.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarActionsProvider.swift index bdde05e017..bc70afcd26 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarActionsProvider.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarActionsProvider.swift @@ -17,12 +17,12 @@ import proton_app_uniffi -struct MailboxActionBarActionsProvider { - let availableActions: AvailableMailboxActionBarActions +struct ListActionsToolbarActionsProvider { + let availableActions: AvailableListToolbarActions let itemTypeForActionBar: MailboxItemType let mailbox: Mailbox - func actions(forItemsWith ids: [ID]) async -> AllBottomBarMessageActions { + func actions(forItemsWith ids: [ID]) async -> AllListActions { switch itemTypeForActionBar { case .message: try! await availableActions.message(mailbox, ids).get() @@ -32,21 +32,21 @@ struct MailboxActionBarActionsProvider { } } -struct AvailableMailboxActionBarActions { - let message: MessageBottomBarActionsProvider - let conversation: ConversationBottomBarActionsProvider +struct AvailableListToolbarActions { + let message: MessageListActionsToolbarActionsProvider + let conversation: ConversationListActionsToolbarActionsProvider } -extension AvailableMailboxActionBarActions { +extension AvailableListToolbarActions { static var productionInstance: Self { .init( - message: allAvailableBottomBarActionsForMessages, - conversation: allAvailableBottomBarActionsForConversations + message: allAvailableListActionsForMessages, + conversation: allAvailableListActionsForConversations ) } } -typealias MessageBottomBarActionsProvider = (Mailbox, [Id]) async -> AllAvailableBottomBarActionsForMessagesResult -typealias ConversationBottomBarActionsProvider = (Mailbox, [Id]) async -> AllAvailableBottomBarActionsForConversationsResult +typealias MessageListActionsToolbarActionsProvider = (Mailbox, [Id]) async -> AllAvailableListActionsForMessagesResult +typealias ConversationListActionsToolbarActionsProvider = (Mailbox, [Id]) async -> AllAvailableListActionsForConversationsResult diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarMoreSheet.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarMoreSheet.swift similarity index 79% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarMoreSheet.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarMoreSheet.swift index 9b14a84424..db669bf6c0 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarMoreSheet.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarMoreSheet.swift @@ -15,18 +15,19 @@ // You should have received a copy of the GNU General Public License // along with Proton Mail. If not, see https://www.gnu.org/licenses/. +import proton_app_uniffi import InboxCoreUI import InboxDesignSystem import SwiftUI -struct MailboxActionBarMoreSheet: View { - let state: MailboxActionBarMoreSheetState - let actionTapped: (BottomBarAction) -> Void +struct ListActionsToolbarMoreSheet: View { + let state: ListActionsToolbarMoreSheetState + let actionTapped: (ListActions) -> Void let editToolbarTapped: () -> Void init( - state: MailboxActionBarMoreSheetState, - actionTapped: @escaping (BottomBarAction) -> Void, + state: ListActionsToolbarMoreSheetState, + actionTapped: @escaping (ListActions) -> Void, editToolbarTapped: @escaping () -> Void ) { self.state = state @@ -54,11 +55,11 @@ struct MailboxActionBarMoreSheet: View { // MARK: - Private - private func section(content: [BottomBarAction]) -> some View { + private func section(content: [ListActions]) -> some View { ActionSheetSection { ForEachLast(collection: content) { action, isLast in ActionSheetImageButton( - displayData: action.actionDisplayData, + displayData: action.displayData, displayBottomSeparator: !isLast, action: { actionTapped(action) } ) @@ -79,15 +80,9 @@ struct MailboxActionBarMoreSheet: View { } -private extension BottomBarAction { - var actionDisplayData: ActionDisplayData { - .init(title: displayData.name.unsafelyUnwrapped, image: displayData.icon) - } -} - #Preview { - MailboxActionBarMoreSheet( - state: MailboxActionBarMoreSheetPreviewProvider.state(), + ListActionsToolbarMoreSheet( + state: ListActionsToolbarMoreSheetPreviewProvider.state(), actionTapped: { _ in }, editToolbarTapped: {} ) diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarMoreSheetPreviewProvider.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarMoreSheetPreviewProvider.swift similarity index 89% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarMoreSheetPreviewProvider.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarMoreSheetPreviewProvider.swift index 6f859e65d1..8e19c22843 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarMoreSheetPreviewProvider.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarMoreSheetPreviewProvider.swift @@ -17,9 +17,9 @@ import Foundation -enum MailboxActionBarMoreSheetPreviewProvider { +enum ListActionsToolbarMoreSheetPreviewProvider { - static func state() -> MailboxActionBarMoreSheetState { + static func state() -> ListActionsToolbarMoreSheetState { .init( selectedItemsIDs: [.init(value: 1), .init(value: 2), .init(value: 3)], bottomBarActions: [ @@ -27,12 +27,12 @@ enum MailboxActionBarMoreSheetPreviewProvider { .moveToSystemFolder(.init(localId: .init(value: 4), name: .archive)), .moveToSystemFolder(.init(localId: .init(value: 5), name: .inbox)), .moveToSystemFolder(.init(localId: .init(value: 6), name: .trash)), - .star + .star, ], moreSheetOnlyActions: [ .labelAs, .moveTo, - .moveToSystemFolder(.init(localId: .init(value: 7), name: .spam)) + .moveToSystemFolder(.init(localId: .init(value: 7), name: .spam)), ] ) } diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarStateStore.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarStore.swift similarity index 90% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarStateStore.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarStore.swift index be59322c9e..77ebf8715c 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/MailboxActionBarStateStore.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/ListActionsToolbarStore.swift @@ -20,10 +20,10 @@ import InboxCoreUI import proton_app_uniffi import SwiftUI -final class MailboxActionBarStateStore: StateStore { - @Published var state: MailboxActionBarState +final class ListActionsToolbarStore: StateStore { + @Published var state: ListActionsToolbarState - private let actionsProvider: MailboxActionBarActionsProvider + private let actionsProvider: ListActionsToolbarActionsProvider private let starActionPerformer: StarActionPerformer private let readActionPerformer: ReadActionPerformer private let deleteActionsPerformer: DeleteActionPerformer @@ -33,8 +33,8 @@ final class MailboxActionBarStateStore: StateStore { private let mailUserSession: MailUserSession init( - state: MailboxActionBarState, - availableActions: AvailableMailboxActionBarActions, + state: ListActionsToolbarState, + availableActions: AvailableListToolbarActions, starActionPerformerActions: StarActionPerformerActions, readActionPerformerActions: ReadActionPerformerActions, deleteActions: DeleteActions, @@ -65,9 +65,9 @@ final class MailboxActionBarStateStore: StateStore { self.toastStateStore = toastStateStore } - func handle(action: MailboxActionBarAction) { + func handle(action: ListActionsToolbarAction) { switch action { - case .mailboxItemsSelectionUpdated(let ids): + case .listItemsSelectionUpdated(let ids): fetchAvailableBottomBarActions(for: ids) case .actionSelected(let action, let ids): handle(action: action, ids: ids) @@ -84,10 +84,10 @@ final class MailboxActionBarStateStore: StateStore { // MARK: - Private - private func handle(action: BottomBarActions, ids: [ID]) { + private func handle(action: ListActions, ids: [ID]) { switch action { case .more: - let moreActionSheetState = MailboxActionBarMoreSheetState( + let moreActionSheetState = ListActionsToolbarMoreSheetState( selectedItemsIDs: ids, bottomBarActions: state.bottomBarActions.moreActionFiltered, moreSheetOnlyActions: state.moreSheetOnlyActions @@ -118,7 +118,7 @@ final class MailboxActionBarStateStore: StateStore { dismissMoreActionSheet() readActionPerformer.markAsUnread(itemsWithIDs: ids, itemType: itemTypeForActionBar) case .permanentDelete: - let keyPath: WritableKeyPath = + let keyPath: WritableKeyPath = state.moreActionSheetPresented != nil ? \.moreDeleteConfirmationAlert : \.deleteConfirmationAlert let alert: AlertModel = .deleteConfirmation( itemsCount: ids.count, @@ -190,11 +190,11 @@ final class MailboxActionBarStateStore: StateStore { } } - private func updateActions(actions: AllBottomBarMessageActions) { + private func updateActions(actions: AllListActions) { state = state - .copy(\.bottomBarActions, to: actions.visibleBottomBarActions) - .copy(\.moreSheetOnlyActions, to: actions.hiddenBottomBarActions) + .copy(\.bottomBarActions, to: actions.visibleListActions) + .copy(\.moreSheetOnlyActions, to: actions.hiddenListActions) } private func dismissMoreActionSheet() { @@ -230,7 +230,7 @@ final class MailboxActionBarStateStore: StateStore { } } -private extension Array where Element == BottomBarActions { +private extension Array where Element == ListActions { var moreActionFiltered: Self { filter { $0 != .more } diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/AllBottomBarMessageActions+TestData.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/AllListActions+TestData.swift similarity index 87% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/AllBottomBarMessageActions+TestData.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/AllListActions+TestData.swift index 3e3ba48a0f..22599284a5 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/AllBottomBarMessageActions+TestData.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/AllListActions+TestData.swift @@ -17,16 +17,16 @@ import proton_app_uniffi -extension AllBottomBarMessageActions { +extension AllListActions { static var testData: Self { .init( - hiddenBottomBarActions: [ + hiddenListActions: [ .notSpam(.testInbox), .permanentDelete, .moveToSystemFolder(.init(localId: .init(value: 7), name: .archive)) ], - visibleBottomBarActions: [.markRead, .star, .moveTo, .labelAs, .more] + visibleListActions: [.markRead, .star, .moveTo, .labelAs, .more] ) } diff --git a/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActions+ActionDisplayData.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActions+ActionDisplayData.swift new file mode 100644 index 0000000000..91b963f345 --- /dev/null +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActions+ActionDisplayData.swift @@ -0,0 +1,66 @@ +// Copyright (c) 2024 Proton Technologies AG +// +// This file is part of Proton Mail. +// +// Proton Mail 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. +// +// Proton Mail 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 Proton Mail. If not, see https://www.gnu.org/licenses/. + +import proton_app_uniffi +import InboxDesignSystem +import SwiftUI + +extension ListActions { + + var displayData: ActionDisplayData { + switch self { + case .labelAs: + .init(title: L10n.Action.labelAs, imageResource: DS.Icon.icTag) + case .markRead: + .init(title: L10n.Action.markAsRead, imageResource: DS.Icon.icEnvelopeOpen) + case .markUnread: + .init(title: L10n.Action.markAsUnread, imageResource: DS.Icon.icEnvelopeDot) + case .more: + .init(title: .empty, imageResource: DS.Icon.icThreeDotsHorizontal) + case .moveTo: + .init(title: L10n.Action.moveTo, imageResource: DS.Icon.icFolderArrowIn) + case .moveToSystemFolder(let systemFolder): + switch systemFolder.name { + case .archive: + .init(title: L10n.Action.moveToArchive, imageResource: DS.Icon.icArchiveBox) + case .inbox: + .init(title: L10n.Action.moveToInbox, imageResource: DS.Icon.icInbox) + case .spam: + .init(title: L10n.Action.moveToSpam, imageResource: DS.Icon.icSpam) + case .trash: + .init(title: L10n.Action.moveToTrash, imageResource: DS.Icon.icTrash) + } + case .notSpam: + .init(title: L10n.Action.notSpam, imageResource: DS.Icon.icNotSpam) + case .permanentDelete: + .init(title: L10n.Action.deletePermanently, imageResource: DS.Icon.icTrashCross) + case .star: + .init(title: L10n.Action.star, image: Image(symbol: .star)) + case .unstar: + .init(title: L10n.Action.unstar, image: Image(symbol: .starSlash)) + case .snooze: + .init(title: L10n.Action.snooze, imageResource: DS.Icon.icClock) + } + } + +} + +extension LocalizedStringResource { + static var empty: Self { + "".notLocalized.stringResource + } +} diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarAction.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarAction.swift similarity index 81% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarAction.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarAction.swift index 465c14ee59..a850c19fb6 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarAction.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarAction.swift @@ -15,10 +15,12 @@ // You should have received a copy of the GNU General Public License // along with Proton Mail. If not, see https://www.gnu.org/licenses/. -enum MailboxActionBarAction { - case mailboxItemsSelectionUpdated(ids: [ID]) - case actionSelected(BottomBarAction, ids: [ID]) - case moreSheetAction(BottomBarAction, ids: [ID]) +import proton_app_uniffi + +enum ListActionsToolbarAction { + case listItemsSelectionUpdated(ids: [ID]) + case actionSelected(ListActions, ids: [ID]) + case moreSheetAction(ListActions, ids: [ID]) case dismissLabelAsSheet case dismissMoveToSheet case alertActionTapped(DeleteConfirmationAlertAction, ids: [ID]) diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarMoreSheetState.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarMoreSheetState.swift similarity index 83% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarMoreSheetState.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarMoreSheetState.swift index 8f3caef8dc..0303704f02 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarMoreSheetState.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarMoreSheetState.swift @@ -15,12 +15,13 @@ // You should have received a copy of the GNU General Public License // along with Proton Mail. If not, see https://www.gnu.org/licenses/. +import proton_app_uniffi import Foundation -struct MailboxActionBarMoreSheetState: Identifiable, Equatable { +struct ListActionsToolbarMoreSheetState: Identifiable, Equatable { let selectedItemsIDs: [ID] - let bottomBarActions: [BottomBarAction] - let moreSheetOnlyActions: [BottomBarAction] + let bottomBarActions: [ListActions] + let moreSheetOnlyActions: [ListActions] // MARK: - Identifiable diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarState.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarState.swift similarity index 83% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarState.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarState.swift index 22ac8b764d..7d361a47d9 100644 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarState.swift +++ b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ListActionsToolbarState.swift @@ -15,13 +15,14 @@ // You should have received a copy of the GNU General Public License // along with Proton Mail. If not, see https://www.gnu.org/licenses/. +import proton_app_uniffi import InboxCore import InboxCoreUI -struct MailboxActionBarState: Copying, Equatable { - var bottomBarActions: [BottomBarAction] - var moreSheetOnlyActions: [BottomBarAction] - var moreActionSheetPresented: MailboxActionBarMoreSheetState? +struct ListActionsToolbarState: Copying, Equatable { + var bottomBarActions: [ListActions] + var moreSheetOnlyActions: [ListActions] + var moreActionSheetPresented: ListActionsToolbarMoreSheetState? var labelAsSheetPresented: ActionSheetInput? var moveToSheetPresented: ActionSheetInput? var deleteConfirmationAlert: AlertModel? @@ -29,7 +30,7 @@ struct MailboxActionBarState: Copying, Equatable { var isSnoozeSheetPresented: Bool } -extension MailboxActionBarState { +extension ListActionsToolbarState { static var initial: Self { .init( bottomBarActions: [], diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/ViewMode+ItemType.swift b/Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ViewMode+ItemType.swift similarity index 100% rename from Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/ViewMode+ItemType.swift rename to Modules/App/Sources/UI/Actions/Views/ListActionsToolbar/Models/ViewMode+ItemType.swift diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/BottomBarAction+DisplayData.swift b/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/BottomBarAction+DisplayData.swift deleted file mode 100644 index 87fd9b37d8..0000000000 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/BottomBarAction+DisplayData.swift +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2024 Proton Technologies AG -// -// This file is part of Proton Mail. -// -// Proton Mail 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. -// -// Proton Mail 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 Proton Mail. If not, see https://www.gnu.org/licenses/. - -import InboxDesignSystem -import SwiftUI - -extension BottomBarAction { - - var displayData: MailboxActionBarActionDisplayData { - switch self { - case .labelAs: - .init(imageResource: DS.Icon.icTag, name: L10n.Action.labelAs) - case .markRead: - .init(imageResource: DS.Icon.icEnvelopeOpen, name: L10n.Action.markAsRead) - case .markUnread: - .init(imageResource: DS.Icon.icEnvelopeDot, name: L10n.Action.markAsUnread) - case .more: - .init(imageResource: DS.Icon.icThreeDotsHorizontal, name: nil) - case .moveTo: - .init(imageResource: DS.Icon.icFolderArrowIn, name: L10n.Action.moveTo) - case .moveToSystemFolder(let systemFolder): - switch systemFolder.name { - case .archive: - .init(imageResource: DS.Icon.icArchiveBox, name: L10n.Action.moveToArchive) - case .inbox: - .init(imageResource: DS.Icon.icInbox, name: L10n.Action.moveToInbox) - case .spam: - .init(imageResource: DS.Icon.icSpam, name: L10n.Action.moveToSpam) - case .trash: - .init(imageResource: DS.Icon.icTrash, name: L10n.Action.moveToTrash) - } - case .notSpam: - .init(imageResource: DS.Icon.icNotSpam, name: L10n.Action.notSpam) - case .permanentDelete: - .init(imageResource: DS.Icon.icTrashCross, name: L10n.Action.deletePermanently) - case .star: - .init(icon: Image(symbol: .star), name: L10n.Action.star) - case .unstar: - .init(icon: Image(symbol: .starSlash), name: L10n.Action.unstar) - case .snooze: - .init(imageResource: DS.Icon.icClock, name: L10n.Action.snooze) - } - } - -} - -private extension MailboxActionBarActionDisplayData { - - init(imageResource: ImageResource, name: LocalizedStringResource?) { - self.init(icon: Image(imageResource), name: name) - } - -} diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/BottomBarAction.swift b/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/BottomBarAction.swift deleted file mode 100644 index 644c2c6b36..0000000000 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/BottomBarAction.swift +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2024 Proton Technologies AG -// -// This file is part of Proton Mail. -// -// Proton Mail 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. -// -// Proton Mail 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 Proton Mail. If not, see https://www.gnu.org/licenses/. - -import proton_app_uniffi - -@available(*, deprecated, message: "Use BottomBarActions directly or rename the uniffi enum") -typealias BottomBarAction = BottomBarActions diff --git a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarActionDisplayData.swift b/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarActionDisplayData.swift deleted file mode 100644 index ea456278a3..0000000000 --- a/Modules/App/Sources/UI/Actions/Views/MailboxActionBar/Models/MailboxActionBarActionDisplayData.swift +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2024 Proton Technologies AG -// -// This file is part of Proton Mail. -// -// Proton Mail 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. -// -// Proton Mail 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 Proton Mail. If not, see https://www.gnu.org/licenses/. - -import SwiftUI - -struct MailboxActionBarActionDisplayData { - let icon: Image - let name: LocalizedStringResource? - - init(icon: Image, name: LocalizedStringResource?) { - self.icon = icon - self.name = name - } -} diff --git a/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailModel.swift b/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailModel.swift index c5ac9ebcd8..c3ee148b69 100644 --- a/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailModel.swift +++ b/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailModel.swift @@ -28,7 +28,7 @@ final class ConversationDetailModel: Sendable, ObservableObject { @Published private(set) var mailbox: Mailbox? @Published private(set) var conversationID: ID? @Published private(set) var isStarred: Bool - @Published private(set) var bottomBarActions: [BottomBarActions] = [] + @Published private(set) var bottomBarActions: [ListActions] = [] @Published var actionSheets: MailboxActionSheetsState = .initial() @Published var editScheduledMessageConfirmationAlert: AlertModel? @Published var deleteConfirmationAlert: AlertModel? @@ -171,7 +171,7 @@ final class ConversationDetailModel: Sendable, ObservableObject { isStarred ? unstarConversation() : starConversation() } - func handleConversation(action: BottomBarActions, toastStateStore: ToastStateStore, goBack: @escaping () -> Void) { + func handleConversation(action: ListActions, toastStateStore: ToastStateStore, goBack: @escaping () -> Void) { let conversationID = conversationID.unsafelyUnwrapped switch action { case .labelAs: @@ -527,9 +527,9 @@ extension ConversationDetailModel { bottomBarActions = try! await dependencies - .bottomBarConversationActionsProvider(mailbox, [conversationID]) + .conversationListActionsToolbarActionsProvider(mailbox, [conversationID]) .get() - .visibleBottomBarActions + .visibleListActions } } @@ -553,14 +553,14 @@ extension ConversationDetailModel { struct Dependencies { let appContext: AppContext - let bottomBarConversationActionsProvider: ConversationBottomBarActionsProvider + let conversationListActionsToolbarActionsProvider: ConversationListActionsToolbarActionsProvider init( appContext: AppContext = .shared, - bottomBarConversationActionsProvider: @escaping ConversationBottomBarActionsProvider = allAvailableBottomBarActionsForConversations + conversationListActionsToolbarActionsProvider: @escaping ConversationListActionsToolbarActionsProvider = allAvailableListActionsForConversations ) { self.appContext = appContext - self.bottomBarConversationActionsProvider = bottomBarConversationActionsProvider + self.conversationListActionsToolbarActionsProvider = conversationListActionsToolbarActionsProvider } } } diff --git a/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailScreen.swift b/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailScreen.swift index 2c95fa4fe6..3d764ce1b8 100644 --- a/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailScreen.swift +++ b/Modules/App/Sources/UI/Screens/ConversationDetail/ConversationDetailScreen.swift @@ -132,7 +132,7 @@ struct ConversationDetailScreen: View { goBack: { navigationPath.removeLast() } ) }) { - action.displayData.icon + action.displayData.image .foregroundStyle(DS.Color.Icon.weak) } .accessibilityIdentifier(MailboxActionBarViewIdentifiers.button(index: index)) diff --git a/Modules/App/Sources/UI/Views/MailboxItemListView/MailboxItemsListView.swift b/Modules/App/Sources/UI/Views/MailboxItemListView/MailboxItemsListView.swift index 12903af28b..6815bc38be 100644 --- a/Modules/App/Sources/UI/Views/MailboxItemListView/MailboxItemsListView.swift +++ b/Modules/App/Sources/UI/Views/MailboxItemListView/MailboxItemsListView.swift @@ -56,7 +56,7 @@ struct MailboxItemsListView: View { .animation(.none, value: selectionState.hasItems) .toolbar(selectionState.hasItems ? .visible : .hidden, for: .bottomBar) .animation(.default, value: selectionState.hasItems) - .mailboxActionBar( + .listActionsToolbar( state: .initial, availableActions: .productionInstance, itemTypeForActionBar: config.itemTypeForActionBar, diff --git a/Modules/App/Tests/Tests/Snapshots/Actions/MailboxActionBarMoreSheetSnapshotTests.swift b/Modules/App/Tests/Tests/Snapshots/Actions/ListActionsToolbarMoreSheetSnapshotTests.swift similarity index 79% rename from Modules/App/Tests/Tests/Snapshots/Actions/MailboxActionBarMoreSheetSnapshotTests.swift rename to Modules/App/Tests/Tests/Snapshots/Actions/ListActionsToolbarMoreSheetSnapshotTests.swift index 926119921a..30b0f41147 100644 --- a/Modules/App/Tests/Tests/Snapshots/Actions/MailboxActionBarMoreSheetSnapshotTests.swift +++ b/Modules/App/Tests/Tests/Snapshots/Actions/ListActionsToolbarMoreSheetSnapshotTests.swift @@ -20,16 +20,16 @@ import InboxSnapshotTesting import InboxTesting @MainActor -class MailboxActionBarMoreSheetSnapshotTests: BaseTestCase { +class ListActionsToolbarMoreSheetSnapshotTests: BaseTestCase { func testMailboxActionBarMoreSheetLayoutsCorrectly() { CustomizeToolbarsFlag.$isVisible.withValue(true) { - let sut = MailboxActionBarMoreSheet( - state: MailboxActionBarMoreSheetPreviewProvider.state(), + let sut = ListActionsToolbarMoreSheet( + state: ListActionsToolbarMoreSheetPreviewProvider.state(), actionTapped: { _ in }, editToolbarTapped: {} ) - assertSnapshotsOnIPhoneX(of: sut, named: "mailbox_action_bar_more_sheet") + assertSnapshotsOnIPhoneX(of: sut, named: "list_actions_toolbar_more_sheet") } } diff --git a/Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/MailboxActionBarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.mailbox_action_bar_more_sheet_dark.png b/Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/ListActionsToolbarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.list_actions_toolbar_more_sheet_dark.png similarity index 100% rename from Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/MailboxActionBarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.mailbox_action_bar_more_sheet_dark.png rename to Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/ListActionsToolbarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.list_actions_toolbar_more_sheet_dark.png diff --git a/Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/MailboxActionBarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.mailbox_action_bar_more_sheet_light.png b/Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/ListActionsToolbarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.list_actions_toolbar_more_sheet_light.png similarity index 100% rename from Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/MailboxActionBarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.mailbox_action_bar_more_sheet_light.png rename to Modules/App/Tests/Tests/Snapshots/Actions/__Snapshots__/ListActionsToolbarMoreSheetSnapshotTests/testMailboxActionBarMoreSheetLayoutsCorrectly.list_actions_toolbar_more_sheet_light.png diff --git a/Modules/App/Tests/Tests/Unit/UI/Actions/MailboxActionBarStateStoreTests.swift b/Modules/App/Tests/Tests/Unit/UI/Actions/ListActionsToolbarStoreTests.swift similarity index 90% rename from Modules/App/Tests/Tests/Unit/UI/Actions/MailboxActionBarStateStoreTests.swift rename to Modules/App/Tests/Tests/Unit/UI/Actions/ListActionsToolbarStoreTests.swift index 07e1f8d91e..e32d7d1b5e 100644 --- a/Modules/App/Tests/Tests/Unit/UI/Actions/MailboxActionBarStateStoreTests.swift +++ b/Modules/App/Tests/Tests/Unit/UI/Actions/ListActionsToolbarStoreTests.swift @@ -21,13 +21,13 @@ import InboxTesting import proton_app_uniffi import XCTest -class MailboxActionBarStateStoreTests: BaseTestCase { +class ListActionsToolbarStoreTests: BaseTestCase { - var sut: MailboxActionBarStateStore! + var sut: ListActionsToolbarStore! var invokedAvailableMessageActionsWithIDs: [[ID]]! - var stubbedAvailableMessageActions: AllBottomBarMessageActions! + var stubbedAvailableMessageActions: AllListActions! var invokedAvailableConversationActionsWithIDs: [[ID]]! - var stubbedAvailableConversationActions: AllBottomBarMessageActions! + var stubbedAvailableConversationActions: AllListActions! var starActionPerformerActionsSpy: StarActionPerformerActionsSpy! var readActionPerformerActionsSpy: ReadActionPerformerActionsSpy! var deleteActionsSpy: DeleteActionsSpy! @@ -60,16 +60,16 @@ class MailboxActionBarStateStoreTests: BaseTestCase { super.tearDown() } - func testState_WhenMailboxItemsSelectionIsUpdatedInMessageMode_ItReturnsCorrectState() { + func testState_WhenListItemsSelectionIsUpdatedInMessageMode_ItReturnsCorrectState() { sut = makeSUT(viewMode: .messages) stubbedAvailableMessageActions = .init( - hiddenBottomBarActions: [.labelAs, .markRead], - visibleBottomBarActions: [.notSpam(.testInbox)] + hiddenListActions: [.labelAs, .markRead], + visibleListActions: [.notSpam(.testInbox)] ) let ids: [ID] = [.init(value: 11)] - sut.handle(action: .mailboxItemsSelectionUpdated(ids: ids)) + sut.handle(action: .listItemsSelectionUpdated(ids: ids)) XCTAssertEqual(invokedAvailableMessageActionsWithIDs.count, 1) XCTAssertEqual(invokedAvailableConversationActionsWithIDs.count, 0) @@ -83,15 +83,15 @@ class MailboxActionBarStateStoreTests: BaseTestCase { )) } - func testState_WhenMailboxItemsSelectionIsUpdatedInConversationModel_ItReturnsCorrectState() { + func testState_WhenListItemsSelectionIsUpdatedInConversationModel_ItReturnsCorrectState() { sut = makeSUT(viewMode: .conversations) stubbedAvailableConversationActions = .init( - hiddenBottomBarActions: [.notSpam(.testInbox), .permanentDelete], - visibleBottomBarActions: [.more] + hiddenListActions: [.notSpam(.testInbox), .permanentDelete], + visibleListActions: [.more] ) let ids: [ID] = [.init(value: 22)] - sut.handle(action: .mailboxItemsSelectionUpdated(ids: ids)) + sut.handle(action: .listItemsSelectionUpdated(ids: ids)) XCTAssertEqual(invokedAvailableMessageActionsWithIDs.count, 0) XCTAssertEqual(invokedAvailableConversationActionsWithIDs.count, 1) @@ -105,10 +105,10 @@ class MailboxActionBarStateStoreTests: BaseTestCase { )) } - func testState_WhenMailboxItemsSelectionIsUpdatedWithNoSelection_ItReturnsCorrectState() { + func testState_WhenListItemsSelectionIsUpdatedWithNoSelection_ItReturnsCorrectState() { sut = makeSUT(viewMode: .messages) - sut.handle(action: .mailboxItemsSelectionUpdated(ids: [])) + sut.handle(action: .listItemsSelectionUpdated(ids: [])) XCTAssertEqual(invokedAvailableMessageActionsWithIDs.count, 0) } @@ -151,7 +151,7 @@ class MailboxActionBarStateStoreTests: BaseTestCase { XCTAssertNil(sut.state.moreActionSheetPresented) - sut.handle(action: .mailboxItemsSelectionUpdated(ids: ids)) + sut.handle(action: .listItemsSelectionUpdated(ids: ids)) sut.handle(action: .actionSelected(.more, ids: ids)) XCTAssertEqual( @@ -285,8 +285,8 @@ class MailboxActionBarStateStoreTests: BaseTestCase { // MARK: - Private - private func makeSUT(viewMode: ViewMode) -> MailboxActionBarStateStore { - MailboxActionBarStateStore( + private func makeSUT(viewMode: ViewMode) -> ListActionsToolbarStore { + ListActionsToolbarStore( state: .initial, availableActions: .init( message: { _, ids in diff --git a/Modules/InboxContacts/Sources/Generated/Rust.generated.swift b/Modules/InboxContacts/Sources/Generated/Rust.generated.swift index ff0bd0027f..3ec256687d 100644 --- a/Modules/InboxContacts/Sources/Generated/Rust.generated.swift +++ b/Modules/InboxContacts/Sources/Generated/Rust.generated.swift @@ -4,8 +4,8 @@ import Foundation import proton_app_uniffi -public extension AllAvailableBottomBarActionsForConversationsResult { - func get() throws(ActionError) -> AllBottomBarMessageActions { +public extension AllAvailableListActionsForConversationsResult { + func get() throws(ActionError) -> AllListActions { switch self { case .ok(let value): value @@ -14,8 +14,8 @@ public extension AllAvailableBottomBarActionsForConversationsResult { } } } -public extension AllAvailableBottomBarActionsForMessagesResult { - func get() throws(ActionError) -> AllBottomBarMessageActions { +public extension AllAvailableListActionsForMessagesResult { + func get() throws(ActionError) -> AllListActions { switch self { case .ok(let value): value diff --git a/Modules/InboxContacts/Sources/Screens/ContactDetails/ContactDetailsScreen.swift b/Modules/InboxContacts/Sources/Screens/ContactDetails/ContactDetailsScreen.swift index caefa517c9..9dca143cdd 100644 --- a/Modules/InboxContacts/Sources/Screens/ContactDetails/ContactDetailsScreen.swift +++ b/Modules/InboxContacts/Sources/Screens/ContactDetails/ContactDetailsScreen.swift @@ -161,7 +161,9 @@ struct ContactDetailsScreen: View { case .urls(let urls): FormList(collection: urls) { item in button(item: ContactFormatter.URL.formatted(from: item)) { - store.handle(action: .openURL(urlString: item.url)) + if let urlString = item.url.urlString { + store.handle(action: .openURL(urlString: urlString)) + } } } case .logos, .photos: @@ -207,6 +209,19 @@ private extension FormList { } +private extension VCardUrlValue { + + var urlString: String? { + switch self { + case .http(let string): + string + case .notHttp, .text: + nil + } + } + +} + #Preview { ContactDetailsScreen( contact: ContactItem( diff --git a/Modules/InboxContacts/Sources/Screens/ContactDetails/Formatters/ContactFormatter.swift b/Modules/InboxContacts/Sources/Screens/ContactDetails/Formatters/ContactFormatter.swift index f1fe1ced9e..1c89104697 100644 --- a/Modules/InboxContacts/Sources/Screens/ContactDetails/Formatters/ContactFormatter.swift +++ b/Modules/InboxContacts/Sources/Screens/ContactDetails/Formatters/ContactFormatter.swift @@ -97,7 +97,7 @@ enum ContactFormatter { static func formatted(from vcardURL: VCardUrl) -> ContactDetailsItem { let label = vcardURL.urlType.humanReadable(fallback: L10n.ContactDetails.Label.url.string) - return .init(label: label, value: vcardURL.url, isInteractive: true) + return .init(label: label, value: vcardURL.url.value, isInteractive: true) } } @@ -177,3 +177,14 @@ private extension String { } } + +private extension VCardUrlValue { + + var value: String { + switch self { + case .http(let string), .notHttp(let string), .text(let string): + string + } + } + +} diff --git a/Modules/InboxContacts/Tests/Snapshots/ContactDetailsScreenSnapshotTests.swift b/Modules/InboxContacts/Tests/Snapshots/ContactDetailsScreenSnapshotTests.swift index 80b80f0b9d..6546472a7e 100644 --- a/Modules/InboxContacts/Tests/Snapshots/ContactDetailsScreenSnapshotTests.swift +++ b/Modules/InboxContacts/Tests/Snapshots/ContactDetailsScreenSnapshotTests.swift @@ -99,7 +99,7 @@ final class ContactDetailsScreenSnapshotTests { .languages(["french"]), .organizations(["CERN", "NASA"]), .members(["N/A"]), - .urls([.init(url: "https://www.nasa.gov", urlType: [.work])]), + .urls([.init(url: .http("https://www.nasa.gov"), urlType: [.work])]), ] assertSnapshotsOnIPhoneX(of: makeSUT(items: items)) diff --git a/Modules/InboxContacts/Tests/Unit/Screens/ContactDetails/Formatters/ContactFormatterTests.swift b/Modules/InboxContacts/Tests/Unit/Screens/ContactDetails/Formatters/ContactFormatterTests.swift index e3b6e9abe0..cf738f44c8 100644 --- a/Modules/InboxContacts/Tests/Unit/Screens/ContactDetails/Formatters/ContactFormatterTests.swift +++ b/Modules/InboxContacts/Tests/Unit/Screens/ContactDetails/Formatters/ContactFormatterTests.swift @@ -171,11 +171,11 @@ struct ContactFormatterTests { arguments: zip( [ - VCardUrl(url: "https://swissbank.ch", urlType: [.work]), - VCardUrl(url: "https://voice.example", urlType: [.voice]), - VCardUrl(url: "https://personal.blog", urlType: [.home]), - VCardUrl(url: "https://example.org", urlType: []), - VCardUrl(url: "https://custom.link", urlType: [.string("GitHub")]), + VCardUrl(url: .http("https://swissbank.ch"), urlType: [.work]), + VCardUrl(url: .http("https://voice.example"), urlType: [.voice]), + VCardUrl(url: .http("https://personal.blog"), urlType: [.home]), + VCardUrl(url: .http("https://example.org"), urlType: []), + VCardUrl(url: .http("https://custom.link"), urlType: [.string("GitHub")]), ], [ ContactDetailsItem(label: "Work", value: "https://swissbank.ch", isInteractive: true), diff --git a/Modules/InboxCoreUI/Sources/Generated/Rust.generated.swift b/Modules/InboxCoreUI/Sources/Generated/Rust.generated.swift index df6d4783ae..869452abb2 100644 --- a/Modules/InboxCoreUI/Sources/Generated/Rust.generated.swift +++ b/Modules/InboxCoreUI/Sources/Generated/Rust.generated.swift @@ -44,6 +44,26 @@ public extension ChallengeLoaderGetResult { } } } +public extension ChallengeLoaderPostResult { + func get() throws(ProtonError) -> ChallengeLoaderResponse { + switch self { + case .ok(let value): + value + case .error(let error): + throw error + } + } +} +public extension ChallengeLoaderPutResult { + func get() throws(ProtonError) -> ChallengeLoaderResponse { + switch self { + case .ok(let value): + value + case .error(let error): + throw error + } + } +} public extension CreateMailSessionResult { func get() throws(UserSessionError) -> MailSession { switch self { @@ -54,6 +74,36 @@ public extension CreateMailSessionResult { } } } +public extension CustomSettingsMobileSignatureResult { + func get() throws(ProtonError) -> MobileSignature { + switch self { + case .ok(let value): + value + case .error(let error): + throw error + } + } +} +public extension CustomSettingsSetMobileSignatureEnabledResult { + func get() throws(ProtonError) { + switch self { + case .ok: + break + case .error(let error): + throw error + } + } +} +public extension CustomSettingsSetMobileSignatureResult { + func get() throws(ProtonError) { + switch self { + case .ok: + break + case .error(let error): + throw error + } + } +} public extension DraftExpirationTimeResult { func get() throws(ProtonError) -> DraftExpirationTime { switch self { diff --git a/Modules/InboxCoreUI/Sources/Resources/Localizable.xcstrings b/Modules/InboxCoreUI/Sources/Resources/Localizable.xcstrings index ae113e44bf..572c5b17c5 100644 --- a/Modules/InboxCoreUI/Sources/Resources/Localizable.xcstrings +++ b/Modules/InboxCoreUI/Sources/Resources/Localizable.xcstrings @@ -214,13 +214,13 @@ "one" : { "stringUnit" : { "state" : "translated", - "value" : "Il vous reste %lld tentative avant la déconnexion." + "value" : "%lld Tentative restante avant la déconnexion" } }, "other" : { "stringUnit" : { "state" : "translated", - "value" : "Il vous reste %lld tentatives avant la déconnexion." + "value" : "%lld tentatives restantes avant la déconnexion" } } } diff --git a/Modules/InboxIAP/Sources/Resources/Localizable.xcstrings b/Modules/InboxIAP/Sources/Resources/Localizable.xcstrings index c0c6338e78..29c2c94d85 100644 --- a/Modules/InboxIAP/Sources/Resources/Localizable.xcstrings +++ b/Modules/InboxIAP/Sources/Resources/Localizable.xcstrings @@ -39,6 +39,24 @@ "state" : "new", "value" : "Billed at %1$@ every %2$@" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Facturado a %1$@ cada %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Facturé %1$@ tous les %2$@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "毎%2$@に%1$@の支払い" + } } } }, diff --git a/mail-sdk-version b/mail-sdk-version index 33e061fe7a..156fe0ca7d 100644 --- a/mail-sdk-version +++ b/mail-sdk-version @@ -1 +1 @@ -0.125.1 +0.130.0