Skip to content
Merged
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 @@ -39,6 +39,8 @@ struct ChatScreenRepresentable: UIViewControllerRepresentable {
let onSendCash: () -> Void
let conversationController: ConversationController
let barModel: ConversationBarModel
/// Whether this is a tip DM — the send button then stays minimized.
let isTipDm: Bool

func makeUIViewController(context: Context) -> ChatScreenViewController {
let barHost = UIHostingController(rootView: bar(coordinator: context.coordinator))
Expand Down Expand Up @@ -96,7 +98,8 @@ struct ChatScreenRepresentable: UIViewControllerRepresentable {
conversationID: conversationID,
symbol: symbol,
onSendCash: onSendCash,
model: barModel
model: barModel,
isTipDm: isTipDm
)
.environment(conversationController)
.modifier(MeasuredBarHeight { coordinator.screen?.setBarHeight($0) })
Expand Down
28 changes: 20 additions & 8 deletions Flipcash/Core/Screens/Conversation/ConversationBottomBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ struct ConversationBottomBar: View {
let symbol: String
let onSendCash: () -> Void
let model: ConversationBarModel
/// Tip chats always show the compact symbol-only send button; ordinary
/// chats expand to "Send €" at rest and collapse only while composing.
var isTipDm: Bool = false

var body: some View {
let content = HStack(alignment: .bottom, spacing: 10) {
Expand All @@ -54,6 +57,7 @@ struct ConversationBottomBar: View {
symbol: symbol,
composing: model.isComposing,
standalone: !chatExists,
alwaysMinimized: isTipDm,
action: onSendCash
)
}
Expand Down Expand Up @@ -170,8 +174,9 @@ private struct BarGradientBackground: ViewModifier {
}

/// The Send Cash button, rendered as a white "Send €" pill at rest and a
/// compact glass "€" square while composing. Alone in the bar it takes the
/// standard filled-button size; beside the composer it's field-sized.
/// compact glass "€" square while composing (or always, in a tip chat). Alone
/// in the bar it takes the standard filled-button size; beside the composer
/// it's field-sized.
// One persistent view: the morph animates its properties (prefix text, fill,
// width, color) in lockstep — splitting the two states into separate views
// would crossfade instead of morphing.
Expand All @@ -182,8 +187,15 @@ struct SendCashMorphButton: View {
/// Whether the button is the bar's only control (no chat yet): it spans
/// the bar at the standard filled-button size instead of field-sized.
let standalone: Bool
/// Forces the compact symbol-only presentation regardless of composing.
/// Tip chats always show it minimized; ordinary chats expand at rest.
var alwaysMinimized: Bool = false
let action: () -> Void

/// The compact glass "€" presentation: while composing, or always in a tip
/// chat. The whole morph (label, fill, width, color) keys off this.
private var minimized: Bool { composing || alwaysMinimized }

private var height: CGFloat {
standalone ? Metrics.buttonHeight : BarMetrics.contentHeight
}
Expand All @@ -195,24 +207,24 @@ struct SendCashMorphButton: View {
var body: some View {
Button(action: action) {
HStack(spacing: 4) {
if !composing {
if !minimized {
Text("Send")
.font(.appTextMedium)
.transition(.opacity)
}
Text(symbol)
// Same persistent Text — .interpolate animates the glyph
// between sizes; swapping views would crossfade.
.font(composing ? .appTextXL : .appTextMedium)
.font(minimized ? .appTextXL : .appTextMedium)
.contentTransition(.interpolate)
}
.foregroundStyle(composing ? Color.textMain : Color.textAction)
.foregroundStyle(minimized ? Color.textMain : Color.textAction)
// The label must never reflow to "Se…" mid-morph; overflow is
// clipped by the shape instead.
.fixedSize()
.padding(.horizontal, composing ? 0 : 20)
.padding(.horizontal, minimized ? 0 : 20)
.frame(minWidth: BarMetrics.contentHeight)
.frame(maxWidth: standalone && !composing ? .infinity : nil)
.frame(maxWidth: standalone && !minimized ? .infinity : nil)
.frame(height: height)
}
.buttonStyle(.plain)
Expand All @@ -221,7 +233,7 @@ struct SendCashMorphButton: View {
.background {
RoundedRectangle(cornerRadius: cornerRadius)
.fill(Color.action)
.opacity(composing ? 0 : 1)
.opacity(minimized ? 0 : 1)
}
.glassBackground(cornerRadius: cornerRadius)
.clipShape(RoundedRectangle(cornerRadius: cornerRadius))
Expand Down
3 changes: 2 additions & 1 deletion Flipcash/Core/Screens/Conversation/ConversationScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ struct ConversationScreen: View {
symbol: ratesController.balanceCurrency.compactSymbol,
onSendCash: sendCash,
conversationController: conversationController,
barModel: barModel
barModel: barModel,
isTipDm: tipCounterpart != nil
)
.ignoresSafeArea(.keyboard)
// Extend the transcript under the navigation bar so content scrolls beneath it — that's
Expand Down