Skip to content

Commit

Permalink
Merge pull request #771 from Infomaniak/fix-thread-toolbar
Browse files Browse the repository at this point in the history
fix: Current toolbar break when the screen is too small
  • Loading branch information
valentinperignon authored Jun 7, 2023
2 parents 42d7908 + 7ce8ff5 commit cfd23c9
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 70 deletions.
84 changes: 84 additions & 0 deletions Mail/Components/BottomBarView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
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 MailCore
import MailResources
import SwiftUI

struct BottomBar<Items: View>: ViewModifier {
let isVisible: Bool
@ViewBuilder var items: () -> Items

func body(content: Content) -> some View {
content
.safeAreaInset(edge: .bottom) {
if isVisible {
BottomBarView(items: items)
.transition(.opacity)
}
}
}
}

extension View {
func bottomBar<Items: View>(isVisible: Bool = true, @ViewBuilder items: @escaping () -> Items) -> some View {
modifier(BottomBar(isVisible: isVisible, items: items))
}
}

struct BottomBarView<Items: View>: View {
@State private var hasBottomSafeArea = true

@ViewBuilder var items: () -> Items

var body: some View {
HStack {
Spacer(minLength: UIConstants.bottomBarHorizontalMinimumSpace)
items()
Spacer(minLength: UIConstants.bottomBarHorizontalMinimumSpace)
}
.padding(.top, UIConstants.bottomBarVerticalPadding)
.padding(.bottom, hasBottomSafeArea ? UIConstants.bottomBarSmallVerticalPadding : UIConstants.bottomBarVerticalPadding)
.background(MailResourcesAsset.backgroundTabBarColor.swiftUIColor)
.overlay(alignment: .top) {
Divider()
.frame(height: 1)
.overlay(Color(uiColor: .systemGray3))
}
.overlay {
ViewGeometry(key: BottomSafeAreaKey.self, property: \.safeAreaInsets.bottom)
}
.onPreferenceChange(BottomSafeAreaKey.self) { value in
hasBottomSafeArea = value > 0
}
}
}

struct BottomBarView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
List {
Text("View #1")
}
.navigationTitle("Title")
.bottomBar {
Text("Coucou")
}
}
}
}
2 changes: 1 addition & 1 deletion Mail/Components/MailButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import MailCore
import MailResources
import SwiftUI

// MARK: - Modifiers
// MARK: - Environment

struct MailButtonStyleKey: EnvironmentKey {
static var defaultValue = MailButton.Style.large
Expand Down
4 changes: 4 additions & 0 deletions Mail/Components/ToolbarButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ struct ToolbarButtonLabel: View {
Label {
Text(text)
.textStyle(MailTextStyle.labelMediumAccent)
.minimumScaleFactor(0.8)
.lineLimit(1)
} icon: {
icon
.resizable()
.frame(width: 24, height: 24)
}
.dynamicLabelStyle(sizeClass: sizeClass ?? .regular)
}
Expand Down
47 changes: 47 additions & 0 deletions Mail/Utils/GeometryReaderHelpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
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 SwiftUI

struct ViewWidthKey: PreferenceKey {
static var defaultValue: CGFloat = .zero

static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}

struct BottomSafeAreaKey: PreferenceKey {
static var defaultValue: CGFloat = .zero

static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}

struct ViewGeometry<K>: View where K: PreferenceKey {
let key: K.Type
let property: KeyPath<GeometryProxy, K.Value>

var body: some View {
GeometryReader { proxy in
Color.clear
.preference(key: key, value: proxy[keyPath: property])
}
}
}
49 changes: 23 additions & 26 deletions Mail/Views/Thread List/ThreadListModifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,37 +130,34 @@ struct ThreadListToolbar: ViewModifier {
.accessibilityLabel(MailResourcesStrings.Localizable.contentDescriptionUserAvatar)
}
}

ToolbarItemGroup(placement: .bottomBar) {
if multipleSelectionViewModel.isEnabled {
HStack(spacing: 0) {
ForEach(multipleSelectionViewModel.toolbarActions) { action in
ToolbarButton(
text: action.shortTitle ?? action.title,
icon: action.icon
) {
Task {
await tryOrDisplayError {
try await multipleSelectionViewModel.didTap(
action: action,
flushAlert: $flushAlert
)
}
}
}
.bottomBar(isVisible: multipleSelectionViewModel.isEnabled) {
HStack(spacing: 0) {
ForEach(multipleSelectionViewModel.toolbarActions) { action in
ToolbarButton(
text: action.shortTitle ?? action.title,
icon: action.icon
) {
Task {
await tryOrDisplayError {
try await multipleSelectionViewModel.didTap(
action: action,
flushAlert: $flushAlert
)
}
.disabled(action == .archive && splitViewManager.selectedFolder?.role == .archive)
}

ToolbarButton(
text: MailResourcesStrings.Localizable.buttonMore,
icon: MailResourcesAsset.plusActions.swiftUIImage
) {
multipleSelectionActionsTarget = .threads(Array(multipleSelectionViewModel.selectedItems), true)
}
}
.disabled(multipleSelectionViewModel.selectedItems.isEmpty)
.disabled(action == .archive && splitViewManager.selectedFolder?.role == .archive)
}

ToolbarButton(
text: MailResourcesStrings.Localizable.buttonMore,
icon: MailResourcesAsset.plusActions.swiftUIImage
) {
multipleSelectionActionsTarget = .threads(Array(multipleSelectionViewModel.selectedItems), true)
}
}
.disabled(multipleSelectionViewModel.selectedItems.isEmpty)
}
.actionsPanel(actionsTarget: $multipleSelectionActionsTarget) {
withAnimation {
Expand Down
19 changes: 1 addition & 18 deletions Mail/Views/Thread/MessageHeaderDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,6 @@ import RealmSwift
import SwiftUI
import WrappingHStack

struct ViewWidthKey: PreferenceKey {
static var defaultValue: CGFloat = .zero

static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}

struct ViewGeometry: View {
var body: some View {
GeometryReader { geometry in
Color.clear
.preference(key: ViewWidthKey.self, value: geometry.size.width)
}
}
}

struct MessageHeaderDetailView: View {
@ObservedRealmObject var message: Message

Expand Down Expand Up @@ -109,7 +92,7 @@ struct RecipientLabel: View {
HStack(alignment: .top) {
Text(title)
.textStyle(.bodySmallSecondary)
.background(ViewGeometry())
.background(ViewGeometry(key: ViewWidthKey.self, property: \.size.width))
.frame(width: labelWidth, alignment: .leading)
VStack(alignment: .leading, spacing: 4) {
ForEach(recipients, id: \.self) { recipient in
Expand Down
51 changes: 26 additions & 25 deletions Mail/Views/Thread/ThreadView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ struct ThreadView: View {
var body: some View {
ScrollView {
VStack(spacing: 0) {
GeometryReader { geometry in
GeometryReader { proxy in
Color.clear.preference(
key: ScrollOffsetPreferenceKey.self,
value: geometry.frame(in: .named("scrollView")).origin
value: proxy.frame(in: .named("scrollView")).origin
)
}
.frame(width: 0, height: 0)
Expand Down Expand Up @@ -100,32 +100,33 @@ struct ThreadView: View {
.foregroundColor(thread.flagged ? MailResourcesAsset.yellowColor.swiftUIColor : .accentColor)
}
}
ToolbarItemGroup(placement: .bottomBar) {
ForEach(toolbarActions) { action in
if action == .reply {
ToolbarButton(text: action.title, icon: action.icon) {
didTap(action: action)
}
.adaptivePanel(item: $replyOrReplyAllMessage) { message in
ReplyActionsView(
mailboxManager: mailboxManager,
message: message,
messageReply: $navigationStore.messageReply
)
}
} else {
ToolbarButton(text: action.title, icon: action.icon) {
didTap(action: action)
}
.disabled(action == .archive && thread.folder?.role == .archive)
}
.bottomBar {
ForEach(toolbarActions) { action in
if action == .reply {
ToolbarButton(text: action.title, icon: action.icon) {
didTap(action: action)
}
Spacer()
}
ActionsPanelButton(threads: [thread]) {
ToolbarButtonLabel(text: MailResourcesStrings.Localizable.buttonMore,
icon: MailResourcesAsset.plusActions.swiftUIImage)
.adaptivePanel(item: $replyOrReplyAllMessage) { message in
ReplyActionsView(
mailboxManager: mailboxManager,
message: message,
messageReply: $navigationStore.messageReply
)
}
} else {
ToolbarButton(text: action.title, icon: action.icon) {
didTap(action: action)
}
.disabled(action == .archive && thread.folder?.role == .archive)
}
Spacer()
}
ActionsPanelButton(threads: [thread]) {
ToolbarButtonLabel(text: MailResourcesStrings.Localizable.buttonMore,
icon: MailResourcesAsset.plusActions.swiftUIImage)
}
.frame(maxWidth: .infinity)
}
.onChange(of: thread.messages) { newMessagesList in
if newMessagesList.isEmpty || thread.messageInFolderCount == 0 {
Expand Down
4 changes: 4 additions & 0 deletions MailCore/UI/UIConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ public enum UIConstants {
public static let buttonsRadius: CGFloat = 16
public static let buttonsIconSize: CGFloat = 16

public static let bottomBarVerticalPadding: CGFloat = 8
public static let bottomBarSmallVerticalPadding: CGFloat = 4
public static let bottomBarHorizontalMinimumSpace: CGFloat = 8

public static let bottomSheetHorizontalPadding: CGFloat = 24

public static let componentsMaxWidth: CGFloat = 496
Expand Down

0 comments on commit cfd23c9

Please sign in to comment.