diff --git a/Mail/Views/Bottom sheets/Actions/ActionsPanelViewModifier.swift b/Mail/Views/Bottom sheets/Actions/ActionsPanelViewModifier.swift index 2002bb08fe..e8c50b1cc8 100644 --- a/Mail/Views/Bottom sheets/Actions/ActionsPanelViewModifier.swift +++ b/Mail/Views/Bottom sheets/Actions/ActionsPanelViewModifier.swift @@ -47,7 +47,6 @@ struct ActionsPanelViewModifier: ViewModifier { @EnvironmentObject private var mailboxManager: MailboxManager - @ModalState private var reportForJunkMessages: [Message]? @ModalState private var reportedForDisplayProblemMessage: Message? @ModalState private var reportedForPhishingMessages: [Message]? @ModalState private var blockSenderAlert: BlockRecipientAlertState? @@ -73,7 +72,6 @@ struct ActionsPanelViewModifier: ViewModifier { nearestMessagesToMoveSheet: $messagesToMove, nearestBlockSenderAlert: $blockSenderAlert, nearestBlockSendersList: $blockSendersList, - nearestReportJunkMessagesActionsPanel: $reportForJunkMessages, nearestReportedForPhishingMessagesAlert: $reportedForPhishingMessages, nearestReportedForDisplayProblemMessageAlert: $reportedForDisplayProblemMessage, nearestShareMailLinkPanel: $shareMailLink, @@ -92,7 +90,7 @@ struct ActionsPanelViewModifier: ViewModifier { } func body(content: Content) -> some View { - content.adaptivePanel(item: $messages, popoverArrowEdge: popoverArrowEdge) { messages in + content.adaptivePanel(item: $messages, style: .native, popoverArrowEdge: popoverArrowEdge) { messages in ActionsView( user: currentUser.value, target: messages, @@ -110,10 +108,6 @@ struct ActionsPanelViewModifier: ViewModifier { ) .sheetViewStyle() } - .mailFloatingPanel(item: $reportForJunkMessages) { reportForJunkMessages in - ReportJunkView(reportedMessages: reportForJunkMessages, origin: origin, completionHandler: completionHandler) - .environmentObject(mailboxManager) // Force environment object to prevent crash on macOS - } .mailFloatingPanel(item: $blockSendersList, title: MailResourcesStrings.Localizable.blockAnExpeditorTitle) { blockSenderState in BlockSenderView(recipientsToMessage: blockSenderState.recipientsToMessage, origin: origin) diff --git a/Mail/Views/Bottom sheets/Actions/ReportJunkView.swift b/Mail/Views/Bottom sheets/Actions/ReportJunkView.swift deleted file mode 100644 index 469a073ca1..0000000000 --- a/Mail/Views/Bottom sheets/Actions/ReportJunkView.swift +++ /dev/null @@ -1,71 +0,0 @@ -/* - Infomaniak Mail - iOS App - Copyright (C) 2024 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 InfomaniakCore -import InfomaniakCoreCommonUI -import InfomaniakDI -import MailCore -import MailCoreUI -import MailResources -import SwiftUI - -struct ReportJunkView: View { - @EnvironmentObject private var mailboxManager: MailboxManager - - let reportedMessages: [Message] - let origin: ActionOrigin - var completionHandler: ((Action) -> Void)? - - private var filteredActions: [Action] { - let currentUserEmail = mailboxManager.mailbox.email - let uniqueSenders = Set(reportedMessages.compactMap { $0.from.first?.email }) - - if uniqueSenders == [currentUserEmail] { - return [.spam, .phishing] - } else { - return [.spam, .phishing, .blockList] - } - } - - var body: some View { - VStack(alignment: .leading, spacing: 0) { - ForEach(filteredActions) { action in - if action != filteredActions.first { - IKDivider() - } - MessageActionView( - targetMessages: reportedMessages, - action: action, - origin: origin, - isMultipleSelection: false, - completionHandler: completionHandler - ) - } - } - .matomoView(view: [MatomoUtils.View.bottomSheet.displayName, "ReportJunkView"]) - } -} - -#Preview { - ReportJunkView( - reportedMessages: PreviewHelper.sampleMessages, - origin: .floatingPanel(source: .threadList) - ) { _ in } - .accentColor(AccentColor.pink.primary.swiftUIColor) - .environmentObject(PreviewHelper.sampleMailboxManager) -} diff --git a/Mail/Views/Thread List/ThreadListCellContextMenu.swift b/Mail/Views/Thread List/ThreadListCellContextMenu.swift index a8c1ac4d60..e252b9be14 100644 --- a/Mail/Views/Thread List/ThreadListCellContextMenu.swift +++ b/Mail/Views/Thread List/ThreadListCellContextMenu.swift @@ -41,7 +41,6 @@ struct ThreadListCellContextMenu: ViewModifier { @EnvironmentObject private var actionsManager: ActionsManager @EnvironmentObject private var mailboxManager: MailboxManager - @ModalState private var reportForJunkMessages: [Message]? @ModalState private var reportedForDisplayProblemMessage: Message? @ModalState private var reportedForPhishingMessages: [Message]? @ModalState private var blockSenderAlert: BlockRecipientAlertState? @@ -64,7 +63,6 @@ struct ThreadListCellContextMenu: ViewModifier { nearestMessagesToMoveSheet: $messagesToMove, nearestBlockSenderAlert: $blockSenderAlert, nearestBlockSendersList: $blockSendersList, - nearestReportJunkMessagesActionsPanel: $reportForJunkMessages, nearestReportedForPhishingMessagesAlert: $reportedForPhishingMessages, nearestReportedForDisplayProblemMessageAlert: $reportedForDisplayProblemMessage, nearestShareMailLinkPanel: $shareMailLink, @@ -126,9 +124,6 @@ struct ThreadListCellContextMenu: ViewModifier { ) .sheetViewStyle() } - .mailFloatingPanel(item: $reportForJunkMessages) { reportForJunkMessages in - ReportJunkView(reportedMessages: reportForJunkMessages, origin: origin) - } .mailFloatingPanel(item: $blockSendersList, title: MailResourcesStrings.Localizable.blockAnExpeditorTitle) { blockSenderState in BlockSenderView(recipientsToMessage: blockSenderState.recipientsToMessage, origin: origin) diff --git a/Mail/Views/Thread/Message/MessageHeader/MessageHeaderSummaryView.swift b/Mail/Views/Thread/Message/MessageHeader/MessageHeaderSummaryView.swift index db8757a37c..f1bc190aa2 100644 --- a/Mail/Views/Thread/Message/MessageHeader/MessageHeaderSummaryView.swift +++ b/Mail/Views/Thread/Message/MessageHeader/MessageHeaderSummaryView.swift @@ -62,7 +62,7 @@ struct MessageHeaderSummaryView: View { size: 40 ) } - .adaptivePanel(item: $contactViewRecipient) { recipient in + .adaptivePanel(item: $contactViewRecipient, style: .native) { recipient in ContactActionsView(recipient: recipient, bimi: message.bimi) .environmentObject(mailboxManager) .environment(\.currentUser, currentUser) diff --git a/MailCore/Cache/Actions/Action+List.swift b/MailCore/Cache/Actions/Action+List.swift index 4127a02f7e..7479d445ff 100644 --- a/MailCore/Cache/Actions/Action+List.swift +++ b/MailCore/Cache/Actions/Action+List.swift @@ -45,7 +45,6 @@ extension Action: CaseIterable { .star, .star, .unstar, - .reportJunk, .spam, .nonSpam, .block, @@ -77,7 +76,6 @@ extension Action: CaseIterable { .openMovePanel, .saveThreadInkDrive, .shareMailLink, - .reportJunk, .phishing, .block, .blockList, @@ -111,9 +109,11 @@ extension Action: CaseIterable { let snoozedActions = snoozedActions([message], folder: origin.frozenFolder) + let isFromMe = message.fromMe(currentMailboxEmail: userEmail) + let isInSpamFolder = message.folder?.role == .spam var spamAction: Action? { - guard !message.fromMe(currentMailboxEmail: userEmail) else { return nil } - return message.folder?.role == .spam ? .nonSpam : .reportJunk + guard !isFromMe else { return nil } + return isInSpamFolder ? .nonSpam : .spam } let archive = message.folder?.role != .archive let unread = !message.seen @@ -121,12 +121,14 @@ extension Action: CaseIterable { let print = origin.type == .floatingPanel(source: .message) let tempListActions: [Action?] = [ .openMovePanel, - spamAction, unread ? .markAsRead : .markAsUnread, + spamAction, + isFromMe || isInSpamFolder ? nil : .phishing, + isFromMe || isInSpamFolder ? nil : .blockList, + .shareMailLink, archive ? .archive : .moveToInbox, star ? .unstar : .star, print ? .print : nil, - .shareMailLink, platformDetector.isMac ? nil : .saveThreadInkDrive, userIsStaff ? .reportDisplayProblem : nil ] @@ -149,15 +151,18 @@ extension Action: CaseIterable { let snoozedActions = snoozedActions(messages, folder: originFolder) + let isSelfThread = isSelfThread(messages, userEmail) + let isInSpamFolder = originFolder?.role == .spam var spamAction: Action? { - let selfThread = messages.flatMap(\.from).allSatisfy { $0.isMe(currentMailboxEmail: userEmail) } - guard !selfThread else { return nil } - return originFolder?.role == .spam ? .nonSpam : .reportJunk + guard !isSelfThread else { return nil } + return isInSpamFolder ? .nonSpam : .spam } let star = messages.allSatisfy(\.flagged) let tempListActions: [Action?] = [ spamAction, + isSelfThread || isInSpamFolder ? nil : .phishing, + isSelfThread || isInSpamFolder ? nil : .blockList, star ? .unstar : .star, .saveThreadInkDrive ] @@ -173,17 +178,20 @@ extension Action: CaseIterable { let unread = messages.allSatisfy(\.seen) let showUnstar = messages.contains { $0.flagged } + let isSelfThread = isSelfThread(messages, userEmail) + let isInSpamFolder = originFolder?.role == .spam var spamAction: Action? { - let selfThread = messages.flatMap(\.from).allSatisfy { $0.isMe(currentMailboxEmail: userEmail) } - guard !selfThread else { return nil } - return originFolder?.role == .spam ? .nonSpam : .reportJunk + guard !isSelfThread else { return nil } + return isInSpamFolder ? .nonSpam : .spam } let snoozedActions = snoozedActions(messages, folder: originFolder) let tempListActions: [Action?] = [ .openMovePanel, - spamAction, unread ? .markAsUnread : .markAsRead, + spamAction, + isSelfThread || isInSpamFolder ? nil : .phishing, + isSelfThread || isInSpamFolder ? nil : .blockList, archive ? .archive : .moveToInbox, showUnstar ? .unstar : .star, .saveThreadInkDrive @@ -206,6 +214,10 @@ extension Action: CaseIterable { } } + private static func isSelfThread(_ messages: [Message], _ userEmail: String) -> Bool { + return messages.flatMap(\.from).allSatisfy { $0.isMe(currentMailboxEmail: userEmail) } + } + public static func actionsForMessages(_ messages: [Message], origin: ActionOrigin, userIsStaff: Bool, @@ -351,12 +363,6 @@ public extension Action { iconResource: MailResourcesAsset.printText, matomoName: "print" ) - static let reportJunk = Action( - id: "reportJunk", - title: MailResourcesStrings.Localizable.actionReportJunk, - iconResource: MailResourcesAsset.report, - matomoName: "reportJunk" - ) static let spam = Action( id: "spam", title: MailResourcesStrings.Localizable.actionSpam, diff --git a/MailCore/Cache/Actions/ActionOrigin.swift b/MailCore/Cache/Actions/ActionOrigin.swift index 63bfa5434f..ede7ee76fc 100644 --- a/MailCore/Cache/Actions/ActionOrigin.swift +++ b/MailCore/Cache/Actions/ActionOrigin.swift @@ -43,7 +43,6 @@ public struct ActionOrigin { private(set) var nearestMessagesToMoveSheet: Binding<[Message]?>? private(set) var nearestBlockSenderAlert: Binding? private(set) var nearestBlockSendersList: Binding? - private(set) var nearestReportJunkMessagesActionsPanel: Binding<[Message]?>? private(set) var nearestReportedForPhishingMessagesAlert: Binding<[Message]?>? private(set) var nearestReportedForDisplayProblemMessageAlert: Binding? private(set) var nearestShareMailLinkPanel: Binding? @@ -58,7 +57,6 @@ public struct ActionOrigin { nearestMessagesToMoveSheet: Binding<[Message]?>? = nil, nearestBlockSenderAlert: Binding? = nil, nearestBlockSendersList: Binding? = nil, - nearestReportJunkMessagesActionsPanel: Binding<[Message]?>? = nil, nearestReportedForPhishingMessagesAlert: Binding<[Message]?>? = nil, nearestReportedForDisplayProblemMessageAlert: Binding? = nil, nearestShareMailLinkPanel: Binding? = nil, @@ -72,7 +70,6 @@ public struct ActionOrigin { self.nearestMessagesToMoveSheet = nearestMessagesToMoveSheet self.nearestBlockSenderAlert = nearestBlockSenderAlert self.nearestBlockSendersList = nearestBlockSendersList - self.nearestReportJunkMessagesActionsPanel = nearestReportJunkMessagesActionsPanel self.nearestReportedForPhishingMessagesAlert = nearestReportedForPhishingMessagesAlert self.nearestReportedForDisplayProblemMessageAlert = nearestReportedForDisplayProblemMessageAlert self.nearestShareMailLinkPanel = nearestShareMailLinkPanel @@ -91,7 +88,6 @@ public struct ActionOrigin { nearestMessagesToMoveSheet: Binding<[Message]?>? = nil, nearestBlockSenderAlert: Binding? = nil, nearestBlockSendersList: Binding? = nil, - nearestReportJunkMessagesActionsPanel: Binding<[Message]?>? = nil, nearestReportedForPhishingMessagesAlert: Binding<[Message]?>? = nil, nearestReportedForDisplayProblemMessageAlert: Binding? = nil, nearestShareMailLinkPanel: Binding? = nil, @@ -104,7 +100,6 @@ public struct ActionOrigin { nearestMessagesToMoveSheet: nearestMessagesToMoveSheet, nearestBlockSenderAlert: nearestBlockSenderAlert, nearestBlockSendersList: nearestBlockSendersList, - nearestReportJunkMessagesActionsPanel: nearestReportJunkMessagesActionsPanel, nearestReportedForPhishingMessagesAlert: nearestReportedForPhishingMessagesAlert, nearestReportedForDisplayProblemMessageAlert: nearestReportedForDisplayProblemMessageAlert, nearestShareMailLinkPanel: nearestShareMailLinkPanel, diff --git a/MailCore/Cache/Actions/ActionsManager.swift b/MailCore/Cache/Actions/ActionsManager.swift index 2421846b3e..5f56298e50 100644 --- a/MailCore/Cache/Actions/ActionsManager.swift +++ b/MailCore/Cache/Actions/ActionsManager.swift @@ -179,10 +179,6 @@ public class ActionsManager: ObservableObject { Task { @MainActor in origin.nearestMessagesActionsPanel?.wrappedValue = messagesWithDuplicates } - case .reportJunk: - Task { @MainActor in - origin.nearestReportJunkMessagesActionsPanel?.wrappedValue = messagesWithDuplicates - } case .spam: let messagesFromFolder = messagesWithDuplicates.fromFolderOrSearch(originFolder: origin.frozenFolder) diff --git a/MailCoreUI/Utils/AdaptivePanelViewModifier.swift b/MailCoreUI/Utils/AdaptivePanelViewModifier.swift index 8275025e42..8b5143f66f 100644 --- a/MailCoreUI/Utils/AdaptivePanelViewModifier.swift +++ b/MailCoreUI/Utils/AdaptivePanelViewModifier.swift @@ -24,10 +24,47 @@ import SwiftUI public extension View { func adaptivePanel( item: Binding, + style: AdaptivePanelStyle = .selfSizing, popoverArrowEdge: Edge = .top, @ViewBuilder content: @escaping (Item) -> Content ) -> some View { - return modifier(AdaptivePanelViewModifier(item: item, popoverArrowEdge: popoverArrowEdge, panelContent: content)) + return modifier(AdaptivePanelViewModifier( + item: item, + style: style, + popoverArrowEdge: popoverArrowEdge, + panelContent: content + )) + } +} + +public enum AdaptivePanelStyle { + case native + case selfSizing +} + +@available(iOS 16.4, *) +struct NativePanelView: View { + @State private var selection: PresentationDetent = .medium + + let item: Item + + @ViewBuilder let panelContent: (Item) -> PanelContent + + var body: some View { + IKFloatingPanelView( + currentDetent: $selection, + closeButtonHidden: false, + topPadding: IKPadding.large, + bottomPadding: 0, + detents: [.medium, .large], + dragIndicator: .visible + ) { + ScrollView { + panelContent(item) + .padding(.bottom, IKPadding.medium) + } + .scrollBounceBehavior(.basedOnSize) + } } } @@ -36,23 +73,45 @@ struct AdaptivePanelViewModifier: ViewMo @Binding var item: Item? - var popoverArrowEdge: Edge + let style: AdaptivePanelStyle + let popoverArrowEdge: Edge + @ViewBuilder let panelContent: (Item) -> PanelContent func body(content: Content) -> some View { content - .popover(item: $item, arrowEdge: popoverArrowEdge) { item in - if isCompactWindow { - if #available(iOS 16.0, *) { - panelContent(item).modifier(SelfSizingPanelViewModifier(topPadding: IKPadding.large, - bottomPadding: IKPadding.medium)) + .sheet(item: Binding(get: { + isCompactWindow ? item : nil + }, set: { newValue in + item = newValue + })) { item in + if style == .native, + #available(iOS 16.4, *) { + NativePanelView(item: item, panelContent: panelContent) + .background(MailResourcesAsset.backgroundSecondaryColor.swiftUIColor) + } else { + if #available(iOS 16.4, *) { + panelContent(item) + .modifier(SelfSizingPanelViewModifier( + topPadding: IKPadding.large, + bottomPadding: IKPadding.medium + )) .background(MailResourcesAsset.backgroundSecondaryColor.swiftUIColor) } else { - panelContent(item).modifier(SelfSizingPanelBackportViewModifier(topPadding: IKPadding.large, - bottomPadding: IKPadding.medium)) + panelContent(item) + .modifier(SelfSizingPanelBackportViewModifier(topPadding: IKPadding.large, + bottomPadding: IKPadding.medium)) .background(MailResourcesAsset.backgroundSecondaryColor.swiftUIColor) } - } else { + } + } + .popover(item: + Binding(get: { + isCompactWindow ? nil : item + }, set: { newValue in + item = newValue + }), + arrowEdge: popoverArrowEdge) { item in ScrollView { panelContent(item) } @@ -60,7 +119,6 @@ struct AdaptivePanelViewModifier: ViewMo .frame(idealWidth: 400) // DO NOT SUPPRESS the scaleEffect it's required for the contrast for macOS .background(MailResourcesAsset.backgroundColor.swiftUIColor.scaleEffect(1.5)) - } } } } diff --git a/MailResources/Localizable/de.lproj/Localizable.strings b/MailResources/Localizable/de.lproj/Localizable.strings index e1c906bc8f..ae690cbb50 100644 --- a/MailResources/Localizable/de.lproj/Localizable.strings +++ b/MailResources/Localizable/de.lproj/Localizable.strings @@ -76,9 +76,6 @@ /* loco:629f0fd21c251254874665a2 */ "actionReportDisplayProblem" = "Ein Anzeigeproblem melden"; -/* loco:63c94bcfbaa59733423c0a83 */ -"actionReportJunk" = "Spam melden"; - /* loco:62e13281cd9a910e235d06d2 */ "actionShortMarkAsRead" = "Gelesen"; diff --git a/MailResources/Localizable/en.lproj/Localizable.strings b/MailResources/Localizable/en.lproj/Localizable.strings index 8d91677252..77f1300f47 100644 --- a/MailResources/Localizable/en.lproj/Localizable.strings +++ b/MailResources/Localizable/en.lproj/Localizable.strings @@ -76,9 +76,6 @@ /* loco:629f0fd21c251254874665a2 */ "actionReportDisplayProblem" = "Report a display problem"; -/* loco:63c94bcfbaa59733423c0a83 */ -"actionReportJunk" = "Report junk"; - /* loco:62e13281cd9a910e235d06d2 */ "actionShortMarkAsRead" = "Read"; diff --git a/MailResources/Localizable/es.lproj/Localizable.strings b/MailResources/Localizable/es.lproj/Localizable.strings index fb21ca6e5d..654a5d5c38 100644 --- a/MailResources/Localizable/es.lproj/Localizable.strings +++ b/MailResources/Localizable/es.lproj/Localizable.strings @@ -76,9 +76,6 @@ /* loco:629f0fd21c251254874665a2 */ "actionReportDisplayProblem" = "Informar de un problema de visualización"; -/* loco:63c94bcfbaa59733423c0a83 */ -"actionReportJunk" = "Informe basura"; - /* loco:62e13281cd9a910e235d06d2 */ "actionShortMarkAsRead" = "Leer"; diff --git a/MailResources/Localizable/fr.lproj/Localizable.strings b/MailResources/Localizable/fr.lproj/Localizable.strings index ea4364d02c..b50fb5b86b 100644 --- a/MailResources/Localizable/fr.lproj/Localizable.strings +++ b/MailResources/Localizable/fr.lproj/Localizable.strings @@ -76,9 +76,6 @@ /* loco:629f0fd21c251254874665a2 */ "actionReportDisplayProblem" = "Signaler un problème d’affichage"; -/* loco:63c94bcfbaa59733423c0a83 */ -"actionReportJunk" = "Signaler comme indésirable"; - /* loco:62e13281cd9a910e235d06d2 */ "actionShortMarkAsRead" = "Lu"; diff --git a/MailResources/Localizable/it.lproj/Localizable.strings b/MailResources/Localizable/it.lproj/Localizable.strings index 5a0f89fac7..1d86081d70 100644 --- a/MailResources/Localizable/it.lproj/Localizable.strings +++ b/MailResources/Localizable/it.lproj/Localizable.strings @@ -76,9 +76,6 @@ /* loco:629f0fd21c251254874665a2 */ "actionReportDisplayProblem" = "Segnala un problema di visualizzazione"; -/* loco:63c94bcfbaa59733423c0a83 */ -"actionReportJunk" = "Segnala spazzatura"; - /* loco:62e13281cd9a910e235d06d2 */ "actionShortMarkAsRead" = "Letto";