Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct ReactionSelectionView: View {
@State private var xOffset: CGFloat = 0.0
@State private var yOffset: CGFloat = 0.0
@State private var viewState: ViewState = .initial
@Binding var chatViewFrame: CGRect

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it a binding here? you are not changing it inside ReactionSelectionView, right?


@State private var bubbleDiameter: CGFloat = .zero

Expand Down Expand Up @@ -177,7 +178,7 @@ struct ReactionSelectionView: View {
Color.clear.viewWidth(max(1, leadingPadding - 8))
Spacer()
} else {
let additionalPadding = max(0, UIScreen.main.bounds.width - maxSelectionRowWidth - trailingPadding)
let additionalPadding = max(0, chatViewFrame.width - maxSelectionRowWidth - trailingPadding)
Color.clear.viewWidth(additionalPadding + trailingPadding * 3)
}
}
Expand All @@ -188,7 +189,7 @@ struct ReactionSelectionView: View {
Spacer()
Color.clear.viewWidth(trailingPadding)
} else {
let additionalPadding = max(0, UIScreen.main.bounds.width - maxSelectionRowWidth - leadingPadding)
let additionalPadding = max(0, chatViewFrame.width - maxSelectionRowWidth - leadingPadding)
Color.clear.viewWidth(additionalPadding + trailingPadding * 3)
}
}
Expand Down Expand Up @@ -287,16 +288,16 @@ struct ReactionSelectionView: View {
/// - Note: If the messageFrame's width is equal to, or larger than, the Screens width then we skip the offset animation
/// - Note: This also prevents the offset animation from occuring when the user uses a custom message builder
private func getXOffset() -> CGFloat {
guard viewModel.messageFrame.width < UIScreen.main.bounds.width else { return .leastNonzeroMagnitude }
guard viewModel.messageFrame.width < chatViewFrame.width else { return .leastNonzeroMagnitude }
switch viewState {
case .initial, .row:
return .leastNonzeroMagnitude
case .search, .picked:
if alignment == .left {
let additionalPadding = max(0, UIScreen.main.bounds.width - maxSelectionRowWidth - leadingPadding) - UIApplication.safeArea.leading
return -((UIScreen.main.bounds.width - (additionalPadding + trailingPadding * 3) - (bubbleDiameter * 0.8)) - viewModel.messageFrame.maxX)
let additionalPadding = max(0, chatViewFrame.width - maxSelectionRowWidth - leadingPadding) - UIApplication.safeArea.leading
return -((chatViewFrame.width - (additionalPadding + trailingPadding * 3) - (bubbleDiameter * 0.8)) - viewModel.messageFrame.maxX)
} else {
let additionalPadding = max(0, UIScreen.main.bounds.width - maxSelectionRowWidth - trailingPadding) - UIApplication.safeArea.leading
let additionalPadding = max(0, chatViewFrame.width - maxSelectionRowWidth - trailingPadding) - UIApplication.safeArea.leading
return viewModel.messageFrame.minX - ((additionalPadding + trailingPadding * 3) + (bubbleDiameter * 0.8))
}
}
Expand All @@ -307,7 +308,7 @@ struct ReactionSelectionView: View {
/// - Note: If the messageFrame's width is equal to, or larger than, the Screens width then we skip the offset animation
/// - Note: This also prevents the offset animation from occuring when the user uses a custom message builder
private func getYOffset() -> CGFloat {
guard viewModel.messageFrame.width < UIScreen.main.bounds.width else { return .leastNonzeroMagnitude }
guard viewModel.messageFrame.width < chatViewFrame.width else { return .leastNonzeroMagnitude }
switch viewState {
case .initial, .row:
return .leastNonzeroMagnitude
Expand Down Expand Up @@ -396,6 +397,7 @@ internal struct InteriorRadialShadow: ViewModifier {
VStack {
ReactionSelectionView(
viewModel: ChatViewModel(),
chatViewFrame: .constant(UIScreen.main.bounds),
backgroundColor: .gray,
selectedColor: .blue,
animation: .linear(duration: 0.2),
Expand Down
118 changes: 66 additions & 52 deletions Sources/ExyteChat/Views/MessageView/MessageMenu/MessageMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct MessageMenu<MainButton: View, ActionEnum: MessageMenuAction>: View {
@Binding var isShowingMenu: Bool

/// Overall ChatView Frame
let chatViewFrame: CGRect = UIScreen.main.bounds
@State private var chatViewFrame: CGRect = .zero

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's the size of the whole chat, it should be calculated on a chat view, not inside a menu. that will allow to only do it once, and not for each menu showing

an important question: why use this size for calculations at all? is there probably a way to avoid this completely? for landscape check, there is an orientation environment var I believe; for width .infinity width would achieve the same result; verticalOffset of 2 screen heights probably just means off-screen etc so could you please check if this can be avoided?


/// The max height for the menu
/// - Note: menus that exceed this value will be placed in a ScrollView
Expand Down Expand Up @@ -152,62 +152,75 @@ struct MessageMenu<MainButton: View, ActionEnum: MessageMenuAction>: View {
}

public var body: some View {
ZStack(alignment: .top) {

// Reaction Overview Rectangle
if reactionOverviewIsVisible, case .vStack = messageMenuStyle {
ReactionOverview(viewModel: viewModel, message: message, width: reactionOverviewWidth, backgroundColor: theme.colors.messageFriendBG, inScrollView: false)
.frame(width: reactionOverviewWidth)
.maxHeightGetter($reactionOverviewHeight)
.offset(y: UIApplication.safeArea.top)
.transition(defaultTransition)
GeometryReader { geometry in

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a frameGetter modifier in Utils in this project, could you please use that one - the syntax is easier, and you won't have to use additional indentaion

also GeometryReader is expensive, so could you please make sure it only applied for ipads, since ios doesn't need this?

ZStack(alignment: .top) {

// Reaction Overview Rectangle
if reactionOverviewIsVisible, case .vStack = messageMenuStyle {
ReactionOverview(viewModel: viewModel, message: message, width: reactionOverviewWidth, backgroundColor: theme.colors.messageFriendBG, inScrollView: false)
.frame(width: reactionOverviewWidth)
.maxHeightGetter($reactionOverviewHeight)
.offset(y: UIApplication.safeArea.top)
.transition(defaultTransition)
.opacity(messageMenuOpacity)
}

// Some views to help debug layout and animations
//debugViews()

// The message and menu view
messageMenuView()
.frameGetter($messageMenuFrame)
.position(x: chatViewFrame.width / 2 + horizontalOffset, y: verticalOffset)
.opacity(messageMenuOpacity)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove the extra \n

}

// Some views to help debug layout and animations
//debugViews()

// The message and menu view
messageMenuView()
.frameGetter($messageMenuFrame)
.position(x: chatViewFrame.width / 2 + horizontalOffset, y: verticalOffset)
.opacity(messageMenuOpacity)

}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
.background(
ZStack {
Rectangle()
.foregroundStyle(.ultraThinMaterial)
Rectangle()
.fill(.primary.opacity(0.1))
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
.opacity(backgroundOpacity)
.onTapGesture {
if viewState == .keyboard {
keyboardState.resignFirstResponder()
.background(
ZStack {
Rectangle()
.foregroundStyle(.ultraThinMaterial)
Rectangle()
.fill(.primary.opacity(0.1))
}
.edgesIgnoringSafeArea(.all)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong alignment here, please make sure the formatting is neat

.opacity(backgroundOpacity)
.onTapGesture {
if viewState == .keyboard {
keyboardState.resignFirstResponder()
transitionViewState(to: .ready)
} else {
dismissSelf()
}
}
)
.onAppear {
chatViewFrame = geometry.frame(in: .global)

transitionViewState(to: .prepare)

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(animationDuration * 333))) {
transitionViewState(to: .original)
}

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(animationDuration * 666))) {
transitionViewState(to: .ready)
} else {
dismissSelf()
}
}
)
.onAppear {
transitionViewState(to: .prepare)

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(animationDuration * 333))) {
transitionViewState(to: .original)
}

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(animationDuration * 666))) {
transitionViewState(to: .ready)
.onChange(of: keyboardState.keyboardFrame) {
if viewState == .ready, keyboardState.isShown {
transitionViewState(to: .keyboard)
}
}
}
.onChange(of: keyboardState.keyboardFrame) {
if viewState == .ready, keyboardState.isShown {
transitionViewState(to: .keyboard)
.onChange(of: geometry.size) { _ , newSize in
chatViewFrame = CGRect(
origin: chatViewFrame.origin,
size: CGSize(width: newSize.width, height: newSize.height)
)

// Recalculate reaction overview width
reactionOverviewWidth = chatViewFrame.width - UIApplication.safeArea.leading - UIApplication.safeArea.trailing
}
}
}
Expand All @@ -231,7 +244,7 @@ struct MessageMenu<MainButton: View, ActionEnum: MessageMenuAction>: View {
reactionOverviewIsVisible = shouldShowReactionOverviewView
reactionSelectionIsVisible = shouldShowReactionSelectionView
menuIsVisible = true
verticalOffset = UIScreen.main.bounds.height * 2
verticalOffset = chatViewFrame.height * 2

/// Kick off the background animation
withAnimation(.easeInOut(duration: animationDuration)) {
Expand All @@ -250,7 +263,7 @@ struct MessageMenu<MainButton: View, ActionEnum: MessageMenuAction>: View {
}

/// If we're in landscape mode, adjust the `horizontalOffset` appropriately
if UIScreen.main.bounds.width > UIScreen.main.bounds.height {
if chatViewFrame.width > chatViewFrame.height {
switch alignment {
case .left:
horizontalOffset = UIApplication.safeArea.leading
Expand Down Expand Up @@ -456,6 +469,7 @@ struct MessageMenu<MainButton: View, ActionEnum: MessageMenuAction>: View {
if reactionSelectionIsVisible {
ReactionSelectionView(
viewModel: viewModel,
chatViewFrame: $chatViewFrame,
backgroundColor: theme.colors.messageFriendBG,
selectedColor: theme.colors.messageMyBG,
animation: .bouncy(duration: animationDuration),
Expand Down
Loading