Add nickname validation to prevent empty names

- Validate nickname only when field loses focus or on submit
- Replace empty nicknames with anon+random 4 digits (e.g. anon3847)
- Remove auto-save timer to prevent validation while typing
- Add FocusState to detect when user exits the field
This commit is contained in:
jack
2025-07-24 12:16:23 +02:00
parent c4ca38654d
commit cc3a094205
2 changed files with 17 additions and 12 deletions
+9 -9
View File
@@ -18,14 +18,7 @@ import UIKit
class ChatViewModel: ObservableObject { class ChatViewModel: ObservableObject {
@Published var messages: [BitchatMessage] = [] @Published var messages: [BitchatMessage] = []
@Published var connectedPeers: [String] = [] @Published var connectedPeers: [String] = []
@Published var nickname: String = "" { @Published var nickname: String = ""
didSet {
nicknameSaveTimer?.invalidate()
nicknameSaveTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in
self.saveNickname()
}
}
}
@Published var isConnected = false @Published var isConnected = false
@Published var privateChats: [String: [BitchatMessage]] = [:] // peerID -> messages @Published var privateChats: [String: [BitchatMessage]] = [:] // peerID -> messages
@Published var selectedPrivateChatPeer: String? = nil @Published var selectedPrivateChatPeer: String? = nil
@@ -42,7 +35,6 @@ class ChatViewModel: ObservableObject {
var meshService = BluetoothMeshService() var meshService = BluetoothMeshService()
private let userDefaults = UserDefaults.standard private let userDefaults = UserDefaults.standard
private let nicknameKey = "bitchat.nickname" private let nicknameKey = "bitchat.nickname"
private var nicknameSaveTimer: Timer?
@Published var favoritePeers: Set<String> = [] // Now stores public key fingerprints instead of peer IDs @Published var favoritePeers: Set<String> = [] // Now stores public key fingerprints instead of peer IDs
private var peerIDToPublicKeyFingerprint: [String: String] = [:] // Maps ephemeral peer IDs to persistent fingerprints private var peerIDToPublicKeyFingerprint: [String: String] = [:] // Maps ephemeral peer IDs to persistent fingerprints
@@ -172,6 +164,14 @@ class ChatViewModel: ObservableObject {
meshService.sendBroadcastAnnounce() meshService.sendBroadcastAnnounce()
} }
func validateAndSaveNickname() {
// Check if nickname is empty or just whitespace
if nickname.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
nickname = "anon\(Int.random(in: 1000...9999))"
}
saveNickname()
}
private func loadFavorites() { private func loadFavorites() {
// Load favorites from secure storage // Load favorites from secure storage
favoritePeers = SecureIdentityStateManager.shared.getFavorites() favoritePeers = SecureIdentityStateManager.shared.getFavorites()
+8 -3
View File
@@ -25,6 +25,7 @@ struct ContentView: View {
@State private var showMessageActions = false @State private var showMessageActions = false
@State private var selectedMessageSender: String? @State private var selectedMessageSender: String?
@State private var selectedMessageSenderID: String? @State private var selectedMessageSenderID: String?
@FocusState private var isNicknameFieldFocused: Bool
private var backgroundColor: Color { private var backgroundColor: Color {
colorScheme == .dark ? Color.black : Color.white colorScheme == .dark ? Color.black : Color.white
@@ -727,11 +728,15 @@ struct ContentView: View {
.font(.system(size: 14, design: .monospaced)) .font(.system(size: 14, design: .monospaced))
.frame(maxWidth: 100) .frame(maxWidth: 100)
.foregroundColor(textColor) .foregroundColor(textColor)
.onChange(of: viewModel.nickname) { _ in .focused($isNicknameFieldFocused)
viewModel.saveNickname() .onChange(of: isNicknameFieldFocused) { isFocused in
if !isFocused {
// Only validate when losing focus
viewModel.validateAndSaveNickname()
}
} }
.onSubmit { .onSubmit {
viewModel.saveNickname() viewModel.validateAndSaveNickname()
} }
} }