mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 00:25:20 +00:00
Liquid Glass theme with in-app appearance switcher (#1337)
* Centralize UI theme colors into semantic ThemePalette tokens Introduce AppTheme/ThemePalette (Utils/Theme.swift) with an environment key and @ThemedPalette property wrapper, persisted via @AppStorage. Views now resolve background/primary/secondary/accentBlue/alertRed/ divider tokens from the environment instead of computing colors inline, removing the backgroundColor/textColor/secondaryTextColor prop-drilling through the header, composer, and people-sheet hierarchy. Matrix theme output is pixel-identical; this is groundwork for a user-selectable theme switcher. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add liquid glass theme with in-app appearance switcher Add a .liquidGlass AppTheme alongside the matrix terminal theme, selectable from a one-line APPEARANCE row in the app info sheet (persisted via @AppStorage, applies live). Liquid glass renders system fonts and colors over a subtle gradient backdrop, with the header and composer floating as Liquid Glass panels (real .glassEffect() on iOS/macOS 26, compiler-gated with an ultraThinMaterial fallback for older SDKs). The message list scrolls underneath the chrome via safe-area insets, and all sheets share the same backdrop and surface language. The matrix theme is unchanged. Details: - Theme is threaded through ChatMessageFormatter so message AttributedStrings switch font design per theme; the per-message format cache gains a variant key so themes never serve each other's cached strings - New palette tokens: accent (interactive tint) and locationAccent (geohash green), replacing scattered hardcoded greens/blues in the voice note, waveform, verification, and people-sheet views - Header controls get full-height tap targets and the people count becomes a real Button (previously a tap gesture on the cluster) - CommandSuggestionsView renders nothing when empty instead of a zero-height view that pushed the composer input off-center - New appearance strings localized for all 29 catalog languages Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
jack
Claude Fable 5
parent
c8381737bb
commit
af954b05ea
@@ -6,16 +6,14 @@ import UIKit
|
||||
struct ContentComposerView: View {
|
||||
@EnvironmentObject private var conversationUIModel: ConversationUIModel
|
||||
@EnvironmentObject private var privateConversationModel: PrivateConversationModel
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@Environment(\.appTheme) private var theme
|
||||
@ThemedPalette private var palette
|
||||
|
||||
@Binding var messageText: String
|
||||
var isTextFieldFocused: FocusState<Bool>.Binding
|
||||
@ObservedObject var voiceRecordingVM: VoiceRecordingViewModel
|
||||
@Binding var autocompleteDebounceTimer: Timer?
|
||||
|
||||
let backgroundColor: Color
|
||||
let textColor: Color
|
||||
let secondaryTextColor: Color
|
||||
let onSendMessage: () -> Void
|
||||
|
||||
#if os(iOS)
|
||||
@@ -35,8 +33,8 @@ struct ContentComposerView: View {
|
||||
}) {
|
||||
HStack {
|
||||
Text(suggestion)
|
||||
.font(.bitchatSystem(size: 11, design: .monospaced))
|
||||
.foregroundColor(textColor)
|
||||
.bitchatFont(size: 11)
|
||||
.foregroundColor(palette.primary)
|
||||
.fontWeight(.medium)
|
||||
Spacer()
|
||||
}
|
||||
@@ -48,20 +46,11 @@ struct ContentComposerView: View {
|
||||
.background(Color.gray.opacity(0.1))
|
||||
}
|
||||
}
|
||||
.background(backgroundColor)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 4)
|
||||
.stroke(secondaryTextColor.opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
.themedOverlayPanel()
|
||||
.padding(.horizontal, 12)
|
||||
}
|
||||
|
||||
CommandSuggestionsView(
|
||||
messageText: $messageText,
|
||||
textColor: textColor,
|
||||
backgroundColor: backgroundColor,
|
||||
secondaryTextColor: secondaryTextColor
|
||||
)
|
||||
CommandSuggestionsView(messageText: $messageText)
|
||||
|
||||
if voiceRecordingVM.state.isActive {
|
||||
recordingIndicator
|
||||
@@ -74,11 +63,11 @@ struct ContentComposerView: View {
|
||||
prompt: Text(
|
||||
String(localized: "content.input.message_placeholder", comment: "Placeholder shown in the chat composer")
|
||||
)
|
||||
.foregroundColor(secondaryTextColor.opacity(0.6))
|
||||
.foregroundColor(palette.secondary.opacity(0.6))
|
||||
)
|
||||
.textFieldStyle(.plain)
|
||||
.font(.bitchatSystem(size: 15, design: .monospaced))
|
||||
.foregroundColor(textColor)
|
||||
.bitchatFont(size: 15)
|
||||
.foregroundColor(palette.primary)
|
||||
.focused(isTextFieldFocused)
|
||||
.autocorrectionDisabled(true)
|
||||
#if os(iOS)
|
||||
@@ -86,12 +75,9 @@ struct ContentComposerView: View {
|
||||
#endif
|
||||
.submitLabel(.send)
|
||||
.onSubmit(onSendMessage)
|
||||
.padding(.vertical, 4)
|
||||
.padding(.vertical, theme.usesGlassChrome ? 8 : 4)
|
||||
.padding(.horizontal, 6)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
||||
.fill(colorScheme == .dark ? Color.black.opacity(0.35) : Color.white.opacity(0.7))
|
||||
)
|
||||
.themedInputBackground()
|
||||
.modifier(FocusEffectDisabledModifier())
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.onChange(of: messageText) { newValue in
|
||||
@@ -114,9 +100,9 @@ struct ContentComposerView: View {
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 6)
|
||||
.padding(.top, 6)
|
||||
.padding(.top, theme.usesGlassChrome ? 8 : 6)
|
||||
.padding(.bottom, 8)
|
||||
.background(backgroundColor.opacity(0.95))
|
||||
.themedChromePanel(edge: .bottom)
|
||||
.onDisappear {
|
||||
autocompleteDebounceTimer?.invalidate()
|
||||
}
|
||||
@@ -134,7 +120,7 @@ private extension ContentComposerView {
|
||||
"recording \(voiceRecordingVM.formattedDuration(for: context.date))",
|
||||
comment: "Voice note recording duration indicator"
|
||||
)
|
||||
.font(.bitchatSystem(size: 13, design: .monospaced))
|
||||
.bitchatFont(size: 13)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
Spacer()
|
||||
@@ -154,7 +140,7 @@ private extension ContentComposerView {
|
||||
}
|
||||
|
||||
var composerAccentColor: Color {
|
||||
privateConversationModel.selectedPeerID != nil ? Color.orange : textColor
|
||||
privateConversationModel.selectedPeerID != nil ? Color.orange : palette.accent
|
||||
}
|
||||
|
||||
var attachmentButton: some View {
|
||||
|
||||
Reference in New Issue
Block a user