mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 16:24:11 +00:00
157 lines
6.0 KiB
Swift
157 lines
6.0 KiB
Swift
//
|
|
// Copyright 2026 Element Creations Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
// Please see LICENSE files in the repository root for full details.
|
|
//
|
|
|
|
import Compound
|
|
import SwiftUI
|
|
|
|
struct SettingsScreenUserStatusRow: View {
|
|
enum Mode: Equatable {
|
|
case pickStatusButton, customStatusInput(emoji: Character), showingStatus(UserStatus.Displayed)
|
|
|
|
var isCustomStatusInput: Bool {
|
|
switch self {
|
|
case .customStatusInput: true
|
|
default: false
|
|
}
|
|
}
|
|
}
|
|
|
|
let mode: Mode
|
|
let action: (SettingsScreenViewAction.UserStatusAction) -> Void
|
|
|
|
@State private var customText = ""
|
|
@FocusState private var isCustomFieldFocused: Bool
|
|
|
|
var body: some View {
|
|
rowContent
|
|
.onChange(of: mode.isCustomStatusInput) { _, newValue in
|
|
guard newValue else { return }
|
|
customText = ""
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
var rowContent: some View {
|
|
switch mode {
|
|
case .pickStatusButton:
|
|
ListRow(label: .default(title: L10n.screenSettingsUserStatusPlaceholder, icon: \.reaction),
|
|
kind: .button { action(.pickStatus) })
|
|
case .customStatusInput(let emoji):
|
|
ListRow(kind: .custom {
|
|
HStack(spacing: ListRowPadding.labelIconSpacing) {
|
|
Button { action(.pickCustomEmoji) } label: {
|
|
Text(String(emoji))
|
|
.font(.compound.headingSM)
|
|
.foregroundStyle(.compound.textPrimary)
|
|
.accessibilityLabel(L10n.a11yCustomEmoji)
|
|
.accessibilityValue(String(emoji))
|
|
}
|
|
.buttonStyle(EditEmojiButtonStyle())
|
|
|
|
TextField(L10n.screenSettingsUserStatusCustomHint, text: $customText)
|
|
.textFieldStyle(.compound(.raised))
|
|
.focused($isCustomFieldFocused)
|
|
.onAppear(perform: focusCustomField)
|
|
.onChange(of: customText) { _, newValue in
|
|
if newValue.count > 30 {
|
|
customText = String(newValue.prefix(30))
|
|
}
|
|
}
|
|
.accessibilityLabel(L10n.screenSettingsUserStatusCustomHint)
|
|
.padding(.vertical, 3)
|
|
|
|
ZStack { // ZStack to stop the text field from resizing.
|
|
Button(L10n.actionCancel) { action(.cancel) }
|
|
.opacity(customText.isEmpty ? 1 : 0)
|
|
Button(L10n.actionSave, action: saveCustomStatus)
|
|
.opacity(customText.isEmpty ? 0 : 1)
|
|
}
|
|
.buttonStyle(.compound(.textLink))
|
|
}
|
|
.listRowBackground(Color.clear)
|
|
})
|
|
case .showingStatus(let status):
|
|
ListRow(kind: .custom {
|
|
HStack(spacing: ListRowPadding.labelIconSpacing) {
|
|
Button { action(.pickStatus) } label: {
|
|
HStack(spacing: ListRowPadding.labelIconSpacing) {
|
|
CompoundIcon(\.reaction)
|
|
.hidden()
|
|
.overlay {
|
|
Text(String(status.emoji))
|
|
.font(.compound.bodyLG)
|
|
.foregroundStyle(.compound.textPrimary)
|
|
}
|
|
|
|
Text(status.text)
|
|
.font(.compound.bodyLG)
|
|
.foregroundStyle(.compound.textPrimary)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
}
|
|
.contentShape(Rectangle())
|
|
}
|
|
.accessibilityLabel(L10n.a11yStatus)
|
|
.accessibilityValue(Text(String(status.emoji)) + Text(status.text))
|
|
.buttonStyle(.plain)
|
|
|
|
Button(L10n.actionClear) { action(.clear) }
|
|
.buttonStyle(.compound(.textLink))
|
|
}
|
|
.padding(ListRowPadding.insets)
|
|
})
|
|
}
|
|
}
|
|
|
|
private func focusCustomField() {
|
|
guard !ProcessInfo.isRunningTests else { return }
|
|
isCustomFieldFocused = true
|
|
}
|
|
|
|
private func saveCustomStatus() {
|
|
guard case let .customStatusInput(emoji) = mode else { return }
|
|
action(.set(.init(text: customText, emoji: emoji)))
|
|
}
|
|
|
|
struct EditEmojiButtonStyle: ButtonStyle {
|
|
func makeBody(configuration: Configuration) -> some View {
|
|
configuration.label
|
|
.padding(12)
|
|
.background {
|
|
ZStack {
|
|
Circle().fill(.compound.bgCanvasDefaultLevel1)
|
|
Circle().inset(by: 0.5).stroke(.compound.borderInteractiveSecondary)
|
|
}
|
|
}
|
|
.drawingGroup()
|
|
.opacity(configuration.isPressed ? 0.6 : 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SettingsScreenUserStatusRow_Previews: PreviewProvider, TestablePreview {
|
|
static var previews: some View {
|
|
Form {
|
|
Section {
|
|
SettingsScreenUserStatusRow(mode: .pickStatusButton) { _ in }
|
|
}
|
|
|
|
Section {
|
|
SettingsScreenUserStatusRow(mode: .customStatusInput(emoji: "😄")) { _ in }
|
|
}
|
|
|
|
Section {
|
|
SettingsScreenUserStatusRow(mode: .showingStatus(.userSet(.init(text: "Away", emoji: "🌴")))) { _ in }
|
|
}
|
|
|
|
Section {
|
|
SettingsScreenUserStatusRow(mode: .showingStatus(.inCall(.init(joinedDate: nil)))) { _ in }
|
|
}
|
|
}
|
|
.compoundList()
|
|
}
|
|
}
|