Skip to content

Commit

Permalink
feat: ActionsPanelViewModifier
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippeWeidmann committed Apr 27, 2023
1 parent 44b1719 commit aca3c65
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 123 deletions.
25 changes: 25 additions & 0 deletions Mail/Utils/NavigationStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
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 <http://www.gnu.org/licenses/>.
*/

import Foundation
import SwiftUI
import MailCore

class NavigationStore: ObservableObject {
@Published var messageReply: MessageReply?
}
60 changes: 60 additions & 0 deletions Mail/Views/Bottom sheets/Actions/ActionsPanelViewModifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
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 <http://www.gnu.org/licenses/>.
*/

import Foundation
import MailCore
import SwiftUI

extension View {
func actionsPanel(actionsTarget: Binding<ActionsTarget?>, completionHandler: (() -> Void)? = nil) -> some View {
return modifier(ActionsPanelViewModifier(actionsTarget: actionsTarget, completionHandler: completionHandler))
}
}

struct ActionsPanelViewModifier: ViewModifier {
@EnvironmentObject private var mailboxManager: MailboxManager
@EnvironmentObject private var navigationStore: NavigationStore

@StateObject private var moveSheet = MoveSheet()

@Binding var actionsTarget: ActionsTarget?
var completionHandler: (() -> Void)?

func body(content: Content) -> some View {
content
.floatingPanel(item: $actionsTarget) { target in
ActionsView(mailboxManager: mailboxManager,
target: target,
moveSheet: moveSheet) { message, replyMode in
// FIXME: There seems to be a bug where SwiftUI looses the "context" and attempts to present
// the view controller before waiting for the dismiss of the first one if we use a closure
// (this "fix" is temporary)
DispatchQueue.main.async {
navigationStore.messageReply = MessageReply(message: message, replyMode: replyMode)
}
} completionHandler: {
completionHandler?()
}
}
.sheet(isPresented: $moveSheet.isShowing) {
if case .move(let folderId, let handler) = moveSheet.state {
MoveEmailView.sheetView(from: folderId, moveHandler: handler)
}
}
}
}
9 changes: 3 additions & 6 deletions Mail/Views/Bottom sheets/Actions/ActionsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,13 @@ struct ActionsView: View {
}
}

/*
struct ActionsView_Previews: PreviewProvider {
static var previews: some View {
ActionsView(mailboxManager: PreviewHelper.sampleMailboxManager,
target: .threads([PreviewHelper.sampleThread], false),
state: ThreadBottomSheet(),
globalSheet: GlobalBottomSheet(),
globalAlert: GlobalAlert()) { _, _ in /* Preview */ }
target: .threads([PreviewHelper.sampleThread], false)) { _, _ in /* Preview */ }
.accentColor(AccentColor.pink.primary.swiftUIColor)
}
}
*/

struct QuickActionView: View {
@Environment(\.dismiss) var dismiss
Expand Down Expand Up @@ -120,13 +115,15 @@ struct QuickActionView: View {
}

struct ActionView: View {
@Environment(\.dismiss) var dismiss
@ObservedObject var viewModel: ActionsViewModel
let action: Action

@AppStorage(UserDefaults.shared.key(.accentColor)) private var accentColor = DefaultPreferences.accentColor

var body: some View {
Button {
dismiss()
Task {
await tryOrDisplayError {
try await viewModel.didTap(action: action)
Expand Down
7 changes: 6 additions & 1 deletion Mail/Views/Bottom sheets/Actions/ActionsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,12 @@ struct Action: Identifiable, Equatable {

enum ActionsTarget: Equatable, Identifiable {
var id: String {
return UUID().uuidString
switch self {
case .threads(let threads, let isMultiSelectionEnabled):
return threads.map {$0.id}.joined()
case .message(let message):
return message.uid
}
}

case threads([Thread], Bool)
Expand Down
6 changes: 3 additions & 3 deletions Mail/Views/Bottom sheets/Actions/ReplyActionsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ struct ReplyActionsView: View {
var quickActions: [Action] = [.reply, .replyAll]

init(mailboxManager: MailboxManager,
target: ActionsTarget,
message: Message,
replyHandler: @escaping (Message, ReplyMode) -> Void) {
viewModel = ActionsViewModel(mailboxManager: mailboxManager,
target: target,
target: .message(message),
matomoCategory: .replyBottomSheet,
replyHandler: replyHandler)
}
Expand All @@ -52,7 +52,7 @@ struct ReplyActionsView: View {
struct ReplyActionsView_Previews: PreviewProvider {
static var previews: some View {
ReplyActionsView(mailboxManager: PreviewHelper.sampleMailboxManager,
target: .threads([PreviewHelper.sampleThread], false)) { _, _ in /* Preview */ }
message: PreviewHelper.sampleMessage) { _, _ in /* Preview */ }
.accentColor(AccentColor.pink.primary.swiftUIColor)
}
}
19 changes: 1 addition & 18 deletions Mail/Views/Search/SearchView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,19 @@ import RealmSwift
import SwiftUI

struct SearchView: View {
@StateObject var viewModel: SearchViewModel

@EnvironmentObject var splitViewManager: SplitViewManager
@EnvironmentObject var globalBottomSheet: GlobalBottomSheet

@StateObject var bottomSheet: ThreadBottomSheet
@StateObject var viewModel: SearchViewModel

@Binding private var editedMessageDraft: Draft?
@Binding private var messageReply: MessageReply?

let isCompact: Bool

init(mailboxManager: MailboxManager,
folder: Folder,
editedMessageDraft: Binding<Draft?>,
messageReply: Binding<MessageReply?>,
isCompact: Bool) {
let threadBottomSheet = ThreadBottomSheet()
_editedMessageDraft = editedMessageDraft
_messageReply = messageReply
_bottomSheet = StateObject(wrappedValue: threadBottomSheet)
_viewModel = StateObject(wrappedValue: SearchViewModel(mailboxManager: mailboxManager, folder: folder))
self.isCompact = isCompact
}
Expand Down Expand Up @@ -94,14 +86,6 @@ struct SearchView: View {
.emptyState(isEmpty: viewModel.searchState == .noResults) {
EmptyStateView.emptySearch
}
.floatingPanel(state: bottomSheet, halfOpening: true) {
if case .actions(let target) = bottomSheet.state, !target.isInvalidated {
ActionsView(mailboxManager: viewModel.mailboxManager,
target: target) { message, replyMode in
messageReply = MessageReply(message: message, replyMode: replyMode)
}
}
}
.refreshable {
await viewModel.fetchThreads()
}
Expand Down Expand Up @@ -144,7 +128,6 @@ struct SearchView_Previews: PreviewProvider {
SearchView(mailboxManager: PreviewHelper.sampleMailboxManager,
folder: PreviewHelper.sampleFolder,
editedMessageDraft: .constant(nil),
messageReply: .constant(nil),
isCompact: true)
}
}
6 changes: 5 additions & 1 deletion Mail/Views/SplitView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct SplitView: View {
var mailboxManager: MailboxManager
@State var splitViewController: UISplitViewController?
@StateObject private var navigationDrawerController = NavigationDrawerState()
@StateObject private var navigationStore = NavigationStore()

@Environment(\.horizontalSizeClass) var horizontalSizeClass
@Environment(\.verticalSizeClass) var verticalSizeClass
Expand Down Expand Up @@ -119,6 +120,9 @@ struct SplitView: View {
}
}
}
.sheet(item: $navigationStore.messageReply) { messageReply in
ComposeMessageView.replyOrForwardMessage(messageReply: messageReply, mailboxManager: mailboxManager)
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
Task {
try await mailboxManager.folders()
Expand Down Expand Up @@ -149,7 +153,6 @@ struct SplitView: View {
setupBehaviour(orientation: interfaceOrientation)
splitViewController.preferredDisplayMode = .twoDisplaceSecondary
}

.customAlert(isPresented: $alert.isShowing) {
switch alert.state {
case .reportPhishing(let message):
Expand All @@ -167,6 +170,7 @@ struct SplitView: View {
.environmentObject(navigationDrawerController)
.environmentObject(bottomSheet)
.environmentObject(alert)
.environmentObject(navigationStore)
.defaultAppStorage(.shared)
}

Expand Down
20 changes: 6 additions & 14 deletions Mail/Views/Thread List/ThreadListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,9 @@ struct ThreadListView: View {
matomo.track(eventWithCategory: .newMessage, name: "openFromFab")
isShowingComposeNewMessageView.toggle()
}
.floatingPanel(item: $viewModel.actionsTarget, content: { target in
ActionsView(mailboxManager: viewModel.mailboxManager,
target: target,
moveSheet: moveSheet) { message, replyMode in
viewModel.actionsTarget = nil
messageReply = MessageReply(message: message, replyMode: replyMode)
} completionHandler: {
multipleSelectionViewModel.isEnabled = false
}
})
.actionsPanel(actionsTarget: $viewModel.actionsTarget) {
multipleSelectionViewModel.isEnabled = false
}
.onAppear {
networkMonitor.start()
viewModel.globalBottomSheet = globalBottomSheet
Expand Down Expand Up @@ -251,8 +244,8 @@ struct ThreadListView: View {
ComposeMessageView.newMessage(mailboxManager: viewModel.mailboxManager)
}
.sheet(isPresented: $moveSheet.isShowing) {
if case let .move(folderId, handler) = moveSheet.state {
MoveEmailView.sheetView(mailboxManager: viewModel.mailboxManager, from: folderId, moveHandler: handler)
if case .move(let folderId, let handler) = moveSheet.state {
MoveEmailView.sheetView(from: folderId, moveHandler: handler)
}
}
.customAlert(item: $flushAlert) { item in
Expand Down Expand Up @@ -388,8 +381,7 @@ private struct ThreadListToolbar: ViewModifier {

ToolbarButton(text: MailResourcesStrings.Localizable.buttonMore,
icon: MailResourcesAsset.plusActions.swiftUIImage) {
bottomSheet
.open(state: .actions(.threads(Array(multipleSelectionViewModel.selectedItems), true)))
viewModel.actionsTarget = .threads(Array(multipleSelectionViewModel.selectedItems), true)
}
}
.disabled(multipleSelectionViewModel.selectedItems.isEmpty)
Expand Down
20 changes: 8 additions & 12 deletions Mail/Views/Thread/MessageHeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ import RealmSwift
import SwiftUI

struct MessageHeaderView: View {
@EnvironmentObject private var navigationStore: NavigationStore

@State private var editedDraft: Draft?
@State private var messageReply: MessageReply?
@State private var contactViewRecipient: Recipient?
@State private var replyOrReplyAllMessage: Message?
@State private var actionsTarget: ActionsTarget?

@ObservedRealmObject var message: Message
@Binding var isHeaderExpanded: Bool
@Binding var isMessageExpanded: Bool

@EnvironmentObject var mailboxManager: MailboxManager
@EnvironmentObject var threadBottomSheet: ThreadBottomSheet

@LazyInjectService private var matomo: MatomoUtils

Expand All @@ -49,10 +50,10 @@ struct MessageHeaderView: View {
if message.canReplyAll {
replyOrReplyAllMessage = message
} else {
messageReply = MessageReply(message: message, replyMode: .reply)
navigationStore.messageReply = MessageReply(message: message, replyMode: .reply)
}
} moreButtonTapped: {
threadBottomSheet.open(state: .actions(.message(message.thaw() ?? message)))
actionsTarget = .message(message)
} recipientTapped: { recipient in
contactViewRecipient = recipient
}
Expand All @@ -78,18 +79,13 @@ struct MessageHeaderView: View {
.sheet(item: $editedDraft) { editedDraft in
ComposeMessageView.editDraft(draft: editedDraft, mailboxManager: mailboxManager)
}
.sheet(item: $messageReply) { messageReply in
ComposeMessageView.replyOrForwardMessage(messageReply: messageReply, mailboxManager: mailboxManager)
}
.floatingPanel(item: $contactViewRecipient) { recipient in
ContactActionsView(recipient: recipient)
}
.actionsPanel(actionsTarget: $actionsTarget)
.floatingPanel(item: $replyOrReplyAllMessage) { message in
ReplyActionsView(
mailboxManager: mailboxManager,
target: .message(message)
) { message, replyMode in
messageReply = MessageReply(message: message, replyMode: replyMode)
ReplyActionsView(mailboxManager: mailboxManager, message: message) { message, replyMode in
navigationStore.messageReply = MessageReply(message: message, replyMode: replyMode)
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions Mail/Views/Thread/MoveEmailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ struct MoveEmailView: View {
}

extension MoveEmailView {
static func sheetView(mailboxManager: MailboxManager, from folderId: String?,
moveHandler: @escaping MoveEmailView.MoveHandler) -> some View {
static func sheetView(from folderId: String?, moveHandler: @escaping MoveEmailView.MoveHandler) -> some View {
SheetView {
MoveEmailView(currentFolderId: folderId, moveHandler: moveHandler)
}
Expand Down
Loading

0 comments on commit aca3c65

Please sign in to comment.