PrefUI // Use AppStorage to handle UserDefaults, plus comment fix.
This commit is contained in:
parent
b715325db3
commit
8541c3b9e6
|
@ -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(
|
||||||
|
|
|
@ -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) {
|
||||||
IMEApp.buzz()
|
if let window = CtlPrefUIShared.sharedWindow, !keys.isEmpty {
|
||||||
if let window = CtlPrefUIShared.sharedWindow {
|
IMEApp.buzz()
|
||||||
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 {
|
|
||||||
selSelectionKeys = PrefMgr.shared.candidateKeys
|
|
||||||
}
|
}
|
||||||
} else {
|
candidateKeys = PrefMgr.kDefaultCandidateKeys
|
||||||
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."
|
||||||
|
|
|
@ -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()
|
|
||||||
PrefMgr.shared.cassetteEnabled = false
|
|
||||||
selCassetteEnabled = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LMMgr.resetCassettePath()
|
||||||
|
cassetteEnabled = 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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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.";
|
||||||
|
|
|
@ -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.";
|
||||||
|
|
|
@ -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." = "指定された候補そのものを置き換える";
|
||||||
|
|
|
@ -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." = "这将会对指定的候选字词进行整词取代。";
|
||||||
|
|
|
@ -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." = "這將會對指定的候選字詞進行整詞取代。";
|
||||||
|
|
Loading…
Reference in New Issue