PrefUI // Use AppStorage to handle UserDefaults, plus comment fix.

This commit is contained in:
ShikiSuen 2023-03-05 22:02:25 +08:00
parent b715325db3
commit 8541c3b9e6
14 changed files with 420 additions and 441 deletions

View File

@ -10,36 +10,50 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneBehavior: View { struct VwrPrefPaneBehavior: View {
@State private var selChooseCandidateUsingSpace = UserDefaults.standard.bool( // MARK: - AppStorage Variables
forKey: UserDef.kChooseCandidateUsingSpace.rawValue)
@State private var selKeyBehaviorShiftTab = @Backport.AppStorage(wrappedValue: true, UserDef.kChooseCandidateUsingSpace.rawValue)
UserDefaults.standard.bool(forKey: UserDef.kSpecifyShiftTabKeyBehavior.rawValue) ? 1 : 0 private var chooseCandidateUsingSpace: Bool
@State private var selKeyBehaviorShiftSpace =
UserDefaults.standard.bool( @Backport.AppStorage(wrappedValue: true, UserDef.kEscToCleanInputBuffer.rawValue)
forKey: UserDef.kSpecifyShiftSpaceKeyBehavior.rawValue) ? 1 : 0 private var escToCleanInputBuffer: Bool
@State private var selKeyBehaviorESCForClearingTheBuffer = UserDefaults.standard.bool(
forKey: UserDef.kEscToCleanInputBuffer.rawValue) @Backport.AppStorage(wrappedValue: 0, UserDef.kSpecifyIntonationKeyBehavior.rawValue)
@State private var selAlsoConfirmAssociatedCandidatesByEnter = UserDefaults.standard.bool( private var specifyIntonationKeyBehavior: Int
forKey: UserDef.kAlsoConfirmAssociatedCandidatesByEnter.rawValue)
@State private var selTogglingAlphanumericalModeWithLShift = UserDefaults.standard.bool( @Backport.AppStorage(wrappedValue: 0, UserDef.kSpecifyShiftBackSpaceKeyBehavior.rawValue)
forKey: UserDef.kTogglingAlphanumericalModeWithLShift.rawValue) private var specifyShiftBackSpaceKeyBehavior: Int
@State private var selTogglingAlphanumericalModeWithRShift = UserDefaults.standard.bool(
forKey: UserDef.kTogglingAlphanumericalModeWithRShift.rawValue) @Backport.AppStorage(wrappedValue: false, UserDef.kSpecifyShiftTabKeyBehavior.rawValue)
@State private var selUpperCaseLetterKeyBehavior = UserDefaults.standard.integer( private var specifyShiftTabKeyBehavior: Bool
forKey: UserDef.kUpperCaseLetterKeyBehavior.rawValue)
@State private var selSpecifyIntonationKeyBehavior = UserDefaults.standard.integer( @Backport.AppStorage(wrappedValue: false, UserDef.kSpecifyShiftSpaceKeyBehavior.rawValue)
forKey: UserDef.kSpecifyIntonationKeyBehavior.rawValue) private var specifyShiftSpaceKeyBehavior: Bool
@State private var selSpecifyShiftBackSpaceKeyBehavior = UserDefaults.standard.integer(
forKey: UserDef.kSpecifyShiftBackSpaceKeyBehavior.rawValue) @Backport.AppStorage(wrappedValue: true, UserDef.kAlsoConfirmAssociatedCandidatesByEnter.rawValue)
@State private var selAlwaysShowTooltipTextsHorizontally = UserDefaults.standard.bool( private var alsoConfirmAssociatedCandidatesByEnter: Bool
forKey: UserDef.kAlwaysShowTooltipTextsHorizontally.rawValue)
@State private var selShowNotificationsWhenTogglingCapsLock = UserDefaults.standard.bool( @Backport.AppStorage(wrappedValue: true, UserDef.kTogglingAlphanumericalModeWithLShift.rawValue)
forKey: UserDef.kShowNotificationsWhenTogglingCapsLock.rawValue) private var togglingAlphanumericalModeWithLShift: Bool
@State private var selShareAlphanumericalModeStatusAcrossClients = UserDefaults.standard.bool(
forKey: UserDef.kShareAlphanumericalModeStatusAcrossClients.rawValue) @Backport.AppStorage(wrappedValue: true, UserDef.kTogglingAlphanumericalModeWithRShift.rawValue)
private var togglingAlphanumericalModeWithRShift: Bool
@Backport.AppStorage(wrappedValue: 0, UserDef.kUpperCaseLetterKeyBehavior.rawValue)
private var upperCaseLetterKeyBehavior: Int
@Backport.AppStorage(wrappedValue: false, UserDef.kAlwaysShowTooltipTextsHorizontally.rawValue)
private var alwaysShowTooltipTextsHorizontally: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kShowNotificationsWhenTogglingCapsLock.rawValue)
private var showNotificationsWhenTogglingCapsLock: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kShareAlphanumericalModeStatusAcrossClients.rawValue)
private var shareAlphanumericalModeStatusAcrossClients: Bool
var macOSMontereyOrLaterDetected: Bool { var macOSMontereyOrLaterDetected: Bool {
if #available(macOS 12, *) { if #available(macOS 12, *) {
@ -48,15 +62,15 @@ struct VwrPrefPaneBehavior: View {
return false return false
} }
// MARK: - Main View
var body: some View { var body: some View {
ScrollView { ScrollView {
SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) { SSPreferences.Container(contentWidth: CtlPrefUIShared.contentWidth) {
SSPreferences.Section(title: "Space:".localized, bottomDivider: true) { SSPreferences.Section(title: "Space:".localized, bottomDivider: true) {
Toggle( Toggle(
LocalizedStringKey("Enable Space key for calling candidate window"), LocalizedStringKey("Enable Space key for calling candidate window"),
isOn: $selChooseCandidateUsingSpace.onChange { isOn: $chooseCandidateUsingSpace
PrefMgr.shared.chooseCandidateUsingSpace = selChooseCandidateUsingSpace
}
) )
Text( Text(
LocalizedStringKey( LocalizedStringKey(
@ -68,9 +82,7 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "ESC:".localized, bottomDivider: true) { SSPreferences.Section(title: "ESC:".localized, bottomDivider: true) {
Toggle( Toggle(
LocalizedStringKey("Use ESC key to clear the entire input buffer"), LocalizedStringKey("Use ESC key to clear the entire input buffer"),
isOn: $selKeyBehaviorESCForClearingTheBuffer.onChange { isOn: $escToCleanInputBuffer
PrefMgr.shared.escToCleanInputBuffer = selKeyBehaviorESCForClearingTheBuffer
}
) )
Text( Text(
LocalizedStringKey( LocalizedStringKey(
@ -82,9 +94,7 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "Enter:".localized, bottomDivider: true) { SSPreferences.Section(title: "Enter:".localized, bottomDivider: true) {
Toggle( Toggle(
LocalizedStringKey("Allow using Enter key to confirm associated candidate selection"), LocalizedStringKey("Allow using Enter key to confirm associated candidate selection"),
isOn: $selAlsoConfirmAssociatedCandidatesByEnter.onChange { isOn: $alsoConfirmAssociatedCandidatesByEnter
PrefMgr.shared.alsoConfirmAssociatedCandidatesByEnter = selAlsoConfirmAssociatedCandidatesByEnter
}
) )
Text( Text(
LocalizedStringKey( LocalizedStringKey(
@ -96,9 +106,7 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "Shift+BackSpace:".localized, bottomDivider: true) { SSPreferences.Section(title: "Shift+BackSpace:".localized, bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selSpecifyShiftBackSpaceKeyBehavior.onChange { selection: $specifyShiftBackSpaceKeyBehavior
PrefMgr.shared.specifyShiftBackSpaceKeyBehavior = selSpecifyShiftBackSpaceKeyBehavior
}
) { ) {
Text(LocalizedStringKey("Disassemble the previous reading, dropping its intonation")).tag(0) Text(LocalizedStringKey("Disassemble the previous reading, dropping its intonation")).tag(0)
Text(LocalizedStringKey("Clear the entire inline composition buffer like Shift+Delete")).tag(1) Text(LocalizedStringKey("Clear the entire inline composition buffer like Shift+Delete")).tag(1)
@ -112,12 +120,10 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "(Shift+)Tab:", bottomDivider: true) { SSPreferences.Section(title: "(Shift+)Tab:", bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selKeyBehaviorShiftTab.onChange { selection: $specifyShiftTabKeyBehavior
PrefMgr.shared.specifyShiftTabKeyBehavior = (selKeyBehaviorShiftTab == 1) ? true : false
}
) { ) {
Text(LocalizedStringKey("for revolving candidates")).tag(0) Text(LocalizedStringKey("for revolving candidates")).tag(false)
Text(LocalizedStringKey("for revolving pages")).tag(1) Text(LocalizedStringKey("for revolving pages")).tag(true)
} }
.labelsHidden() .labelsHidden()
.horizontalRadioGroupLayout() .horizontalRadioGroupLayout()
@ -128,12 +134,10 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "(Shift+)Space:".localized, bottomDivider: true) { SSPreferences.Section(title: "(Shift+)Space:".localized, bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selKeyBehaviorShiftSpace.onChange { selection: $specifyShiftSpaceKeyBehavior
PrefMgr.shared.specifyShiftSpaceKeyBehavior = (selKeyBehaviorShiftSpace == 1) ? true : false
}
) { ) {
Text(LocalizedStringKey("Space to +revolve candidates, Shift+Space to +revolve pages")).tag(0) Text(LocalizedStringKey("Space to +revolve candidates, Shift+Space to +revolve pages")).tag(false)
Text(LocalizedStringKey("Space to +revolve pages, Shift+Space to +revolve candidates")).tag(1) Text(LocalizedStringKey("Space to +revolve pages, Shift+Space to +revolve candidates")).tag(true)
} }
.labelsHidden() .labelsHidden()
.pickerStyle(RadioGroupPickerStyle()) .pickerStyle(RadioGroupPickerStyle())
@ -143,9 +147,7 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "Shift+Letter:".localized, bottomDivider: true) { SSPreferences.Section(title: "Shift+Letter:".localized, bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selUpperCaseLetterKeyBehavior.onChange { selection: $upperCaseLetterKeyBehavior
PrefMgr.shared.upperCaseLetterKeyBehavior = selUpperCaseLetterKeyBehavior
}
) { ) {
Text(LocalizedStringKey("Type them into inline composition buffer")).tag(0) Text(LocalizedStringKey("Type them into inline composition buffer")).tag(0)
Text(LocalizedStringKey("Directly commit lowercased letters")).tag(1) Text(LocalizedStringKey("Directly commit lowercased letters")).tag(1)
@ -159,9 +161,7 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "Intonation Key:".localized, bottomDivider: true) { SSPreferences.Section(title: "Intonation Key:".localized, bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selSpecifyIntonationKeyBehavior.onChange { selection: $specifyIntonationKeyBehavior
PrefMgr.shared.specifyIntonationKeyBehavior = selSpecifyIntonationKeyBehavior
}
) { ) {
Text(LocalizedStringKey("Override the previous reading's intonation with candidate-reset")).tag(0) Text(LocalizedStringKey("Override the previous reading's intonation with candidate-reset")).tag(0)
Text(LocalizedStringKey("Only override the intonation of the previous reading if different")).tag(1) Text(LocalizedStringKey("Only override the intonation of the previous reading if different")).tag(1)
@ -175,23 +175,21 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "Shift:", bottomDivider: true) { SSPreferences.Section(title: "Shift:", bottomDivider: true) {
Toggle( Toggle(
LocalizedStringKey("Toggle alphanumerical mode with Left-Shift"), LocalizedStringKey("Toggle alphanumerical mode with Left-Shift"),
isOn: $selTogglingAlphanumericalModeWithLShift.onChange { isOn: $togglingAlphanumericalModeWithLShift.onChange {
PrefMgr.shared.togglingAlphanumericalModeWithLShift = selTogglingAlphanumericalModeWithLShift SessionCtl.theShiftKeyDetector.toggleWithLShift = togglingAlphanumericalModeWithLShift
} }
) )
Toggle( Toggle(
LocalizedStringKey("Toggle alphanumerical mode with Right-Shift"), LocalizedStringKey("Toggle alphanumerical mode with Right-Shift"),
isOn: $selTogglingAlphanumericalModeWithRShift.onChange { isOn: $togglingAlphanumericalModeWithRShift.onChange {
PrefMgr.shared.togglingAlphanumericalModeWithRShift = selTogglingAlphanumericalModeWithRShift SessionCtl.theShiftKeyDetector.toggleWithRShift = togglingAlphanumericalModeWithRShift
} }
) )
Toggle( Toggle(
LocalizedStringKey("Share alphanumerical mode status across all clients"), LocalizedStringKey("Share alphanumerical mode status across all clients"),
isOn: $selShareAlphanumericalModeStatusAcrossClients.onChange { isOn: $shareAlphanumericalModeStatusAcrossClients
PrefMgr.shared.shareAlphanumericalModeStatusAcrossClients = selShareAlphanumericalModeStatusAcrossClients
}
).disabled( ).disabled(
!PrefMgr.shared.togglingAlphanumericalModeWithRShift && !PrefMgr.shared.togglingAlphanumericalModeWithLShift !togglingAlphanumericalModeWithRShift && !togglingAlphanumericalModeWithLShift
) )
Text( Text(
"This feature requires macOS 10.15 and above.".localized + CtlPrefUIShared.sentenceSeparator "This feature requires macOS 10.15 and above.".localized + CtlPrefUIShared.sentenceSeparator
@ -201,20 +199,20 @@ struct VwrPrefPaneBehavior: View {
SSPreferences.Section(title: "Caps Lock:", bottomDivider: true) { SSPreferences.Section(title: "Caps Lock:", bottomDivider: true) {
Toggle( Toggle(
LocalizedStringKey("Show notifications when toggling Caps Lock"), LocalizedStringKey("Show notifications when toggling Caps Lock"),
isOn: $selShowNotificationsWhenTogglingCapsLock.onChange { isOn: $showNotificationsWhenTogglingCapsLock.onChange {
PrefMgr.shared.showNotificationsWhenTogglingCapsLock = selShowNotificationsWhenTogglingCapsLock if !macOSMontereyOrLaterDetected, showNotificationsWhenTogglingCapsLock {
showNotificationsWhenTogglingCapsLock.toggle()
}
} }
).disabled(!macOSMontereyOrLaterDetected) ).disabled(!macOSMontereyOrLaterDetected)
Text( Text(
"This feature requires macOS 10.15 and above.".localized "This feature requires macOS 12 and above.".localized
).preferenceDescription() ).preferenceDescription()
} }
SSPreferences.Section(title: "Misc Settings:".localized) { SSPreferences.Section(title: "Misc Settings:".localized) {
Toggle( Toggle(
LocalizedStringKey("Always show tooltip texts horizontally"), LocalizedStringKey("Always show tooltip texts horizontally"),
isOn: $selAlwaysShowTooltipTextsHorizontally.onChange { isOn: $alwaysShowTooltipTextsHorizontally
PrefMgr.shared.alwaysShowTooltipTextsHorizontally = selAlwaysShowTooltipTextsHorizontally
}
).disabled(Bundle.main.preferredLocalizations[0] == "en") ).disabled(Bundle.main.preferredLocalizations[0] == "en")
Text( Text(
LocalizedStringKey( LocalizedStringKey(

View File

@ -10,39 +10,46 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneCandidates: View { struct VwrPrefPaneCandidates: View {
@State private var selCandidateUIFontSize = UserDefaults.standard.integer( // MARK: - AppStorage Variables
forKey: UserDef.kCandidateListTextSize.rawValue)
@State private var selEnableHorizontalCandidateLayout = UserDefaults.standard.bool(
forKey: UserDef.kUseHorizontalCandidateList.rawValue)
@State private var selCandidateWindowShowOnlyOneLine = UserDefaults.standard.bool(
forKey: UserDef.kCandidateWindowShowOnlyOneLine.rawValue)
@State private var selShowReverseLookupInCandidateUI = UserDefaults.standard.bool(
forKey: UserDef.kShowReverseLookupInCandidateUI.rawValue)
@State private var selCursorPosition =
UserDefaults.standard.bool(
forKey: UserDef.kUseRearCursorMode.rawValue) ? 1 : 0
@State private var selPushCursorAfterSelection = UserDefaults.standard.bool(
forKey: UserDef.kMoveCursorAfterSelectingCandidate.rawValue)
@State private var selUseFixecCandidateOrderOnSelection: Bool = UserDefaults.standard.bool(
forKey: UserDef.kUseFixecCandidateOrderOnSelection.rawValue)
@State private var selConsolidateContextOnCandidateSelection: Bool = UserDefaults.standard.bool(
forKey: UserDef.kConsolidateContextOnCandidateSelection.rawValue)
@State private var selUseIMKCandidateWindow: Bool = UserDefaults.standard.bool(
forKey: UserDef.kUseIMKCandidateWindow.rawValue)
@State private var selEnableMouseScrollingForTDKCandidatesCocoa: Bool = UserDefaults.standard.bool(
forKey: UserDef.kEnableMouseScrollingForTDKCandidatesCocoa.rawValue)
@State private var selEnableSwiftUIForTDKCandidates: Bool = UserDefaults.standard.bool(
forKey: UserDef.kEnableSwiftUIForTDKCandidates.rawValue)
var isMontereyOrAbove: Bool = { @Backport.AppStorage(wrappedValue: 16, UserDef.kCandidateListTextSize.rawValue)
if #available(macOS 12.0, *) { private var candidateListTextSize: Double
return true
} @Backport.AppStorage(wrappedValue: true, UserDef.kUseHorizontalCandidateList.rawValue)
return false private var useHorizontalCandidateList: Bool
}()
@Backport.AppStorage(wrappedValue: false, UserDef.kCandidateWindowShowOnlyOneLine.rawValue)
private var candidateWindowShowOnlyOneLine: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kShowReverseLookupInCandidateUI.rawValue)
private var showReverseLookupInCandidateUI: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kUseRearCursorMode.rawValue)
private var useRearCursorMode: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kMoveCursorAfterSelectingCandidate.rawValue)
private var moveCursorAfterSelectingCandidate: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kUseFixecCandidateOrderOnSelection.rawValue)
private var useFixecCandidateOrderOnSelection: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kConsolidateContextOnCandidateSelection.rawValue)
private var consolidateContextOnCandidateSelection: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kUseIMKCandidateWindow.rawValue)
private var useIMKCandidateWindow: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kEnableSwiftUIForTDKCandidates.rawValue)
private var enableSwiftUIForTDKCandidates: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kEnableMouseScrollingForTDKCandidatesCocoa.rawValue)
private var enableMouseScrollingForTDKCandidatesCocoa: Bool
// MARK: - Main View
var body: some View { var body: some View {
ScrollView { ScrollView {
@ -53,9 +60,7 @@ struct VwrPrefPaneCandidates: View {
SSPreferences.Section(title: "Candidate Layout:".localized, bottomDivider: true) { SSPreferences.Section(title: "Candidate Layout:".localized, bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selEnableHorizontalCandidateLayout.onChange { selection: $useHorizontalCandidateList
PrefMgr.shared.useHorizontalCandidateList = selEnableHorizontalCandidateLayout
}
) { ) {
Text(LocalizedStringKey("Vertical")).tag(false) Text(LocalizedStringKey("Vertical")).tag(false)
Text(LocalizedStringKey("Horizontal")).tag(true) Text(LocalizedStringKey("Horizontal")).tag(true)
@ -67,13 +72,10 @@ struct VwrPrefPaneCandidates: View {
.preferenceDescription() .preferenceDescription()
Toggle( Toggle(
LocalizedStringKey("Use only one row / column in candidate window."), LocalizedStringKey("Use only one row / column in candidate window."),
isOn: $selCandidateWindowShowOnlyOneLine.onChange { isOn: $candidateWindowShowOnlyOneLine
PrefMgr.shared.candidateWindowShowOnlyOneLine =
selCandidateWindowShowOnlyOneLine
}
) )
.controlSize(.small) .controlSize(.small)
.disabled(PrefMgr.shared.useIMKCandidateWindow) .disabled(useIMKCandidateWindow)
Text( Text(
"This only works with Tadokoro candidate window.".localized "This only works with Tadokoro candidate window.".localized
+ CtlPrefUIShared.sentenceSeparator + CtlPrefUIShared.sentenceSeparator
@ -84,24 +86,25 @@ struct VwrPrefPaneCandidates: View {
SSPreferences.Section(title: "Candidate Size:".localized, bottomDivider: true) { SSPreferences.Section(title: "Candidate Size:".localized, bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selCandidateUIFontSize.onChange { selection: $candidateListTextSize.onChange {
PrefMgr.shared.candidateListTextSize = Double(selCandidateUIFontSize) guard !(12 ... 196).contains(candidateListTextSize) else { return }
candidateListTextSize = max(12, min(candidateListTextSize, 196))
} }
) { ) {
Group { Group {
Text("12").tag(12) Text("12").tag(12.0)
Text("14").tag(14) Text("14").tag(14.0)
Text("16").tag(16) Text("16").tag(16.0)
Text("17").tag(17) Text("17").tag(17.0)
Text("18").tag(18) Text("18").tag(18.0)
Text("20").tag(20) Text("20").tag(20.0)
Text("22").tag(22) Text("22").tag(22.0)
Text("24").tag(24) Text("24").tag(24.0)
} }
Group { Group {
Text("32").tag(32) Text("32").tag(32.0)
Text("64").tag(64) Text("64").tag(64.0)
Text("96").tag(96) Text("96").tag(96.0)
} }
} }
.labelsHidden() .labelsHidden()
@ -112,12 +115,10 @@ struct VwrPrefPaneCandidates: View {
SSPreferences.Section(title: "Cursor Selection:".localized, bottomDivider: true) { SSPreferences.Section(title: "Cursor Selection:".localized, bottomDivider: true) {
Picker( Picker(
"", "",
selection: $selCursorPosition.onChange { selection: $useRearCursorMode
PrefMgr.shared.useRearCursorMode = (selCursorPosition == 1) ? true : false
}
) { ) {
Text(LocalizedStringKey("in front of the phrase (like macOS built-in Zhuyin IME)")).tag(0) Text(LocalizedStringKey("in front of the phrase (like macOS built-in Zhuyin IME)")).tag(false)
Text(LocalizedStringKey("at the rear of the phrase (like Microsoft New Phonetic)")).tag(1) Text(LocalizedStringKey("at the rear of the phrase (like Microsoft New Phonetic)")).tag(true)
} }
.labelsHidden() .labelsHidden()
.pickerStyle(RadioGroupPickerStyle()) .pickerStyle(RadioGroupPickerStyle())
@ -125,19 +126,15 @@ struct VwrPrefPaneCandidates: View {
.preferenceDescription() .preferenceDescription()
Toggle( Toggle(
LocalizedStringKey("Push the cursor in front of the phrase after selection"), LocalizedStringKey("Push the cursor in front of the phrase after selection"),
isOn: $selPushCursorAfterSelection.onChange { isOn: $moveCursorAfterSelectingCandidate
PrefMgr.shared.moveCursorAfterSelectingCandidate = selPushCursorAfterSelection
}
).controlSize(.small) ).controlSize(.small)
} }
SSPreferences.Section(title: "Misc Settings:".localized, bottomDivider: true) { SSPreferences.Section(title: "Misc Settings:".localized, bottomDivider: true) {
Toggle( Toggle(
LocalizedStringKey("Show available reverse-lookup results in candidate window"), LocalizedStringKey("Show available reverse-lookup results in candidate window"),
isOn: $selShowReverseLookupInCandidateUI.onChange { isOn: $showReverseLookupInCandidateUI
PrefMgr.shared.showReverseLookupInCandidateUI = selShowReverseLookupInCandidateUI
}
) )
.disabled(PrefMgr.shared.useIMKCandidateWindow) .disabled(useIMKCandidateWindow)
Text( Text(
"This only works with Tadokoro candidate window.".localized "This only works with Tadokoro candidate window.".localized
+ CtlPrefUIShared.sentenceSeparator + CtlPrefUIShared.sentenceSeparator
@ -146,9 +143,7 @@ struct VwrPrefPaneCandidates: View {
.preferenceDescription() .preferenceDescription()
Toggle( Toggle(
LocalizedStringKey("Always use fixed listing order in candidate window"), LocalizedStringKey("Always use fixed listing order in candidate window"),
isOn: $selUseFixecCandidateOrderOnSelection.onChange { isOn: $useFixecCandidateOrderOnSelection
PrefMgr.shared.useFixecCandidateOrderOnSelection = selUseFixecCandidateOrderOnSelection
}
) )
Text( Text(
LocalizedStringKey( LocalizedStringKey(
@ -158,9 +153,7 @@ struct VwrPrefPaneCandidates: View {
.preferenceDescription() .preferenceDescription()
Toggle( Toggle(
LocalizedStringKey("Consolidate the context on confirming candidate selection"), LocalizedStringKey("Consolidate the context on confirming candidate selection"),
isOn: $selConsolidateContextOnCandidateSelection.onChange { isOn: $consolidateContextOnCandidateSelection
PrefMgr.shared.consolidateContextOnCandidateSelection = selConsolidateContextOnCandidateSelection
}
) )
Text( Text(
"For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is.".localized "For example: When typing “章太炎” and you want to override the “太” with “泰”, and the raw operation index range [1,2) which bounds are cutting the current node “章太炎” in range [0,3). If having lack of the pre-consolidation process, this word will become something like “張泰言” after the candidate selection. Only if we enable this consolidation, this word will become “章泰炎” which is the expected result that the context is kept as-is.".localized
@ -170,8 +163,7 @@ struct VwrPrefPaneCandidates: View {
SSPreferences.Section(title: "Experimental:".localized) { SSPreferences.Section(title: "Experimental:".localized) {
Toggle( Toggle(
LocalizedStringKey("Use IMK Candidate Window instead of Tadokoro"), LocalizedStringKey("Use IMK Candidate Window instead of Tadokoro"),
isOn: $selUseIMKCandidateWindow.onChange { isOn: $useIMKCandidateWindow.onChange {
PrefMgr.shared.useIMKCandidateWindow = selUseIMKCandidateWindow
NSLog("vChewing App self-terminated due to enabling / disabling IMK candidate window.") NSLog("vChewing App self-terminated due to enabling / disabling IMK candidate window.")
NSApp.terminate(nil) NSApp.terminate(nil)
} }
@ -186,22 +178,16 @@ struct VwrPrefPaneCandidates: View {
.preferenceDescription() .preferenceDescription()
Toggle( Toggle(
LocalizedStringKey("Enable mouse wheel support for Tadokoro Candidate Window"), LocalizedStringKey("Enable mouse wheel support for Tadokoro Candidate Window"),
isOn: $selEnableMouseScrollingForTDKCandidatesCocoa.onChange { isOn: $enableMouseScrollingForTDKCandidatesCocoa
PrefMgr.shared.enableMouseScrollingForTDKCandidatesCocoa =
selEnableMouseScrollingForTDKCandidatesCocoa
}
) )
.disabled( .disabled(
PrefMgr.shared.useIMKCandidateWindow || PrefMgr.shared.enableSwiftUIForTDKCandidates useIMKCandidateWindow || enableSwiftUIForTDKCandidates
) )
Toggle( Toggle(
LocalizedStringKey("Enable experimental Swift UI typesetting method"), LocalizedStringKey("Enable experimental Swift UI typesetting method"),
isOn: $selEnableSwiftUIForTDKCandidates.onChange { isOn: $enableSwiftUIForTDKCandidates
PrefMgr.shared.enableSwiftUIForTDKCandidates =
selEnableSwiftUIForTDKCandidates
}
) )
.disabled(PrefMgr.shared.useIMKCandidateWindow) .disabled(useIMKCandidateWindow)
Text( Text(
"By checking this, Tadokoro Candidate Window will use SwiftUI. SwiftUI was being used in vChewing 3.3.8 and before. However, SwiftUI has unacceptable responsiveness & latency & efficiency problems in rendering the candidate panel UI. That's why a refactored version has been introduced since vChewing 3.3.9 using Cocoa, providing an optimized user experience with blasing-fast operation responsiveness, plus experimental mouse-wheel support.".localized "By checking this, Tadokoro Candidate Window will use SwiftUI. SwiftUI was being used in vChewing 3.3.8 and before. However, SwiftUI has unacceptable responsiveness & latency & efficiency problems in rendering the candidate panel UI. That's why a refactored version has been introduced since vChewing 3.3.9 using Cocoa, providing an optimized user experience with blasing-fast operation responsiveness, plus experimental mouse-wheel support.".localized
) )
@ -224,40 +210,35 @@ struct VwrPrefPaneCandidates_Previews: PreviewProvider {
@available(macOS 10.15, *) @available(macOS 10.15, *)
private struct VwrPrefPaneCandidates_SelectionKeys: View { private struct VwrPrefPaneCandidates_SelectionKeys: View {
@State private var selSelectionKeysList = CandidateKey.suggestions // MARK: - AppStorage Variables
@State private var selSelectionKeys =
UserDefaults.standard.string(forKey: UserDef.kCandidateKeys.rawValue) ?? CandidateKey.defaultKeys @Backport.AppStorage(wrappedValue: PrefMgr.kDefaultCandidateKeys, UserDef.kCandidateKeys.rawValue)
private var candidateKeys: String
@Backport.AppStorage(wrappedValue: false, UserDef.kUseIMKCandidateWindow.rawValue)
private var useIMKCandidateWindow: Bool
// MARK: - Main View
var body: some View { var body: some View {
ComboBox( ComboBox(
items: CandidateKey.suggestions, items: CandidateKey.suggestions,
text: $selSelectionKeys.onChange { text: $candidateKeys.onChange {
let value = selSelectionKeys let value = candidateKeys
let keys: String = value.trimmingCharacters(in: .whitespacesAndNewlines).deduplicated let keys: String = value.trimmingCharacters(in: .whitespacesAndNewlines).deduplicated
if keys.isEmpty {
selSelectionKeys = PrefMgr.shared.candidateKeys
return
}
// Start Error Handling. // Start Error Handling.
if let errorResult = CandidateKey.validate(keys: keys) { if let errorResult = CandidateKey.validate(keys: keys) {
if let window = CtlPrefUIShared.sharedWindow, !keys.isEmpty {
IMEApp.buzz() IMEApp.buzz()
if let window = CtlPrefUIShared.sharedWindow {
let alert = NSAlert(error: NSLocalizedString("Invalid Selection Keys.", comment: "")) let alert = NSAlert(error: NSLocalizedString("Invalid Selection Keys.", comment: ""))
alert.informativeText = errorResult alert.informativeText = errorResult
alert.beginSheetModal(for: window) { _ in alert.beginSheetModal(for: window)
selSelectionKeys = PrefMgr.shared.candidateKeys
} }
} else { candidateKeys = PrefMgr.kDefaultCandidateKeys
selSelectionKeys = PrefMgr.shared.candidateKeys
}
} else {
PrefMgr.shared.candidateKeys = keys
selSelectionKeys = PrefMgr.shared.candidateKeys
return
} }
} }
).frame(width: 180).disabled(PrefMgr.shared.useIMKCandidateWindow) ).frame(width: 180).disabled(useIMKCandidateWindow)
if PrefMgr.shared.useIMKCandidateWindow { if useIMKCandidateWindow {
Text( Text(
LocalizedStringKey( LocalizedStringKey(
"⚠︎ This feature in IMK Candidate Window defects. Please consult\nApple Developer Relations with Radar ID: #FB11300759." "⚠︎ This feature in IMK Candidate Window defects. Please consult\nApple Developer Relations with Radar ID: #FB11300759."

View File

@ -11,21 +11,30 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneCassette: View { struct VwrPrefPaneCassette: View {
// MARK: - AppStorage Variables
@Backport.AppStorage(wrappedValue: "", UserDef.kCassettePath.rawValue)
private var cassettePath: String
@Backport.AppStorage(wrappedValue: false, UserDef.kCassetteEnabled.rawValue)
private var cassetteEnabled: Bool
@Backport.AppStorage(wrappedValue: 0, UserDef.kForceCassetteChineseConversion.rawValue)
private var forceCassetteChineseConversion: Int
@Backport.AppStorage(wrappedValue: true, UserDef.kShowTranslatedStrokesInCompositionBuffer.rawValue)
private var showTranslatedStrokesInCompositionBuffer: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kAutoCompositeWithLongestPossibleCassetteKey.rawValue)
private var autoCompositeWithLongestPossibleCassetteKey: Bool
// MARK: - Main View
private var fdrCassetteDataDefault: String { "" } private var fdrCassetteDataDefault: String { "" }
@State private var tbxCassettePath: String =
UserDefaults.standard.string(forKey: UserDef.kCassettePath.rawValue)
?? ""
@State private var selCassetteEnabled: Bool = UserDefaults.standard.bool(
forKey: UserDef.kCassetteEnabled.rawValue)
@State private var selForceCassetteChineseConversion: Int = UserDefaults.standard.integer(
forKey: UserDef.kForceCassetteChineseConversion.rawValue)
@State private var selShowTranslatedStrokesInCompositionBuffer: Bool = UserDefaults.standard.bool(
forKey: UserDef.kShowTranslatedStrokesInCompositionBuffer.rawValue)
@State private var selAutoCompositeWithLongestPossibleCassetteKey = UserDefaults.standard.bool(
forKey: UserDef.kAutoCompositeWithLongestPossibleCassetteKey.rawValue)
private static let dlgOpenFile = NSOpenPanel() private static let dlgOpenFile = NSOpenPanel()
@ -37,8 +46,8 @@ struct VwrPrefPaneCassette: View {
SSPreferences.Section(bottomDivider: true) { SSPreferences.Section(bottomDivider: true) {
Text(LocalizedStringKey("Choose your desired cassette file path. Will be omitted if invalid.")) Text(LocalizedStringKey("Choose your desired cassette file path. Will be omitted if invalid."))
HStack { HStack {
TextField(fdrCassetteDataDefault, text: $tbxCassettePath).disabled(true) TextField(fdrCassetteDataDefault, text: $cassettePath).disabled(true)
.help(tbxCassettePath) .help(cassettePath)
Button { Button {
Self.dlgOpenFile.title = NSLocalizedString( Self.dlgOpenFile.title = NSLocalizedString(
"Choose your desired cassette file path.", comment: "" "Choose your desired cassette file path.", comment: ""
@ -52,16 +61,15 @@ struct VwrPrefPaneCassette: View {
Self.dlgOpenFile.allowsOtherFileTypes = true Self.dlgOpenFile.allowsOtherFileTypes = true
let bolPreviousPathValidity = LMMgr.checkCassettePathValidity( let bolPreviousPathValidity = LMMgr.checkCassettePathValidity(
PrefMgr.shared.cassettePath.expandingTildeInPath) cassettePath.expandingTildeInPath)
if let window = CtlPrefUIShared.sharedWindow { if let window = CtlPrefUIShared.sharedWindow {
Self.dlgOpenFile.beginSheetModal(for: window) { result in Self.dlgOpenFile.beginSheetModal(for: window) { result in
if result == NSApplication.ModalResponse.OK { if result == NSApplication.ModalResponse.OK {
guard let url = Self.dlgOpenFile.url else { return } guard let url = Self.dlgOpenFile.url else { return }
if LMMgr.checkCassettePathValidity(url.path) { if LMMgr.checkCassettePathValidity(url.path) {
PrefMgr.shared.cassettePath = url.path cassettePath = url.path
LMMgr.loadCassetteData() LMMgr.loadCassetteData()
tbxCassettePath = PrefMgr.shared.cassettePath
BookmarkManager.shared.saveBookmark(for: url) BookmarkManager.shared.saveBookmark(for: url)
} else { } else {
IMEApp.buzz() IMEApp.buzz()
@ -83,15 +91,14 @@ struct VwrPrefPaneCassette: View {
} }
Button { Button {
LMMgr.resetCassettePath() LMMgr.resetCassettePath()
tbxCassettePath = ""
} label: { } label: {
Text("×") Text("×")
} }
} }
Toggle( Toggle(
LocalizedStringKey("Enable cassette mode, suppressing phonabet input"), LocalizedStringKey("Enable cassette mode, suppressing phonabet input"),
isOn: $selCassetteEnabled.onChange { isOn: $cassetteEnabled.onChange {
if selCassetteEnabled, !LMMgr.checkCassettePathValidity(PrefMgr.shared.cassettePath) { if cassetteEnabled, !LMMgr.checkCassettePathValidity(cassettePath) {
if let window = CtlPrefUIShared.sharedWindow { if let window = CtlPrefUIShared.sharedWindow {
IMEApp.buzz() IMEApp.buzz()
let alert = NSAlert(error: NSLocalizedString("Path invalid or file access error.", comment: "")) let alert = NSAlert(error: NSLocalizedString("Path invalid or file access error.", comment: ""))
@ -99,15 +106,14 @@ struct VwrPrefPaneCassette: View {
"Please reconfigure the cassette path to a valid one before enabling this mode.", comment: "" "Please reconfigure the cassette path to a valid one before enabling this mode.", comment: ""
) )
alert.beginSheetModal(for: window) { _ in alert.beginSheetModal(for: window) { _ in
}
}
LMMgr.resetCassettePath() LMMgr.resetCassettePath()
PrefMgr.shared.cassetteEnabled = false cassetteEnabled = false
selCassetteEnabled = false
}
}
} else { } else {
PrefMgr.shared.cassetteEnabled = selCassetteEnabled
LMMgr.loadCassetteData() LMMgr.loadCassetteData()
} }
LMMgr.setCassetteEnabled(cassetteEnabled)
} }
).controlSize(.small) ).controlSize(.small)
Text( Text(
@ -123,16 +129,11 @@ struct VwrPrefPaneCassette: View {
SSPreferences.Section { SSPreferences.Section {
Toggle( Toggle(
LocalizedStringKey("Auto-composite when the longest possible key is formed"), LocalizedStringKey("Auto-composite when the longest possible key is formed"),
isOn: $selAutoCompositeWithLongestPossibleCassetteKey.onChange { isOn: $autoCompositeWithLongestPossibleCassetteKey
PrefMgr.shared.autoCompositeWithLongestPossibleCassetteKey =
selAutoCompositeWithLongestPossibleCassetteKey
}
) )
Toggle( Toggle(
LocalizedStringKey("Show translated strokes in composition buffer"), LocalizedStringKey("Show translated strokes in composition buffer"),
isOn: $selShowTranslatedStrokesInCompositionBuffer.onChange { isOn: $showTranslatedStrokesInCompositionBuffer
PrefMgr.shared.showTranslatedStrokesInCompositionBuffer = selShowTranslatedStrokesInCompositionBuffer
}
) )
Text( Text(
LocalizedStringKey( LocalizedStringKey(
@ -142,9 +143,7 @@ struct VwrPrefPaneCassette: View {
.preferenceDescription() .preferenceDescription()
Picker( Picker(
"", "",
selection: $selForceCassetteChineseConversion.onChange { selection: $forceCassetteChineseConversion
PrefMgr.shared.forceCassetteChineseConversion = selForceCassetteChineseConversion
}
) { ) {
Text(LocalizedStringKey("Disable forced conversion for cassette outputs")).tag(0) Text(LocalizedStringKey("Disable forced conversion for cassette outputs")).tag(0)
Text(LocalizedStringKey("Enforce conversion in both input modes")).tag(1) Text(LocalizedStringKey("Enforce conversion in both input modes")).tag(1)

View File

@ -10,20 +10,19 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneDevZone: View { struct VwrPrefPaneDevZone: View {
@State private var selDisableSegmentedThickUnderlineInMarkingModeForManagedClients // MARK: - AppStorage Variables
= UserDefaults.standard.bool(
forKey: UserDef.kDisableSegmentedThickUnderlineInMarkingModeForManagedClients.rawValue
)
var isMontereyOrAbove: Bool = { @Backport.AppStorage(
if #available(macOS 12.0, *) { wrappedValue: false,
return true UserDef.kDisableSegmentedThickUnderlineInMarkingModeForManagedClients.rawValue
} )
return false private var disableSegmentedThickUnderlineInMarkingModeForManagedClients: Bool
}()
// MARK: - Main View
var body: some View { var body: some View {
ScrollView { ScrollView {
@ -41,9 +40,7 @@ struct VwrPrefPaneDevZone: View {
} }
Toggle( Toggle(
"Disable segmented thick underline in marking mode for managed clients".localized, "Disable segmented thick underline in marking mode for managed clients".localized,
isOn: $selDisableSegmentedThickUnderlineInMarkingModeForManagedClients.onChange { isOn: $disableSegmentedThickUnderlineInMarkingModeForManagedClients
PrefMgr.shared.disableSegmentedThickUnderlineInMarkingModeForManagedClients = selDisableSegmentedThickUnderlineInMarkingModeForManagedClients
}
) )
Text( Text(
"Some clients with web-based front UI may have issues rendering segmented thick underlines drawn by their implemented “setMarkedText()”. This option stops the input method from delivering segmented thick underlines to “client().setMarkedText()”. Note that segmented thick underlines are only used in marking mode, unless the client itself misimplements the IMKTextInput method “setMarkedText()”. This option only affects the inline composition buffer.".localized "Some clients with web-based front UI may have issues rendering segmented thick underlines drawn by their implemented “setMarkedText()”. This option stops the input method from delivering segmented thick underlines to “client().setMarkedText()”. Note that segmented thick underlines are only used in marking mode, unless the client itself misimplements the IMKTextInput method “setMarkedText()”. This option only affects the inline composition buffer.".localized

View File

@ -11,29 +11,42 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneDictionary: View { struct VwrPrefPaneDictionary: View {
// MARK: - AppStorage Variables
@Backport.AppStorage(wrappedValue: "", UserDef.kUserDataFolderSpecified.rawValue)
private var userDataFolderSpecified: String
@Backport.AppStorage(wrappedValue: true, UserDef.kShouldAutoReloadUserDataFiles.rawValue)
private var shouldAutoReloadUserDataFiles: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kUseExternalFactoryDict.rawValue)
private var useExternalFactoryDict: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kOnlyLoadFactoryLangModelsIfNeeded.rawValue)
private var onlyLoadFactoryLangModelsIfNeeded: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kCNS11643Enabled.rawValue)
private var cns11643Enabled: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kSymbolInputEnabled.rawValue)
private var symbolInputEnabled: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kFetchSuggestionsFromUserOverrideModel.rawValue)
private var fetchSuggestionsFromUserOverrideModel: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kPhraseReplacementEnabled.rawValue)
private var phraseReplacementEnabled: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kAllowBoostingSingleKanjiAsUserPhrase.rawValue)
private var allowBoostingSingleKanjiAsUserPhrase: Bool
// MARK: - Main View
private var fdrUserDataDefault: String { LMMgr.dataFolderPath(isDefaultFolder: true) } private var fdrUserDataDefault: String { LMMgr.dataFolderPath(isDefaultFolder: true) }
@State private var tbxUserDataPathSpecified: String =
UserDefaults.standard.string(forKey: UserDef.kUserDataFolderSpecified.rawValue)
?? LMMgr.dataFolderPath(isDefaultFolder: true)
@State private var selAutoReloadUserData: Bool = UserDefaults.standard.bool(
forKey: UserDef.kShouldAutoReloadUserDataFiles.rawValue)
@State private var selUseExternalFactoryDict: Bool = UserDefaults.standard.bool(
forKey: UserDef.kUseExternalFactoryDict.rawValue)
@State private var selOnlyLoadFactoryLangModelsIfNeeded: Bool = UserDefaults.standard.bool(
forKey: UserDef.kOnlyLoadFactoryLangModelsIfNeeded.rawValue)
@State private var selEnableCNS11643: Bool = UserDefaults.standard.bool(forKey: UserDef.kCNS11643Enabled.rawValue)
@State private var selEnableSymbolInputSupport: Bool = UserDefaults.standard.bool(
forKey: UserDef.kSymbolInputEnabled.rawValue)
@State private var selFetchSuggestionsFromUserOverrideModel: Bool = UserDefaults.standard.bool(
forKey: UserDef.kFetchSuggestionsFromUserOverrideModel.rawValue)
@State private var selPhraseReplacementEnabled: Bool = UserDefaults.standard.bool(
forKey: UserDef.kPhraseReplacementEnabled.rawValue
)
@State private var selAllowBoostingSingleKanjiAsUserPhrase: Bool = UserDefaults.standard.bool(
forKey: UserDef.kAllowBoostingSingleKanjiAsUserPhrase.rawValue)
private static let dlgOpenPath = NSOpenPanel() private static let dlgOpenPath = NSOpenPanel()
private static let dlgOpenFile = NSOpenPanel() private static let dlgOpenFile = NSOpenPanel()
@ -47,8 +60,8 @@ struct VwrPrefPaneDictionary: View {
Group { Group {
Text(LocalizedStringKey("Choose your desired user data folder path. Will be omitted if invalid.")) Text(LocalizedStringKey("Choose your desired user data folder path. Will be omitted if invalid."))
HStack { HStack {
TextField(fdrUserDataDefault, text: $tbxUserDataPathSpecified).disabled(true) TextField(fdrUserDataDefault, text: $userDataFolderSpecified).disabled(true)
.help(tbxUserDataPathSpecified) .help(userDataFolderSpecified)
Button { Button {
Self.dlgOpenPath.title = NSLocalizedString( Self.dlgOpenPath.title = NSLocalizedString(
"Choose your desired user data folder.", comment: "" "Choose your desired user data folder.", comment: ""
@ -60,7 +73,7 @@ struct VwrPrefPaneDictionary: View {
Self.dlgOpenPath.canChooseDirectories = true Self.dlgOpenPath.canChooseDirectories = true
let bolPreviousFolderValidity = LMMgr.checkIfSpecifiedUserDataFolderValid( let bolPreviousFolderValidity = LMMgr.checkIfSpecifiedUserDataFolderValid(
PrefMgr.shared.userDataFolderSpecified.expandingTildeInPath) userDataFolderSpecified.expandingTildeInPath)
if let window = CtlPrefUIShared.sharedWindow { if let window = CtlPrefUIShared.sharedWindow {
Self.dlgOpenPath.beginSheetModal(for: window) { result in Self.dlgOpenPath.beginSheetModal(for: window) { result in
@ -71,8 +84,7 @@ struct VwrPrefPaneDictionary: View {
var newPath = url.path var newPath = url.path
newPath.ensureTrailingSlash() newPath.ensureTrailingSlash()
if LMMgr.checkIfSpecifiedUserDataFolderValid(newPath) { if LMMgr.checkIfSpecifiedUserDataFolderValid(newPath) {
PrefMgr.shared.userDataFolderSpecified = newPath userDataFolderSpecified = newPath
tbxUserDataPathSpecified = PrefMgr.shared.userDataFolderSpecified
BookmarkManager.shared.saveBookmark(for: url) BookmarkManager.shared.saveBookmark(for: url)
(NSApp.delegate as? AppDelegate)?.updateDirectoryMonitorPath() (NSApp.delegate as? AppDelegate)?.updateDirectoryMonitorPath()
} else { } else {
@ -94,17 +106,16 @@ struct VwrPrefPaneDictionary: View {
Text("...") Text("...")
} }
Button { Button {
userDataFolderSpecified = ""
LMMgr.resetSpecifiedUserDataFolder() LMMgr.resetSpecifiedUserDataFolder()
tbxUserDataPathSpecified = ""
} label: { } label: {
Text("") Text("")
} }
} }
Toggle( Toggle(
LocalizedStringKey("Automatically reload user data files if changes detected"), LocalizedStringKey("Automatically reload user data files if changes detected"),
isOn: $selAutoReloadUserData.onChange { isOn: $shouldAutoReloadUserDataFiles.onChange {
PrefMgr.shared.shouldAutoReloadUserDataFiles = selAutoReloadUserData if shouldAutoReloadUserDataFiles {
if selAutoReloadUserData {
LMMgr.initUserLangModels() LMMgr.initUserLangModels()
} }
} }
@ -120,8 +131,7 @@ struct VwrPrefPaneDictionary: View {
Group { Group {
Toggle( Toggle(
LocalizedStringKey("Read external factory dictionary plists if possible"), LocalizedStringKey("Read external factory dictionary plists if possible"),
isOn: $selUseExternalFactoryDict.onChange { isOn: $useExternalFactoryDict.onChange {
PrefMgr.shared.useExternalFactoryDict = selUseExternalFactoryDict
LMMgr.reloadFactoryDictionaryPlists() LMMgr.reloadFactoryDictionaryPlists()
} }
) )
@ -133,29 +143,25 @@ struct VwrPrefPaneDictionary: View {
.preferenceDescription() .preferenceDescription()
Toggle( Toggle(
LocalizedStringKey("Only load factory language models if needed"), LocalizedStringKey("Only load factory language models if needed"),
isOn: $selOnlyLoadFactoryLangModelsIfNeeded.onChange { isOn: $onlyLoadFactoryLangModelsIfNeeded.onChange {
PrefMgr.shared.onlyLoadFactoryLangModelsIfNeeded = selOnlyLoadFactoryLangModelsIfNeeded if !onlyLoadFactoryLangModelsIfNeeded { LMMgr.loadDataModelsOnAppDelegate() }
} }
) )
Toggle( Toggle(
LocalizedStringKey("Enable CNS11643 Support (2023-01-06)"), LocalizedStringKey("Enable CNS11643 Support (2023-01-06)"),
isOn: $selEnableCNS11643.onChange { isOn: $cns11643Enabled.onChange {
PrefMgr.shared.cns11643Enabled = selEnableCNS11643 LMMgr.setCNSEnabled(cns11643Enabled)
LMMgr.setCNSEnabled(PrefMgr.shared.cns11643Enabled)
} }
) )
Toggle( Toggle(
LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"), LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"),
isOn: $selEnableSymbolInputSupport.onChange { isOn: $symbolInputEnabled.onChange {
PrefMgr.shared.symbolInputEnabled = selEnableSymbolInputSupport LMMgr.setSymbolEnabled(symbolInputEnabled)
LMMgr.setSymbolEnabled(PrefMgr.shared.symbolInputEnabled)
} }
) )
Toggle( Toggle(
LocalizedStringKey("Applying typing suggestions from half-life user override model"), LocalizedStringKey("Applying typing suggestions from half-life user override model"),
isOn: $selFetchSuggestionsFromUserOverrideModel.onChange { isOn: $fetchSuggestionsFromUserOverrideModel
PrefMgr.shared.fetchSuggestionsFromUserOverrideModel = selFetchSuggestionsFromUserOverrideModel
}
) )
Text( Text(
"The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu.".localized "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu.".localized
@ -163,8 +169,11 @@ struct VwrPrefPaneDictionary: View {
.preferenceDescription() .preferenceDescription()
Toggle( Toggle(
LocalizedStringKey("Enable phrase replacement table"), LocalizedStringKey("Enable phrase replacement table"),
isOn: $selPhraseReplacementEnabled.onChange { isOn: $phraseReplacementEnabled.onChange {
PrefMgr.shared.phraseReplacementEnabled = selPhraseReplacementEnabled LMMgr.setPhraseReplacementEnabled(phraseReplacementEnabled)
if phraseReplacementEnabled {
LMMgr.loadUserPhraseReplacement()
}
} }
) )
Text("This will batch-replace specified candidates.".localized).preferenceDescription() Text("This will batch-replace specified candidates.".localized).preferenceDescription()
@ -173,9 +182,7 @@ struct VwrPrefPaneDictionary: View {
Group { Group {
Toggle( Toggle(
LocalizedStringKey("Allow boosting / excluding a candidate of single kanji when marking"), LocalizedStringKey("Allow boosting / excluding a candidate of single kanji when marking"),
isOn: $selAllowBoostingSingleKanjiAsUserPhrase.onChange { isOn: $allowBoostingSingleKanjiAsUserPhrase
PrefMgr.shared.allowBoostingSingleKanjiAsUserPhrase = selAllowBoostingSingleKanjiAsUserPhrase
}
) )
Text( Text(
LocalizedStringKey( LocalizedStringKey(

View File

@ -10,30 +10,63 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneGeneral: View { struct VwrPrefPaneGeneral: View {
@State private var selUILanguage: [String] = @Binding var appleLanguageTag: String
Shared.arrSupportedLocales.contains(
((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil) init() {
? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages.rawValue) as? [String] ?? ["auto"])[0]) _appleLanguageTag = .init(
? ((UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil) get: {
? ["auto"] : UserDefaults.standard.array(forKey: UserDef.kAppleLanguages.rawValue) as? [String] ?? ["auto"]) let loadedValue = (UserDefaults.standard.array(forKey: UserDef.kAppleLanguages.rawValue) as? [String] ?? ["auto"]).joined()
: ["auto"] let plistValueNotExist = (UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil)
@State private var selAutoCorrectReadingCombination = UserDefaults.standard.bool( let targetToCheck = (plistValueNotExist || loadedValue.isEmpty) ? "auto" : loadedValue
forKey: UserDef.kAutoCorrectReadingCombination.rawValue) return Shared.arrSupportedLocales.contains(targetToCheck) ? (plistValueNotExist ? "auto" : loadedValue) : "auto"
@State private var selShowHanyuPinyinInCompositionBuffer = UserDefaults.standard.bool( }, set: { newValue in
forKey: UserDef.kShowHanyuPinyinInCompositionBuffer.rawValue) var newValue = newValue
@State private var selKeepReadingUponCompositionError = UserDefaults.standard.bool( if newValue.isEmpty || newValue == "auto" {
forKey: UserDef.kKeepReadingUponCompositionError.rawValue) UserDefaults.standard.removeObject(forKey: UserDef.kAppleLanguages.rawValue)
@State private var selClassicHaninKeyboardSymbolModeShortcutEnabled = UserDefaults.standard.bool( }
forKey: UserDef.kClassicHaninKeyboardSymbolModeShortcutEnabled.rawValue) if newValue == "auto" { newValue = "" }
@State private var selEnableSCPCTypingMode = UserDefaults.standard.bool(forKey: UserDef.kUseSCPCTypingMode.rawValue) guard PrefMgr.shared.appleLanguages.joined() != newValue else { return }
@State private var selEnableFartSuppressor = UserDefaults.standard.bool( if !newValue.isEmpty { PrefMgr.shared.appleLanguages = [newValue] }
forKey: UserDef.kShouldNotFartInLieuOfBeep.rawValue) NSLog("vChewing App self-terminated due to UI language change.")
@State private var selEnableAutoUpdateCheck = UserDefaults.standard.bool( NSApp.terminate(nil)
forKey: UserDef.kCheckUpdateAutomatically.rawValue) }
@State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled.rawValue) )
}
// MARK: - AppStorage Variables
@Backport.AppStorage(wrappedValue: [], UserDef.kAppleLanguages.rawValue)
private var appleLanguages: [String]
@Backport.AppStorage(wrappedValue: true, UserDef.kAutoCorrectReadingCombination.rawValue)
private var autoCorrectReadingCombination: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kKeepReadingUponCompositionError.rawValue)
private var keepReadingUponCompositionError: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kShowHanyuPinyinInCompositionBuffer.rawValue)
private var showHanyuPinyinInCompositionBuffer: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kClassicHaninKeyboardSymbolModeShortcutEnabled.rawValue)
private var classicHaninKeyboardSymbolModeShortcutEnabled: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kUseSCPCTypingMode.rawValue)
private var useSCPCTypingMode: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kShouldNotFartInLieuOfBeep.rawValue)
private var shouldNotFartInLieuOfBeep: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kCheckUpdateAutomatically.rawValue)
private var checkUpdateAutomatically: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kIsDebugModeEnabled.rawValue)
private var isDebugModeEnabled: Bool
// MARK: - Main View
var body: some View { var body: some View {
ScrollView { ScrollView {
@ -56,28 +89,13 @@ struct VwrPrefPaneGeneral: View {
HStack { HStack {
Picker( Picker(
LocalizedStringKey("Follow OS settings"), LocalizedStringKey("Follow OS settings"),
selection: $selUILanguage.onChange { selection: $appleLanguageTag
vCLog(selUILanguage[0])
if selUILanguage == PrefMgr.shared.appleLanguages
|| (selUILanguage[0] == "auto"
&& UserDefaults.standard.object(forKey: UserDef.kAppleLanguages.rawValue) == nil)
{
return
}
if selUILanguage[0] != "auto" {
PrefMgr.shared.appleLanguages = selUILanguage
} else {
UserDefaults.standard.removeObject(forKey: UserDef.kAppleLanguages.rawValue)
}
NSLog("vChewing App self-terminated due to UI language change.")
NSApp.terminate(nil)
}
) { ) {
Text(LocalizedStringKey("Follow OS settings")).tag(["auto"]) Text(LocalizedStringKey("Follow OS settings")).tag("auto")
Text(LocalizedStringKey("Simplified Chinese")).tag(["zh-Hans"]) Text(LocalizedStringKey("Simplified Chinese")).tag("zh-Hans")
Text(LocalizedStringKey("Traditional Chinese")).tag(["zh-Hant"]) Text(LocalizedStringKey("Traditional Chinese")).tag("zh-Hant")
Text(LocalizedStringKey("Japanese")).tag(["ja"]) Text(LocalizedStringKey("Japanese")).tag("ja")
Text(LocalizedStringKey("English")).tag(["en"]) Text(LocalizedStringKey("English")).tag("en")
} }
.labelsHidden() .labelsHidden()
.frame(width: 180.0) .frame(width: 180.0)
@ -89,33 +107,25 @@ struct VwrPrefPaneGeneral: View {
SSPreferences.Section(label: { Text(LocalizedStringKey("Typing Settings:")) }) { SSPreferences.Section(label: { Text(LocalizedStringKey("Typing Settings:")) }) {
Toggle( Toggle(
LocalizedStringKey("Automatically correct reading combinations when typing"), LocalizedStringKey("Automatically correct reading combinations when typing"),
isOn: $selAutoCorrectReadingCombination.onChange { isOn: $autoCorrectReadingCombination
PrefMgr.shared.autoCorrectReadingCombination = selAutoCorrectReadingCombination
}
) )
Toggle( Toggle(
LocalizedStringKey("Show Hanyu-Pinyin in the inline composition buffer"), LocalizedStringKey("Show Hanyu-Pinyin in the inline composition buffer"),
isOn: $selShowHanyuPinyinInCompositionBuffer.onChange { isOn: $showHanyuPinyinInCompositionBuffer
PrefMgr.shared.showHanyuPinyinInCompositionBuffer = selShowHanyuPinyinInCompositionBuffer
}
) )
Toggle( Toggle(
LocalizedStringKey("Allow backspace-editing miscomposed readings"), LocalizedStringKey("Allow backspace-editing miscomposed readings"),
isOn: $selKeepReadingUponCompositionError.onChange { isOn: $keepReadingUponCompositionError
PrefMgr.shared.keepReadingUponCompositionError = selKeepReadingUponCompositionError
}
) )
Toggle( Toggle(
LocalizedStringKey("Also use “\\” or “¥” key for Hanin Keyboard Symbol Input"), LocalizedStringKey("Also use “\\” or “¥” key for Hanin Keyboard Symbol Input"),
isOn: $selClassicHaninKeyboardSymbolModeShortcutEnabled.onChange { isOn: $classicHaninKeyboardSymbolModeShortcutEnabled
PrefMgr.shared.classicHaninKeyboardSymbolModeShortcutEnabled
= selClassicHaninKeyboardSymbolModeShortcutEnabled
}
) )
Toggle( Toggle(
LocalizedStringKey("Emulating select-candidate-per-character mode"), LocalizedStringKey("Emulating select-candidate-per-character mode"),
isOn: $selEnableSCPCTypingMode.onChange { isOn: $useSCPCTypingMode.onChange {
PrefMgr.shared.useSCPCTypingMode = selEnableSCPCTypingMode guard useSCPCTypingMode else { return }
LMMgr.loadUserSCPCSequencesData()
} }
) )
Text(LocalizedStringKey("An accommodation for elder computer users.")) Text(LocalizedStringKey("An accommodation for elder computer users."))
@ -123,7 +133,7 @@ struct VwrPrefPaneGeneral: View {
if Date.isTodayTheDate(from: 0401) { if Date.isTodayTheDate(from: 0401) {
Toggle( Toggle(
LocalizedStringKey("Stop farting (when typed phonetic combination is invalid, etc.)"), LocalizedStringKey("Stop farting (when typed phonetic combination is invalid, etc.)"),
isOn: $selEnableFartSuppressor.onChange { isOn: $shouldNotFartInLieuOfBeep.onChange {
let content = String( let content = String(
format: NSLocalizedString( format: NSLocalizedString(
"You are about to uncheck this fart suppressor. You are responsible for all consequences lead by letting people nearby hear the fart sound come from your computer. We strongly advise against unchecking this in any public circumstance that prohibits NSFW netas.", "You are about to uncheck this fart suppressor. You are responsible for all consequences lead by letting people nearby hear the fart sound come from your computer. We strongly advise against unchecking this in any public circumstance that prohibits NSFW netas.",
@ -138,22 +148,20 @@ struct VwrPrefPaneGeneral: View {
} }
} }
alert.addButton(withTitle: NSLocalizedString("Leave it checked", comment: "")) alert.addButton(withTitle: NSLocalizedString("Leave it checked", comment: ""))
if let window = CtlPrefUIShared.sharedWindow, !selEnableFartSuppressor { if let window = CtlPrefUIShared.sharedWindow, !shouldNotFartInLieuOfBeep {
PrefMgr.shared.shouldNotFartInLieuOfBeep = true shouldNotFartInLieuOfBeep = true
alert.beginSheetModal(for: window) { result in alert.beginSheetModal(for: window) { result in
switch result { switch result {
case .alertFirstButtonReturn: case .alertFirstButtonReturn:
PrefMgr.shared.shouldNotFartInLieuOfBeep = false shouldNotFartInLieuOfBeep = false
case .alertSecondButtonReturn: case .alertSecondButtonReturn:
PrefMgr.shared.shouldNotFartInLieuOfBeep = true shouldNotFartInLieuOfBeep = true
default: break default: break
} }
selEnableFartSuppressor = PrefMgr.shared.shouldNotFartInLieuOfBeep
IMEApp.buzz() IMEApp.buzz()
} }
return return
} }
PrefMgr.shared.shouldNotFartInLieuOfBeep = selEnableFartSuppressor
IMEApp.buzz() IMEApp.buzz()
} }
) )
@ -162,16 +170,12 @@ struct VwrPrefPaneGeneral: View {
SSPreferences.Section(label: { Text(LocalizedStringKey("Misc Settings:")).controlSize(.small) }) { SSPreferences.Section(label: { Text(LocalizedStringKey("Misc Settings:")).controlSize(.small) }) {
Toggle( Toggle(
LocalizedStringKey("Check for updates automatically"), LocalizedStringKey("Check for updates automatically"),
isOn: $selEnableAutoUpdateCheck.onChange { isOn: $checkUpdateAutomatically
PrefMgr.shared.checkUpdateAutomatically = selEnableAutoUpdateCheck
}
) )
.controlSize(.small) .controlSize(.small)
Toggle( Toggle(
LocalizedStringKey("Debug Mode"), LocalizedStringKey("Debug Mode"),
isOn: $selEnableDebugMode.onChange { isOn: $isDebugModeEnabled
PrefMgr.shared.isDebugModeEnabled = selEnableDebugMode
}
) )
.controlSize(.small) .controlSize(.small)
} }

View File

@ -11,15 +11,28 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneKeyboard: View { struct VwrPrefPaneKeyboard: View {
@State private var selKeyboardParser = UserDefaults.standard.integer(forKey: UserDef.kKeyboardParser.rawValue) // MARK: - AppStorage Variables
@State private var selBasicKeyboardLayout: String =
UserDefaults.standard.string(forKey: UserDef.kBasicKeyboardLayout.rawValue) ?? PrefMgr.shared.basicKeyboardLayout @Backport.AppStorage(wrappedValue: 0, UserDef.kKeyboardParser.rawValue)
@State private var selAlphanumericalKeyboardLayout: String = private var keyboardParser: Int
UserDefaults.standard.string(forKey: UserDef.kAlphanumericalKeyboardLayout.rawValue)
?? PrefMgr.shared.alphanumericalKeyboardLayout @Backport.AppStorage(
wrappedValue: PrefMgr.kDefaultBasicKeyboardLayout,
UserDef.kBasicKeyboardLayout.rawValue
)
private var basicKeyboardLayout: String
@Backport.AppStorage(
wrappedValue: PrefMgr.kDefaultAlphanumericalKeyboardLayout,
UserDef.kAlphanumericalKeyboardLayout.rawValue
)
private var alphanumericalKeyboardLayout: String
// MARK: - Main View
var body: some View { var body: some View {
ScrollView { ScrollView {
@ -27,26 +40,20 @@ struct VwrPrefPaneKeyboard: View {
SSPreferences.Section(title: "Quick Setup:".localized) { SSPreferences.Section(title: "Quick Setup:".localized) {
HStack(alignment: .top) { HStack(alignment: .top) {
Button { Button {
PrefMgr.shared.keyboardParser = 0 keyboardParser = 0
selKeyboardParser = PrefMgr.shared.keyboardParser basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
PrefMgr.shared.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
selBasicKeyboardLayout = PrefMgr.shared.basicKeyboardLayout
} label: { } label: {
Text("↻ㄅ" + " " + NSLocalizedString("Dachen Trad.", comment: "")) Text("↻ㄅ" + " " + NSLocalizedString("Dachen Trad.", comment: ""))
} }
Button { Button {
PrefMgr.shared.keyboardParser = 1 keyboardParser = 1
selKeyboardParser = PrefMgr.shared.keyboardParser basicKeyboardLayout = "com.apple.keylayout.ZhuyinEten"
PrefMgr.shared.basicKeyboardLayout = "com.apple.keylayout.ZhuyinEten"
selBasicKeyboardLayout = PrefMgr.shared.basicKeyboardLayout
} label: { } label: {
Text("↻ㄅ" + " " + NSLocalizedString("Eten Trad.", comment: "")) Text("↻ㄅ" + " " + NSLocalizedString("Eten Trad.", comment: ""))
} }
Button { Button {
PrefMgr.shared.keyboardParser = 10 keyboardParser = 10
selKeyboardParser = PrefMgr.shared.keyboardParser basicKeyboardLayout = "com.apple.keylayout.ABC"
PrefMgr.shared.basicKeyboardLayout = "com.apple.keylayout.ABC"
selBasicKeyboardLayout = PrefMgr.shared.basicKeyboardLayout
} label: { } label: {
Text("↻A") Text("↻A")
} }
@ -56,10 +63,7 @@ struct VwrPrefPaneKeyboard: View {
HStack { HStack {
Picker( Picker(
"", "",
selection: $selKeyboardParser.onChange { selection: $keyboardParser
let value = selKeyboardParser
PrefMgr.shared.keyboardParser = value
}
) { ) {
ForEach(KeyboardParser.allCases, id: \.self) { item in ForEach(KeyboardParser.allCases, id: \.self) { item in
if [7, 10].contains(item.rawValue) { Divider() } if [7, 10].contains(item.rawValue) { Divider() }
@ -77,10 +81,7 @@ struct VwrPrefPaneKeyboard: View {
HStack { HStack {
Picker( Picker(
"", "",
selection: $selBasicKeyboardLayout.onChange { selection: $basicKeyboardLayout
let value = selBasicKeyboardLayout
PrefMgr.shared.basicKeyboardLayout = value
}
) { ) {
ForEach(0 ... (IMKHelper.allowedBasicLayoutsAsTISInputSources.count - 1), id: \.self) { id in ForEach(0 ... (IMKHelper.allowedBasicLayoutsAsTISInputSources.count - 1), id: \.self) { id in
let theEntry = IMKHelper.allowedBasicLayoutsAsTISInputSources[id] let theEntry = IMKHelper.allowedBasicLayoutsAsTISInputSources[id]
@ -106,9 +107,7 @@ struct VwrPrefPaneKeyboard: View {
HStack { HStack {
Picker( Picker(
"", "",
selection: $selAlphanumericalKeyboardLayout.onChange { selection: $alphanumericalKeyboardLayout
PrefMgr.shared.alphanumericalKeyboardLayout = selAlphanumericalKeyboardLayout
}
) { ) {
ForEach(0 ... (IMKHelper.allowedAlphanumericalTISInputSources.count - 1), id: \.self) { id in ForEach(0 ... (IMKHelper.allowedAlphanumericalTISInputSources.count - 1), id: \.self) { id in
if let theEntry = IMKHelper.allowedAlphanumericalTISInputSources[id] { if let theEntry = IMKHelper.allowedAlphanumericalTISInputSources[id] {
@ -138,79 +137,77 @@ struct VwrPrefPaneKeyboard: View {
@available(macOS 10.15, *) @available(macOS 10.15, *)
private struct VwrPrefPaneKeyboard_KeyboardShortcuts: View { private struct VwrPrefPaneKeyboard_KeyboardShortcuts: View {
@State private var selUsingHotKeySCPC = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeySCPC.rawValue) // MARK: - AppStorage Variables
@State private var selUsingHotKeyAssociates = UserDefaults.standard.bool(
forKey: UserDef.kUsingHotKeyAssociates.rawValue) @Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeySCPC.rawValue)
@State private var selUsingHotKeyCNS = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyCNS.rawValue) private var usingHotKeySCPC: Bool
@State private var selUsingHotKeyKangXi = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyKangXi.rawValue)
@State private var selUsingHotKeyJIS = UserDefaults.standard.bool(forKey: UserDef.kUsingHotKeyJIS.rawValue) @Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyAssociates.rawValue)
@State private var selUsingHotKeyHalfWidthASCII = UserDefaults.standard.bool( private var usingHotKeyAssociates: Bool
forKey: UserDef.kUsingHotKeyHalfWidthASCII.rawValue)
@State private var selUsingHotKeyCurrencyNumerals = UserDefaults.standard.bool( @Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyCNS.rawValue)
forKey: UserDef.kUsingHotKeyCurrencyNumerals.rawValue) private var usingHotKeyCNS: Bool
@State private var selUsingHotKeyCassette = UserDefaults.standard.bool(
forKey: UserDef.kUsingHotKeyCassette.rawValue) @Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyKangXi.rawValue)
@State private var selUsingHotKeyRevLookup = UserDefaults.standard.bool( private var usingHotKeyKangXi: Bool
forKey: UserDef.kUsingHotKeyRevLookup.rawValue)
@Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyJIS.rawValue)
private var usingHotKeyJIS: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyHalfWidthASCII.rawValue)
private var usingHotKeyHalfWidthASCII: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyCurrencyNumerals.rawValue)
private var usingHotKeyCurrencyNumerals: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyCassette.rawValue)
private var usingHotKeyCassette: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kUsingHotKeyRevLookup.rawValue)
private var usingHotKeyRevLookup: Bool
// MARK: - Main View
var body: some View { var body: some View {
HStack(alignment: .top, spacing: NSFont.systemFontSize) { HStack(alignment: .top, spacing: NSFont.systemFontSize) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
Toggle( Toggle(
LocalizedStringKey("Per-Char Select Mode"), LocalizedStringKey("Per-Char Select Mode"),
isOn: $selUsingHotKeySCPC.onChange { isOn: $usingHotKeySCPC
PrefMgr.shared.usingHotKeySCPC = selUsingHotKeySCPC
}
) )
Toggle( Toggle(
LocalizedStringKey("Per-Char Associated Phrases"), LocalizedStringKey("Per-Char Associated Phrases"),
isOn: $selUsingHotKeyAssociates.onChange { isOn: $usingHotKeyAssociates
PrefMgr.shared.usingHotKeyAssociates = selUsingHotKeyAssociates
}
) )
Toggle( Toggle(
LocalizedStringKey("CNS11643 Mode"), LocalizedStringKey("CNS11643 Mode"),
isOn: $selUsingHotKeyCNS.onChange { isOn: $usingHotKeyCNS
PrefMgr.shared.usingHotKeyCNS = selUsingHotKeyCNS
}
) )
Toggle( Toggle(
LocalizedStringKey("Force KangXi Writing"), LocalizedStringKey("Force KangXi Writing"),
isOn: $selUsingHotKeyKangXi.onChange { isOn: $usingHotKeyKangXi
PrefMgr.shared.usingHotKeyKangXi = selUsingHotKeyKangXi
}
) )
Toggle( Toggle(
LocalizedStringKey("Reverse Lookup (Phonabets)"), LocalizedStringKey("Reverse Lookup (Phonabets)"),
isOn: $selUsingHotKeyRevLookup.onChange { isOn: $usingHotKeyRevLookup
PrefMgr.shared.usingHotKeyRevLookup = selUsingHotKeyRevLookup
}
) )
} }
VStack(alignment: .leading) { VStack(alignment: .leading) {
Toggle( Toggle(
LocalizedStringKey("JIS Shinjitai Output"), LocalizedStringKey("JIS Shinjitai Output"),
isOn: $selUsingHotKeyJIS.onChange { isOn: $usingHotKeyJIS
PrefMgr.shared.usingHotKeyJIS = selUsingHotKeyJIS
}
) )
Toggle( Toggle(
LocalizedStringKey("Half-Width Punctuation Mode"), LocalizedStringKey("Half-Width Punctuation Mode"),
isOn: $selUsingHotKeyHalfWidthASCII.onChange { isOn: $usingHotKeyHalfWidthASCII
PrefMgr.shared.usingHotKeyHalfWidthASCII = selUsingHotKeyHalfWidthASCII
}
) )
Toggle( Toggle(
LocalizedStringKey("Currency Numeral Output"), LocalizedStringKey("Currency Numeral Output"),
isOn: $selUsingHotKeyCurrencyNumerals.onChange { isOn: $usingHotKeyCurrencyNumerals
PrefMgr.shared.usingHotKeyCurrencyNumerals = selUsingHotKeyCurrencyNumerals
}
) )
Toggle( Toggle(
LocalizedStringKey("CIN Cassette Mode"), LocalizedStringKey("CIN Cassette Mode"),
isOn: $selUsingHotKeyCassette.onChange { isOn: $usingHotKeyCassette
PrefMgr.shared.usingHotKeyCassette = selUsingHotKeyCassette
}
) )
} }
} }

View File

@ -10,26 +10,28 @@ import Shared
import SSPreferences import SSPreferences
import SwiftExtension import SwiftExtension
import SwiftUI import SwiftUI
import SwiftUIBackports
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPaneOutput: View { struct VwrPrefPaneOutput: View {
@State private var selEnableKanjiConvToKangXi = UserDefaults.standard.bool( // MARK: - AppStorage Variables
forKey: UserDef.kChineseConversionEnabled.rawValue)
@State private var selEnableKanjiConvToJIS = UserDefaults.standard.bool(
forKey: UserDef.kShiftJISShinjitaiOutputEnabled.rawValue)
@State private var selInlineDumpPinyinInLieuOfZhuyin = UserDefaults.standard.bool(
forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin.rawValue)
@State private var selTrimUnfinishedReadingsOnCommit = UserDefaults.standard.bool(
forKey: UserDef.kTrimUnfinishedReadingsOnCommit.rawValue)
@State private var selHardenVerticalPunctuations: Bool = UserDefaults.standard.bool(
forKey: UserDef.kHardenVerticalPunctuations.rawValue)
var macOSMontereyOrLaterDetected: Bool { @Backport.AppStorage(wrappedValue: false, UserDef.kChineseConversionEnabled.rawValue)
if #available(macOS 12, *) { private var chineseConversionEnabled: Bool
return true
} @Backport.AppStorage(wrappedValue: false, UserDef.kShiftJISShinjitaiOutputEnabled.rawValue)
return false private var shiftJISShinjitaiOutputEnabled: Bool
}
@Backport.AppStorage(wrappedValue: false, UserDef.kInlineDumpPinyinInLieuOfZhuyin.rawValue)
private var inlineDumpPinyinInLieuOfZhuyin: Bool
@Backport.AppStorage(wrappedValue: true, UserDef.kTrimUnfinishedReadingsOnCommit.rawValue)
private var trimUnfinishedReadingsOnCommit: Bool
@Backport.AppStorage(wrappedValue: false, UserDef.kHardenVerticalPunctuations.rawValue)
private var hardenVerticalPunctuations: Bool
// MARK: - Main View
var body: some View { var body: some View {
ScrollView { ScrollView {
@ -37,37 +39,33 @@ struct VwrPrefPaneOutput: View {
SSPreferences.Section(title: "Output Settings:".localized, bottomDivider: true) { SSPreferences.Section(title: "Output Settings:".localized, bottomDivider: true) {
Toggle( Toggle(
LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"), LocalizedStringKey("Auto-convert traditional Chinese glyphs to KangXi characters"),
isOn: $selEnableKanjiConvToKangXi.onChange { isOn: $chineseConversionEnabled.onChange {
PrefMgr.shared.chineseConversionEnabled = selEnableKanjiConvToKangXi if chineseConversionEnabled, shiftJISShinjitaiOutputEnabled {
selEnableKanjiConvToJIS = PrefMgr.shared.shiftJISShinjitaiOutputEnabled shiftJISShinjitaiOutputEnabled = false
}
} }
) )
Toggle( Toggle(
LocalizedStringKey("Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"), LocalizedStringKey("Auto-convert traditional Chinese glyphs to JIS Shinjitai characters"),
isOn: $selEnableKanjiConvToJIS.onChange { isOn: $shiftJISShinjitaiOutputEnabled.onChange {
PrefMgr.shared.shiftJISShinjitaiOutputEnabled = selEnableKanjiConvToJIS if chineseConversionEnabled, shiftJISShinjitaiOutputEnabled {
selEnableKanjiConvToKangXi = PrefMgr.shared.chineseConversionEnabled chineseConversionEnabled = false
}
} }
) )
Toggle( Toggle(
LocalizedStringKey("Commit Hanyu-Pinyin instead on Ctrl(+Option)+Command+Enter"), LocalizedStringKey("Commit Hanyu-Pinyin instead on Ctrl(+Option)+Command+Enter"),
isOn: $selInlineDumpPinyinInLieuOfZhuyin.onChange { isOn: $inlineDumpPinyinInLieuOfZhuyin
PrefMgr.shared.inlineDumpPinyinInLieuOfZhuyin = selInlineDumpPinyinInLieuOfZhuyin
}
) )
Toggle( Toggle(
LocalizedStringKey("Trim unfinished readings / strokes on commit"), LocalizedStringKey("Trim unfinished readings / strokes on commit"),
isOn: $selTrimUnfinishedReadingsOnCommit.onChange { isOn: $trimUnfinishedReadingsOnCommit
PrefMgr.shared.trimUnfinishedReadingsOnCommit = selTrimUnfinishedReadingsOnCommit
}
) )
} }
SSPreferences.Section(title: "Experimental:".localized) { SSPreferences.Section(title: "Experimental:".localized) {
Toggle( Toggle(
LocalizedStringKey("Harden vertical punctuations during vertical typing (not recommended)"), LocalizedStringKey("Harden vertical punctuations during vertical typing (not recommended)"),
isOn: $selHardenVerticalPunctuations.onChange { isOn: $hardenVerticalPunctuations
PrefMgr.shared.hardenVerticalPunctuations = selHardenVerticalPunctuations
}
) )
Text( Text(
LocalizedStringKey( LocalizedStringKey(

View File

@ -14,13 +14,6 @@ import SwiftUI
@available(macOS 10.15, *) @available(macOS 10.15, *)
struct VwrPrefPanePhrases: View { struct VwrPrefPanePhrases: View {
var isMontereyOrAbove: Bool = {
if #available(macOS 12.0, *) {
return true
}
return false
}()
var body: some View { var body: some View {
ScrollView { ScrollView {
VStack { VStack {

View File

@ -324,6 +324,7 @@
"The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu."; "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu.";
"This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode."; "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode.";
"This feature requires macOS 10.15 and above." = "This feature requires macOS 10.15 and above."; "This feature requires macOS 10.15 and above." = "This feature requires macOS 10.15 and above.";
"This feature requires macOS 12 and above." = "This feature requires macOS 12 and above.";
"This only works with Tadokoro candidate window." = "This only works with Tadokoro candidate window."; "This only works with Tadokoro candidate window." = "This only works with Tadokoro candidate window.";
"This will also affect the row / column capacity of the candidate window." = "This will also affect the row / column capacity of the candidate window."; "This will also affect the row / column capacity of the candidate window." = "This will also affect the row / column capacity of the candidate window.";
"This will batch-replace specified candidates." = "This will batch-replace specified candidates."; "This will batch-replace specified candidates." = "This will batch-replace specified candidates.";

View File

@ -324,6 +324,7 @@
"The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu."; "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu.";
"This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode."; "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode.";
"This feature requires macOS 10.15 and above." = "This feature requires macOS 10.15 and above."; "This feature requires macOS 10.15 and above." = "This feature requires macOS 10.15 and above.";
"This feature requires macOS 12 and above." = "This feature requires macOS 12 and above.";
"This only works with Tadokoro candidate window." = "This only works with Tadokoro candidate window."; "This only works with Tadokoro candidate window." = "This only works with Tadokoro candidate window.";
"This will also affect the row / column capacity of the candidate window." = "This will also affect the row / column capacity of the candidate window."; "This will also affect the row / column capacity of the candidate window." = "This will also affect the row / column capacity of the candidate window.";
"This will batch-replace specified candidates." = "This will batch-replace specified candidates."; "This will batch-replace specified candidates." = "This will batch-replace specified candidates.";

View File

@ -325,6 +325,7 @@
"The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "臨時記憶モジュールは文字の通り「臨時的」の記憶をします。記録は六日間どんどん忘れてしまいます。入力アプリのメニューから全ての記録を消すことはできます。"; "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "臨時記憶モジュールは文字の通り「臨時的」の記憶をします。記録は六日間どんどん忘れてしまいます。入力アプリのメニューから全ての記録を消すことはできます。";
"This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "この転換はカセットモードだけに使える転換であり、転換結果はこの設定と入力モード次第である。"; "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "この転換はカセットモードだけに使える転換であり、転換結果はこの設定と入力モード次第である。";
"This feature requires macOS 10.15 and above." = "この機能の稼働には macOS 10.15 以降のシステムが必要である。"; "This feature requires macOS 10.15 and above." = "この機能の稼働には macOS 10.15 以降のシステムが必要である。";
"This feature requires macOS 12 and above." = "この機能の稼働には macOS 12 以降のシステムが必要である。";
"This only works with Tadokoro candidate window." = "これは田所候補陳列ウィンドウだけに効ける機能である。"; "This only works with Tadokoro candidate window." = "これは田所候補陳列ウィンドウだけに効ける機能である。";
"This will also affect the row / column capacity of the candidate window." = "言選り用キーの数は、候補陳列の行・列の容量制限にも影響。"; "This will also affect the row / column capacity of the candidate window." = "言選り用キーの数は、候補陳列の行・列の容量制限にも影響。";
"This will batch-replace specified candidates." = "指定された候補そのものを置き換える"; "This will batch-replace specified candidates." = "指定された候補そのものを置き換える";

View File

@ -324,6 +324,7 @@
"The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "半衰记忆模组仅持有临时记忆之功能。每一笔记录都会在六天之内逐渐变得彻底失效。您可以借由输入法选单清除全部的记忆记录。"; "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "半衰记忆模组仅持有临时记忆之功能。每一笔记录都会在六天之内逐渐变得彻底失效。您可以借由输入法选单清除全部的记忆记录。";
"This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "该转换仅对磁带模式有影响,会将键入的内容根据该选项与当前的简繁体模式来转换。"; "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "该转换仅对磁带模式有影响,会将键入的内容根据该选项与当前的简繁体模式来转换。";
"This feature requires macOS 10.15 and above." = "该功能要求系统版本至少 macOS 10.15。"; "This feature requires macOS 10.15 and above." = "该功能要求系统版本至少 macOS 10.15。";
"This feature requires macOS 12 and above." = "该功能要求系统版本至少 macOS 12。";
"This only works with Tadokoro candidate window." = "该选项仅对田所选字窗起作用。"; "This only works with Tadokoro candidate window." = "该选项仅对田所选字窗起作用。";
"This will also affect the row / column capacity of the candidate window." = "该选项也会影响到选字窗每行/每列最多显示的候选字数量。"; "This will also affect the row / column capacity of the candidate window." = "该选项也会影响到选字窗每行/每列最多显示的候选字数量。";
"This will batch-replace specified candidates." = "这将会对指定的候选字词进行整词取代。"; "This will batch-replace specified candidates." = "这将会对指定的候选字词进行整词取代。";

View File

@ -324,6 +324,7 @@
"The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "半衰記憶模組僅持有臨時記憶之功能。每一筆記錄都會在六天之內逐漸變得徹底失效。您可以藉由輸入法選單清除全部的記憶記錄。"; "The user override model only possesses memories temporarily. Each memory record gradually becomes ineffective within approximately less than 6 days. You can erase all memory records through the input method menu." = "半衰記憶模組僅持有臨時記憶之功能。每一筆記錄都會在六天之內逐漸變得徹底失效。您可以藉由輸入法選單清除全部的記憶記錄。";
"This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "該轉換僅對磁帶模式有影響,會將鍵入的內容根據該選項與當前的簡繁體模式來轉換。"; "This conversion only affects the cassette module, converting typed contents to either Simplified Chinese or Traditional Chinese in accordance with this setting and your current input mode." = "該轉換僅對磁帶模式有影響,會將鍵入的內容根據該選項與當前的簡繁體模式來轉換。";
"This feature requires macOS 10.15 and above." = "該功能要求系統版本至少 macOS 10.15。"; "This feature requires macOS 10.15 and above." = "該功能要求系統版本至少 macOS 10.15。";
"This feature requires macOS 12 and above." = "該功能要求系統版本至少 macOS 12。";
"This only works with Tadokoro candidate window." = "該選項僅對田所選字窗起作用。"; "This only works with Tadokoro candidate window." = "該選項僅對田所選字窗起作用。";
"This will also affect the row / column capacity of the candidate window." = "該選項也會影響到選字窗每行/每列最多顯示的候選字數量。"; "This will also affect the row / column capacity of the candidate window." = "該選項也會影響到選字窗每行/每列最多顯示的候選字數量。";
"This will batch-replace specified candidates." = "這將會對指定的候選字詞進行整詞取代。"; "This will batch-replace specified candidates." = "這將會對指定的候選字詞進行整詞取代。";