mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-10-29 21:53:43 +00:00
refactor(servers): replace group rename alert with a sheet
The pre-filled current name in the rename alert only showed on the first presentation: SwiftUI on macOS recycles the alert panel and its TextField does not pick up binding changes made in the same update as re-presenting. Swap the alert for a RenameGroupSheet modeled on NewGroupSheet, presented via sheet(item:) so content state is rebuilt each time and the prefill always matches the target group. As with the creation form, a failed rename now keeps the sheet open with the entered name instead of closing the alert first and losing the input. The NodeContext adapter previously used by the move sheet is shared by both presentations. Add the manual catalog keys 重命名分组 (Rename Group) and 名称 (Name); 保存/取消 already existed.
This commit is contained in:
@@ -1100,6 +1100,28 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"名称": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Name"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"重命名分组": {
|
||||
"extractionState": "manual",
|
||||
"localizations": {
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Rename Group"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": "1.0"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import SwiftUI
|
||||
|
||||
/// 重命名分组表单:名称初值取现名;失败保留名称,成功才关闭。
|
||||
struct RenameGroupSheet: View {
|
||||
let workflow: CatalogWorkflow
|
||||
let errors: ErrorAlertPresenter
|
||||
let nodeID: NodeID
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State private var name: String
|
||||
@State private var isSubmitting = false
|
||||
@FocusState private var nameFocused: Bool
|
||||
|
||||
init(workflow: CatalogWorkflow, errors: ErrorAlertPresenter, nodeID: NodeID) {
|
||||
self.workflow = workflow
|
||||
self.errors = errors
|
||||
self.nodeID = nodeID
|
||||
// 打开时的现名仅作为初值,后续编辑由本表单持有。
|
||||
_name = State(initialValue: workflow.displayName(for: nodeID))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Text("重命名分组").font(.title2)
|
||||
TextField("名称", text: $name)
|
||||
.focused($nameFocused)
|
||||
HStack {
|
||||
Spacer()
|
||||
Button("取消", role: .cancel) { dismiss() }
|
||||
Button("保存") { rename() }
|
||||
.keyboardShortcut(.defaultAction)
|
||||
}
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 360)
|
||||
.disabled(isSubmitting)
|
||||
.interactiveDismissDisabled(isSubmitting)
|
||||
.defaultFocus($nameFocused, true)
|
||||
}
|
||||
|
||||
private func rename() {
|
||||
guard !isSubmitting else { return }
|
||||
isSubmitting = true
|
||||
Task {
|
||||
defer { isSubmitting = false }
|
||||
do {
|
||||
try await workflow.renameGroup(nodeID, to: name)
|
||||
dismiss()
|
||||
} catch {
|
||||
errors.present(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ struct ServersView: View {
|
||||
|
||||
// 纯窗口状态(issue #41):selection/sheet/alert 不进目录 module。
|
||||
@State private var renameTarget: NodeID?
|
||||
@State private var renameText = ""
|
||||
@State private var newGroupParent: NodeID?
|
||||
@State private var isPresentingNewGroup = false
|
||||
@State private var serverFormOperation: ServerFormSheet.Operation?
|
||||
@@ -45,15 +44,12 @@ struct ServersView: View {
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
.frame(minHeight: 420)
|
||||
.alert(
|
||||
"重命名分组",
|
||||
isPresented: Binding(
|
||||
get: { renameTarget != nil },
|
||||
set: { if !$0 { renameTarget = nil } })
|
||||
) {
|
||||
TextField("名称", text: $renameText)
|
||||
Button("确定") { commitRename() }
|
||||
Button("取消", role: .cancel) { renameTarget = nil }
|
||||
.sheet(
|
||||
item: Binding(
|
||||
get: { renameTarget.map(NodeContext.init) },
|
||||
set: { renameTarget = $0?.nodeID })
|
||||
) { context in
|
||||
RenameGroupSheet(workflow: workflow, errors: errors, nodeID: context.nodeID)
|
||||
}
|
||||
.sheet(isPresented: $isPresentingNewGroup) {
|
||||
NewGroupSheet(
|
||||
@@ -75,7 +71,7 @@ struct ServersView: View {
|
||||
}
|
||||
.sheet(
|
||||
item: Binding(
|
||||
get: { moveTarget.map(MoveContext.init) },
|
||||
get: { moveTarget.map(NodeContext.init) },
|
||||
set: { moveTarget = $0?.nodeID })
|
||||
) { context in
|
||||
MoveNodeSheet(workflow: workflow, errors: errors, nodeID: context.nodeID)
|
||||
@@ -146,10 +142,7 @@ struct ServersView: View {
|
||||
activeTargetID: activeTargetID,
|
||||
errors: errors,
|
||||
onEdit: presentEditServer,
|
||||
onRename: { id in
|
||||
renameTarget = id
|
||||
renameText = workflow.displayName(for: id)
|
||||
},
|
||||
onRename: { renameTarget = $0 },
|
||||
onNewGroup: { parent in
|
||||
presentNewGroup(in: parent)
|
||||
},
|
||||
@@ -362,18 +355,6 @@ extension ServersView {
|
||||
}
|
||||
}
|
||||
|
||||
private func commitRename() {
|
||||
guard let id = renameTarget else { return }
|
||||
renameTarget = nil
|
||||
Task {
|
||||
do {
|
||||
try await workflow.renameGroup(id, to: renameText)
|
||||
} catch {
|
||||
errors.present(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 删除确认文案:档位与规模事实来自 seam;句子由 UI 拼(Q3-A)。
|
||||
private var deleteTitle: String {
|
||||
guard let id = deleteTarget else { return "" }
|
||||
@@ -413,8 +394,8 @@ extension ServersView {
|
||||
}
|
||||
}
|
||||
|
||||
/// moveTarget 的 sheet(item:) 适配壳。
|
||||
private struct MoveContext: Identifiable {
|
||||
/// moveTarget/renameTarget 的 sheet(item:) 适配壳。
|
||||
private struct NodeContext: Identifiable {
|
||||
let nodeID: NodeID
|
||||
var id: NodeID { nodeID }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user