@@ -29,7 +29,10 @@ struct WelcomeWindowView: View {
2929 @State private var selectedConnectionId : UUID ? // For keyboard navigation
3030 @State private var showOnboarding = !AppSettingsStorage. shared. hasCompletedOnboarding ( )
3131 @State private var groups : [ ConnectionGroup ] = [ ]
32- @State private var collapsedGroupIds : Set < UUID > = [ ]
32+ @State private var collapsedGroupIds : Set < UUID > = {
33+ let strings = UserDefaults . standard. stringArray ( forKey: " com.TablePro.collapsedGroupIds " ) ?? [ ]
34+ return Set ( strings. compactMap { UUID ( uuidString: $0) } )
35+ } ( )
3336 @State private var showNewGroupSheet = false
3437
3538 @Environment ( \. openWindow) private var openWindow
@@ -103,7 +106,7 @@ struct WelcomeWindowView: View {
103106 loadConnections ( )
104107 }
105108 . sheet ( isPresented: $showNewGroupSheet) {
106- NewGroupSheet { name, color in
109+ CreateGroupSheet { name, color in
107110 let group = ConnectionGroup ( name: name, color: color)
108111 groupStorage. addGroup ( group)
109112 groups = groupStorage. loadGroups ( )
@@ -339,6 +342,10 @@ struct WelcomeWindowView: View {
339342 } else {
340343 collapsedGroupIds. insert ( group. id)
341344 }
345+ UserDefaults . standard. set (
346+ Array ( collapsedGroupIds. map ( \. uuidString) ) ,
347+ forKey: " com.TablePro.collapsedGroupIds "
348+ )
342349 }
343350 }
344351 . contextMenu {
@@ -493,6 +500,10 @@ struct WelcomeWindowView: View {
493500 if alert. runModal ( ) == . alertFirstButtonReturn {
494501 let newName = textField. stringValue. trimmingCharacters ( in: . whitespaces)
495502 guard !newName. isEmpty else { return }
503+ let isDuplicate = groups. contains {
504+ $0. id != group. id && $0. name. lowercased ( ) == newName. lowercased ( )
505+ }
506+ guard !isDuplicate else { return }
496507 var updated = group
497508 updated. name = newName
498509 groupStorage. updateGroup ( updated)
@@ -502,11 +513,18 @@ struct WelcomeWindowView: View {
502513
503514 private func moveUngroupedConnections( from source: IndexSet , to destination: Int ) {
504515 let ungroupedIndices = connections. indices. filter { connections [ $0] . groupId == nil }
505- var ungroupedConns = ungroupedIndices. map { connections [ $0] }
506- ungroupedConns. move ( fromOffsets: source, toOffset: destination)
507516
508- let groupedConns = connections. filter { $0. groupId != nil }
509- connections = ungroupedConns + groupedConns
517+ let globalSource = IndexSet ( source. map { ungroupedIndices [ $0] } )
518+ let globalDestination : Int
519+ if destination < ungroupedIndices. count {
520+ globalDestination = ungroupedIndices [ destination]
521+ } else if let last = ungroupedIndices. last {
522+ globalDestination = last + 1
523+ } else {
524+ globalDestination = 0
525+ }
526+
527+ connections. move ( fromOffsets: globalSource, toOffset: globalDestination)
510528 storage. saveConnections ( connections)
511529 }
512530
@@ -536,66 +554,6 @@ struct WelcomeWindowView: View {
536554 }
537555}
538556
539- // MARK: - NewGroupSheet
540-
541- private struct NewGroupSheet : View {
542- @Environment ( \. dismiss) private var dismiss
543- @State private var groupName : String = " "
544- @State private var groupColor : ConnectionColor = . none
545- let onSave : ( String , ConnectionColor ) -> Void
546-
547- var body : some View {
548- VStack ( spacing: 16 ) {
549- Text ( " New Group " )
550- . font ( . headline)
551-
552- TextField ( " Group name " , text: $groupName)
553- . textFieldStyle ( . roundedBorder)
554- . frame ( width: 200 )
555-
556- VStack ( alignment: . leading, spacing: 6 ) {
557- Text ( " Color " )
558- . font ( . caption)
559- . foregroundStyle ( . secondary)
560- HStack ( spacing: 6 ) {
561- ForEach ( ConnectionColor . allCases) { color in
562- Circle ( )
563- . fill ( color == . none ? Color ( nsColor: . quaternaryLabelColor) : color. color)
564- . frame ( width: 14 , height: 14 )
565- . overlay (
566- Circle ( )
567- . stroke ( Color . primary, lineWidth: groupColor == color ? 2 : 0 )
568- . frame ( width: 18 , height: 18 )
569- )
570- . onTapGesture {
571- groupColor = color
572- }
573- }
574- }
575- }
576-
577- HStack {
578- Button ( " Cancel " ) {
579- dismiss ( )
580- }
581-
582- Button ( " Create " ) {
583- onSave ( groupName, groupColor)
584- dismiss ( )
585- }
586- . keyboardShortcut ( . return)
587- . buttonStyle ( . borderedProminent)
588- . disabled ( groupName. trimmingCharacters ( in: . whitespaces) . isEmpty)
589- }
590- }
591- . padding ( 20 )
592- . frame ( width: 300 )
593- . onExitCommand {
594- dismiss ( )
595- }
596- }
597- }
598-
599557// MARK: - ConnectionRow
600558
601559private struct ConnectionRow : View {
0 commit comments