diff --git a/assets/zh-Hans.lproj/Localizable.strings b/assets/zh-Hans.lproj/Localizable.strings index c0bba24..c9312af 100644 Binary files a/assets/zh-Hans.lproj/Localizable.strings and b/assets/zh-Hans.lproj/Localizable.strings differ diff --git a/src/config/importtable.swift b/src/config/importtable.swift new file mode 100644 index 0000000..266fd48 --- /dev/null +++ b/src/config/importtable.swift @@ -0,0 +1,94 @@ +import Fcitx +import Logging +import SwiftUI + +class ImportTableVM: ObservableObject { + // Record IMs and auto add new ones. + @Published private(set) var ims = [String]() + var onError: (String) -> Void = { _ in } + var finalize: () -> Void = {} + + func setHandler(onError: @escaping (String) -> Void, finalize: @escaping () -> Void) { + self.onError = onError + self.finalize = finalize + } + + func load() { + ims = getFileNamesWithExtension(imLocalDir.localPath(), ".conf") + } +} + +private func convertTxt() -> [String] { + let converter = libraryDir.appendingPathComponent("bin/libime_tabledict").localPath() + let tables = getFileNamesWithExtension(tableLocalDir.localPath(), ".txt") + return tables.filter({ table in + let src = tableLocalDir.appendingPathComponent("\(table).txt") + return + !(exec( + converter, + [src.localPath(), tableLocalDir.appendingPathComponent("\(table).dict").localPath()]) + && removeFile(src)) + }) +} + +struct ImportTableView: View { + @Environment(\.presentationMode) var presentationMode + + @ObservedObject private var importTableVM = ImportTableVM() + + func load(onError: @escaping (String) -> Void, finalize: @escaping () -> Void) -> some View { + mkdirP(imLocalDir.localPath()) + mkdirP(tableLocalDir.localPath()) + importTableVM.setHandler(onError: onError, finalize: finalize) + importTableVM.load() + return self + } + + var body: some View { + VStack { + Button { + NSWorkspace.shared.open(imLocalDir) + } label: { + Text("Copy \\*.conf to this directory") + } + Button { + NSWorkspace.shared.open(tableLocalDir) + } label: { + Text("Copy \\*.dict/\\*.txt to this directory") + } + + Spacer().frame(height: gapSize) + + HStack { + Button { + presentationMode.wrappedValue.dismiss() + } label: { + Text("Cancel") + } + + Button { + let existingIMs = Set(importTableVM.ims) + let failures = convertTxt() + importTableVM.load() + let newIMs = importTableVM.ims.filter({ im in !existingIMs.contains(im) }) + restartAndReconnect() + if Fcitx.imGroupCount() == 1 { + for im in newIMs { + Fcitx.imAddToCurrentGroup(im) + } + } + presentationMode.wrappedValue.dismiss() + if !failures.isEmpty { + let msg = String( + format: NSLocalizedString("Failed to convert txt table(s): %@", comment: ""), + failures.joined(separator: ", ")) + importTableVM.onError(msg) + } + importTableVM.finalize() + } label: { + Text("Reload") + }.buttonStyle(.borderedProminent) + } + }.padding() + } +} diff --git a/src/config/inputmethod.swift b/src/config/inputmethod.swift index 4eb805a..288304d 100644 --- a/src/config/inputmethod.swift +++ b/src/config/inputmethod.swift @@ -1,3 +1,4 @@ +import AlertToast import Fcitx import Logging import SwiftUI @@ -69,6 +70,10 @@ struct InputMethodConfigView: View { @State fileprivate var addToGroup: Group? @State var mouseHoverIMID: UUID? + @State private var showImportTable = false + @State private var importTableErrorMsg = "" + @State private var showImportTableError = false + var body: some View { NavigationSplitView { List(selection: $viewModel.selectedItem) { @@ -189,15 +194,38 @@ struct InputMethodConfigView: View { } label: { Text("Cancel") } + + Spacer() + + Button { + showImportTable = true + } label: { + Text("Import customized table") + } Button { add() addingInputMethod = false } label: { Text("Add") }.buttonStyle(.borderedProminent) - .disabled(inputMethodsToAdd.count == 0) + .disabled(inputMethodsToAdd.isEmpty) }.padding() }.padding([.top]) + .sheet(isPresented: $showImportTable) { + ImportTableView().load( + onError: { msg in + importTableErrorMsg = msg + showImportTableError = true + }, + finalize: { + refresh() + }) + } + .toast(isPresenting: $showImportTableError) { + AlertToast( + displayMode: .hud, + type: .error(Color.red), title: importTableErrorMsg) + } } } diff --git a/src/config/util.swift b/src/config/util.swift index 2afb61d..368bc24 100644 --- a/src/config/util.swift +++ b/src/config/util.swift @@ -182,7 +182,12 @@ func exec(_ command: String, _ args: [String]) -> Bool { process.launchPath = command process.arguments = args - process.launch() - process.waitUntilExit() - return process.terminationStatus == 0 + do { + try process.run() + process.waitUntilExit() + return process.terminationStatus == 0 + } catch { + FCITX_ERROR("Fatal error executing \(command) \(args)") + return false + } }