commit 767d29a66d4fd810346eadc87cf5b3f9d1cb1e49
parent 33a3e34f8cfee4d2ddc553a855b0d3bfaa8e0cb0
Author: Michael Camilleri <[email protected]>
Date: Thu, 11 Jun 2026 12:41:00 +0900
Add profile name to Settings view
Diffstat:
1 file changed, 76 insertions(+), 0 deletions(-)
diff --git a/Crossmate/Views/SettingsView.swift b/Crossmate/Views/SettingsView.swift
@@ -16,6 +16,22 @@ struct SettingsView: View {
@Bindable var preferences = preferences
NavigationStack {
Form {
+ Section {
+ NavigationLink {
+ ProfileNameEditView()
+ } label: {
+ HStack {
+ Text("Name")
+ Spacer()
+ Text(preferences.name)
+ .foregroundStyle(.secondary)
+ .lineLimit(1)
+ }
+ }
+ } header: {
+ Text("Profile")
+ }
+
Section("External Source") {
Picker("Publisher", selection: $externalSource) {
Text("None").tag(nil as ExternalSource?)
@@ -162,3 +178,63 @@ struct SettingsView: View {
}
}
+private struct ProfileNameEditView: View {
+ @Environment(PlayerPreferences.self) private var preferences
+ @State private var nameDraft = ""
+ @FocusState private var isNameFocused: Bool
+
+ var body: some View {
+ Form {
+ Section {
+ HStack {
+ TextField("Name", text: $nameDraft)
+ .textInputAutocapitalization(.never)
+ .autocorrectionDisabled()
+ .focused($isNameFocused)
+ .onSubmit(commitName)
+
+ if !nameDraft.isEmpty {
+ Button {
+ nameDraft = ""
+ isNameFocused = true
+ } label: {
+ Image(systemName: "xmark.circle.fill")
+ .foregroundStyle(.secondary)
+ }
+ .buttonStyle(.plain)
+ .accessibilityLabel("Clear Name")
+ }
+ }
+ } footer: {
+ Text("This is the name other players will see.")
+ }
+ }
+ .navigationTitle("Name")
+ .navigationBarTitleDisplayMode(.inline)
+ .onAppear {
+ nameDraft = preferences.name
+ }
+ .onChange(of: isNameFocused) { _, isFocused in
+ if !isFocused {
+ commitName()
+ }
+ }
+ .onDisappear {
+ commitName()
+ }
+ }
+
+ private var trimmedName: String {
+ nameDraft.trimmingCharacters(in: .whitespacesAndNewlines)
+ }
+
+ private var canCommitName: Bool {
+ !trimmedName.isEmpty && trimmedName != preferences.name
+ }
+
+ private func commitName() {
+ guard canCommitName else { return }
+ preferences.name = trimmedName
+ nameDraft = trimmedName
+ }
+}