From f51fc98e55d53cf0d61b69f1042f1763dbbdfc8f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Wed, 2 Aug 2023 23:27:38 +0900 Subject: [PATCH 001/124] Fixed warnings mainly relating to concurrency --- .../AutoCompletionStrengthSetting.swift | 2 +- .../KeyboardSetting/KeyboardSetting.swift | 14 ++++++-------- .../KeyboardSetting/MarkedTextSetting.swift | 2 +- .../QwertyCustomKeyKeyboardSetting.swift | 2 +- AzooKeyCore/Sources/KeyboardViews/Design.swift | 6 +++--- .../View/Components/ResizingRect.swift | 4 ++-- .../View/CustomKeybaord/CustomKeyboard.swift | 2 +- .../KeyView/FlickKeyModelProtocol.swift | 5 +++-- .../SuggestView/FlickedKeyModel.swift | 2 +- .../View/KeyboardBar/EmojiTabResultBar.swift | 8 +++++--- .../View/KeyboardBar/ResultBar.swift | 13 ++++++++----- .../SwiftUIUtils/TouchDownAndTouchUpGesture.swift | 2 +- Keyboard/Display/KeyboardViewController.swift | 2 +- MainApp/Customize/CustardInformationView.swift | 2 +- MainApp/Customize/EditingTenkeyCustardView.swift | 2 +- MainApp/Customize/ManageCustardView.swift | 4 ++-- MainApp/General/CancelableEditor.swift | 2 +- MainApp/General/DraggableView.swift | 2 +- MainApp/General/Focus.swift | 4 ++-- MainApp/LOUDSLogic/LOUDSBuilder.swift | 6 +++--- .../AdditionalDict/AzooKeyUserDictionary.swift | 15 +++++++-------- .../FlickCustomKeySettingView.swift | 12 +++++++----- .../QwertyCustomKeysItemView.swift | 8 ++++++-- .../FlickSensitivitySettingView.swift | 2 +- .../Setting/OpenSourceSoftwaresLicenseView.swift | 2 -- MainApp/Setting/Template/TemplateListView.swift | 2 +- 26 files changed, 67 insertions(+), 60 deletions(-) diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/AutoCompletionStrengthSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/AutoCompletionStrengthSetting.swift index 818152a5..24b06aa3 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/AutoCompletionStrengthSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/AutoCompletionStrengthSetting.swift @@ -10,7 +10,7 @@ import Foundation import SwiftUI public struct AutomaticCompletionStrengthKey: KeyboardSettingKey, StoredInUserDefault { - public enum Value: Int { + public enum Value: Int, Sendable { case disabled // 無効化 case weak // 弱い case normal // 普通 diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift index 4a412332..fcab3762 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift @@ -31,27 +31,25 @@ public struct KeyboardSetting { /// 生の`SettingKey`の値を`@State`で宣言した場合、更新の反映ができない。 /// `SettingUpdater`で包むことで、設定の更新を行いつつUIの更新も行われるようにできる。 -public struct SettingUpdater { - public var value: Wrapped.Value { +@MainActor public struct SettingUpdater { + public var value: Wrapped.Value { didSet { let newValue = value - Task.detached { @MainActor in - Wrapped.value = newValue - } + Wrapped.value = newValue } } - @MainActor public init() { + public init() { self.value = Wrapped.value } - @MainActor public mutating func reload() { + public mutating func reload() { self.value = Wrapped.value } } public protocol KeyboardSettingKey { - associatedtype Value + associatedtype Value: Sendable static var defaultValue: Value { get } static var title: LocalizedStringKey { get } static var explanation: LocalizedStringKey { get } diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/MarkedTextSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/MarkedTextSetting.swift index 50f2e335..44a83349 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/MarkedTextSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/MarkedTextSetting.swift @@ -22,7 +22,7 @@ public struct MarkedTextSettingKey: KeyboardSettingKey { } } - public enum Value: String { + public enum Value: String, Sendable { case disabled case enabled case auto diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/QwertyCustomKeyKeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/QwertyCustomKeyKeyboardSetting.swift index 0f4ae0d4..55015e20 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/QwertyCustomKeyKeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/QwertyCustomKeyKeyboardSetting.swift @@ -20,7 +20,7 @@ public struct NumberTabCustomKeysSetting: QwertyCustomKeyKeyboardSetting { public static let defaultValue: QwertyCustomKeysValue = .defaultValue public static let title: LocalizedStringKey = "数字タブのカスタムキー機能" public static let explanation: LocalizedStringKey = "数字タブの「、。!?…」部分に好きな記号や文字を割り当てて利用することができます。" - private static var key = "roman_number_custom_keys" + private static let key = "roman_number_custom_keys" @MainActor public static var value: QwertyCustomKeysValue { get { if let value = SharedStore.userDefaults.value(forKey: key), let keys = QwertyCustomKeysValue.get(value) { diff --git a/AzooKeyCore/Sources/KeyboardViews/Design.swift b/AzooKeyCore/Sources/KeyboardViews/Design.swift index bd35c878..fd865cde 100644 --- a/AzooKeyCore/Sources/KeyboardViews/Design.swift +++ b/AzooKeyCore/Sources/KeyboardViews/Design.swift @@ -255,11 +255,11 @@ public enum Design { Font.system(size: self.iconFontSize(keyViewFontSizePreference: keyViewFontSizePreference), weight: theme.textFont.weight) } - @MainActor func resultViewFontSize(userPrefrerence: CGFloat) -> CGFloat { - userPrefrerence == -1 ? 18: userPrefrerence + func resultViewFontSize(userPrefrerence: CGFloat) -> CGFloat { + userPrefrerence == -1 ? 18 : userPrefrerence } - @MainActor func resultViewFont(theme: ThemeData, userSizePrefrerence: CGFloat, fontSize: CGFloat? = nil) -> Font { + func resultViewFont(theme: ThemeData, userSizePrefrerence: CGFloat, fontSize: CGFloat? = nil) -> Font { Font.system(size: fontSize ?? resultViewFontSize(userPrefrerence: userSizePrefrerence)).weight(theme.textFont.weight) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift index 06e1ca5d..09846d80 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift @@ -92,7 +92,7 @@ struct ResizingRect: View { self[keyPath: target].wrappedValue.current.x = self[keyPath: target].wrappedValue.initial.x + dx let width = abs(bottom_right_edge.current.x - top_left_edge.current.x) let px = (top_left_edge.current.x + bottom_right_edge.current.x - initialSize.width) / 2 - if width < minimumWidth || px < -initialSize.width/2 || px > initialSize.width / 2 { + if width < minimumWidth || px < -initialSize.width / 2 || px > initialSize.width / 2 { self[keyPath: target].wrappedValue.current.x = before } else { self.size.width = width @@ -114,7 +114,7 @@ struct ResizingRect: View { self[keyPath: target].wrappedValue.current.y = self[keyPath: target].wrappedValue.initial.y + dy let height = abs(bottom_right_edge.current.y - top_left_edge.current.y) let py = (top_left_edge.current.y + bottom_right_edge.current.y - initialSize.height) / 2 - if py < -initialSize.height/2 || py > initialSize.height / 2 { + if py < -initialSize.height / 2 || py > initialSize.height / 2 { self[keyPath: target].wrappedValue.current.y = before } else { self.size.height = height diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index 6148bb0b..22e95d11 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -326,7 +326,7 @@ struct CustomKeyboardView: public struct CustardFlickKeysView: View { @State private var suggestState = FlickSuggestState() - public init(models: [KeyPosition : (model: any FlickKeyModelProtocol, width: Int, height: Int)], tabDesign: TabDependentDesign, layout: CustardInterfaceLayoutGridValue, @ViewBuilder generator: @escaping (FlickKeyView, Int, Int) -> (Content)) { + public init(models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)], tabDesign: TabDependentDesign, layout: CustardInterfaceLayoutGridValue, @ViewBuilder generator: @escaping (FlickKeyView, Int, Int) -> (Content)) { self.models = models self.tabDesign = tabDesign self.layout = layout diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift index f8b486ef..2249a5df 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift @@ -34,8 +34,9 @@ enum FlickKeyColorType { public protocol FlickKeyModelProtocol { associatedtype Extension: ApplicationSpecificKeyboardViewExtension - var longPressActions: LongpressActionType {get} - var needSuggestView: Bool {get} + @MainActor var needSuggestView: Bool {get} + + @MainActor var longPressActions: LongpressActionType {get} @MainActor func pressActions(variableStates: VariableStates) -> [ActionType] @MainActor func backGroundColorWhenPressed(theme: ThemeData) -> Color diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift index 43807992..38b764b1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift @@ -53,7 +53,7 @@ public struct FlickedKeyModel { .frame(width: size.width, height: size.height) .overlay(self.label(width: size.width, theme: theme, extension: Extension.self)) .allowsHitTesting(false) - .opacity(isHidden ? 0:1) + .opacity(isHidden ? 0 : 1) } @MainActor func label(width: CGFloat, theme: Extension.Theme, extension: Extension.Type) -> some View { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift index 1e43e0b5..0897d78a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift @@ -100,15 +100,17 @@ struct EmojiTabResultBar: V struct EmojiTabResultBarButtonStyle: ButtonStyle { private let height: CGFloat + private let userSizePrefrerence: CGFloat @Environment(Extension.Theme.self) private var theme - init(height: CGFloat) { + @MainActor init(height: CGFloat) { + self.userSizePrefrerence = Extension.SettingProvider.resultViewFontSize self.height = height } - @MainActor func makeBody(configuration: Configuration) -> some View { + func makeBody(configuration: Configuration) -> some View { configuration.label - .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: Extension.SettingProvider.resultViewFontSize, fontSize: height * 0.9)) + .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: self.userSizePrefrerence, fontSize: height * 0.9)) .frame(height: height) .foregroundColor(theme.resultTextColor.color) // 文字色は常に不透明度1で描画する .background( diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index 1458646b..c3749a12 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -110,7 +110,7 @@ struct ResultBar: View { .padding(.horizontal, 5) } // 候補を展開するボタン - Button(action: self.expand) { + Button(action: {self.expand()}) { ZStack { Color(white: 1, opacity: 0.001) .frame(width: buttonWidth) @@ -166,7 +166,7 @@ struct ResultContextMenuView: View { } if SemiStaticStates.shared.hasFullAccess { Button { - Task.detached { + Task { @MainActor in await action.notifyReportWrongConversion(candidate, index: index, variableStates: variableStates) } } label: { @@ -187,15 +187,18 @@ struct ResultContextMenuView: View { struct ResultButtonStyle: ButtonStyle { private let height: CGFloat + private let userSizePreference: Double + @Environment(Extension.Theme.self) private var theme - init(height: CGFloat) { + @MainActor init(height: CGFloat) { + self.userSizePreference = Extension.SettingProvider.resultViewFontSize self.height = height } - @MainActor func makeBody(configuration: Configuration) -> some View { + func makeBody(configuration: Configuration) -> some View { configuration.label - .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: Extension.SettingProvider.resultViewFontSize)) + .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: self.userSizePreference)) .frame(height: height) .padding(.all, 5) .foregroundColor(theme.resultTextColor.color) // 文字色は常に不透明度1で描画する diff --git a/AzooKeyCore/Sources/SwiftUIUtils/TouchDownAndTouchUpGesture.swift b/AzooKeyCore/Sources/SwiftUIUtils/TouchDownAndTouchUpGesture.swift index 52ef947f..4f8e9685 100644 --- a/AzooKeyCore/Sources/SwiftUIUtils/TouchDownAndTouchUpGesture.swift +++ b/AzooKeyCore/Sources/SwiftUIUtils/TouchDownAndTouchUpGesture.swift @@ -81,7 +81,7 @@ public struct TouchDownAndTouchUpGestureView: UIViewRepresentable { } } -fileprivate final class SingleScrollAndLongpressGestureRecognizer: UIGestureRecognizer { +private final class SingleScrollAndLongpressGestureRecognizer: UIGestureRecognizer { private var startLocation: CGPoint = .zero private var _distance: CGFloat = .zero diff --git a/Keyboard/Display/KeyboardViewController.swift b/Keyboard/Display/KeyboardViewController.swift index 43dd793f..88d7c330 100644 --- a/Keyboard/Display/KeyboardViewController.swift +++ b/Keyboard/Display/KeyboardViewController.swift @@ -270,7 +270,7 @@ final class KeyboardViewController: UIInputViewController { } @objc func openURL(_ url: URL) {} - //https://stackoverflow.com/questions/40019521/open-my-application-from-my-keyboard-extension-in-swift-3-0より + // https://stackoverflow.com/questions/40019521/open-my-application-from-my-keyboard-extension-in-swift-3-0より func openUrl(url: URL?) { let selector = #selector(openURL(_:)) var responder = (self as UIResponder).next diff --git a/MainApp/Customize/CustardInformationView.swift b/MainApp/Customize/CustardInformationView.swift index c64e3100..772f5910 100644 --- a/MainApp/Customize/CustardInformationView.swift +++ b/MainApp/Customize/CustardInformationView.swift @@ -58,7 +58,7 @@ private struct ExportedCustardData { let fileIdentifier: String } -fileprivate final class ShareURL { +private final class ShareURL { private(set) var url: URL? func setURL(_ url: URL?) { diff --git a/MainApp/Customize/EditingTenkeyCustardView.swift b/MainApp/Customize/EditingTenkeyCustardView.swift index 0ad1cb65..2b50ea97 100644 --- a/MainApp/Customize/EditingTenkeyCustardView.swift +++ b/MainApp/Customize/EditingTenkeyCustardView.swift @@ -312,7 +312,7 @@ struct EditingTenkeyCustardView: CancelableEditor { .navigationBarBackButtonHidden(true) .navigationTitle(Text("カスタムタブを作る")) .navigationBarItems( - leading: Button("キャンセル", role: .cancel, action: cancel), + leading: Button("キャンセル", role: .cancel, action: {self.cancel()}), trailing: Button("保存") { self.save() self.dismiss() diff --git a/MainApp/Customize/ManageCustardView.swift b/MainApp/Customize/ManageCustardView.swift index e9b1d2ea..dcffed02 100644 --- a/MainApp/Customize/ManageCustardView.swift +++ b/MainApp/Customize/ManageCustardView.swift @@ -182,11 +182,11 @@ struct ManageCustardView: View { } } } - .onDelete(perform: delete) + .onDelete(perform: {self.delete(at: $0)}) } } } - .onAppear(perform: loadWebCustard) + .onAppear(perform: {self.loadWebCustard()}) Section(header: Text("作る")) { Text("登録したい文字や単語を順番に書いていくだけでスクロール式のカスタムタブを作成することができます。") diff --git a/MainApp/General/CancelableEditor.swift b/MainApp/General/CancelableEditor.swift index a179b740..44684cc5 100644 --- a/MainApp/General/CancelableEditor.swift +++ b/MainApp/General/CancelableEditor.swift @@ -11,5 +11,5 @@ import SwiftUI protocol CancelableEditor: View { associatedtype EditTarget var base: EditTarget { get } - func cancel() + @MainActor func cancel() } diff --git a/MainApp/General/DraggableView.swift b/MainApp/General/DraggableView.swift index 81ddf3ea..bb89761c 100644 --- a/MainApp/General/DraggableView.swift +++ b/MainApp/General/DraggableView.swift @@ -49,7 +49,7 @@ struct DraggableView some View { - let shadowColor = focused ? color:.clear - let shadowRadius: CGFloat = focused ? 0.5:.zero + let shadowColor = focused ? color : .clear + let shadowRadius: CGFloat = focused ? 0.5 : .zero return content .shadow(color: shadowColor, radius: shadowRadius, x: 1) .shadow(color: shadowColor, radius: shadowRadius, x: -1) diff --git a/MainApp/LOUDSLogic/LOUDSBuilder.swift b/MainApp/LOUDSLogic/LOUDSBuilder.swift index 732cb227..77f7b8b6 100644 --- a/MainApp/LOUDSLogic/LOUDSBuilder.swift +++ b/MainApp/LOUDSLogic/LOUDSBuilder.swift @@ -49,7 +49,7 @@ struct LOUDSBuilder { for i in 0...value.quotient { var value: UInt64 = 0 for j in 0..] = (0...count).map { let start = $0 * txtFileSplit let _end = ($0 + 1) * txtFileSplit - let end = data.count < _end ? data.count:_end + let end = data.count < _end ? data.count : _end return start.. Bool { - return word.contains(templateRegex) + word.contains(templateRegex) } private func templateIndex(name: String) -> Int? { - return variables.templates.firstIndex(where: {$0.name == name}) + variables.templates.firstIndex(where: {$0.name == name}) } // こちらは「今まで同名のテンプレートがなかった」場合にのみテンプレートを追加する @@ -173,7 +173,7 @@ private struct UserDictionaryDataEditor: CancelableEditor { } @State private var wordEditMode: Bool = false - @State private var pickerTemplateName: String? = nil + @State private var pickerTemplateName: String? @State private var shareThisWord = false @State private var showExplanation = false @State private var sending = false @@ -250,8 +250,8 @@ private struct UserDictionaryDataEditor: CancelableEditor { @ViewBuilder private func templateEditor(index: Int, selectedTemplate: (name: String, index: Int)) -> some View { if variables.templates[index].name == selectedTemplate.name { - TemplateEditingView($variables.templates[index], validationInfo: variables.templates.map{$0.name}, options: .init(nameEdit: false, appearance: .embed { template in - if template.name == selectedTemplate.name && index < variables.templates.endIndex { + TemplateEditingView($variables.templates[index], validationInfo: variables.templates.map {$0.name}, options: .init(nameEdit: false, appearance: .embed { template in + if template.name == selectedTemplate.name && index < variables.templates.endIndex { variables.templates[index] = template } else { debug("templateEditor: Unknown situation:", template, selectedTemplate, variables.templates[index]) @@ -284,7 +284,7 @@ private struct UserDictionaryDataEditor: CancelableEditor { } label: { Image(systemName: "rectangle.and.pencil.and.ellipsis") } - } else { + } else { wordField } Divider() @@ -389,7 +389,6 @@ private struct UserDictionaryDataEditor: CancelableEditor { } } else { self.save() - let data = self.item.makeStableData() variables.mode = .list MainAppFeedback.success() } diff --git a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift index 37191187..ccb3b89f 100644 --- a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift +++ b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift @@ -208,7 +208,9 @@ struct FlickCustomKeySettingView: Vie NavigationLink("長押しアクションを編集する", destination: CodableLongpressActionDataEditor($setting.value[keyPath: selectedPosition.bindedKeyPath].longpressActions, availableCustards: CustardManager.load().availableCustards)) .foregroundColor(.accentColor) } - Button("リセット", action: reload) + Button("リセット") { + self.reload() + } .foregroundColor(.red) } else { Text("このキーは編集できません") @@ -219,7 +221,7 @@ struct FlickCustomKeySettingView: Vie } } - @ViewBuilder private func tabSetter(keyPath: WritableKeyPath) -> some View { + @MainActor @ViewBuilder private func tabSetter(keyPath: WritableKeyPath) -> some View { Text("このキーにはタブ移動以外のアクションが設定されています。現在のアクションを消去して移動するタブを設定するには「タブを設定する」を押してください") Button("タブを設定する") { setting.value[keyPath: keyPath].actions = [.moveTab(.system(.user_japanese))] @@ -227,7 +229,7 @@ struct FlickCustomKeySettingView: Vie .foregroundColor(.accentColor) } - private func isPossiblePosition(_ position: FlickKeyPosition) -> Bool { + @MainActor private func isPossiblePosition(_ position: FlickKeyPosition) -> Bool { setting.value.identifier.ablePosition.contains(position) } @@ -248,7 +250,7 @@ struct FlickCustomKeySettingView: Vie return nil } - private func reload() { + @MainActor private func reload() { if self.isPossiblePosition(selectedPosition) { setting.value[keyPath: selectedPosition.keyPath] = setting.value.identifier.defaultSetting[keyPath: selectedPosition.keyPath] } @@ -259,7 +261,7 @@ struct FlickCustomKeySettingView: Vie case tab } - private var mainEditor: MainEditorSpecifier { + @MainActor private var mainEditor: MainEditorSpecifier { switch setting.value.identifier { case .kanaSymbols, .kogana: return .input diff --git a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift index f9aa7bec..a26a6ac8 100644 --- a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift +++ b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift @@ -204,7 +204,9 @@ struct QwertyCustomKeysSettingView: bottomSheetShown = false editState.toggle(.drag) } - Button("キーを追加する", action: self.addPressKey) + Button("キーを追加する") { + self.addPressKey() + } Button("このキーに長押しキーを追加する") { self.addLongpressKey(sIndex: selection.selectIndex) } @@ -253,7 +255,9 @@ struct QwertyCustomKeysSettingView: } .foregroundColor(.red) } else { - Button("キーを追加する", action: self.addPressKey) + Button("キーを追加する") { + self.addPressKey() + } } } } diff --git a/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift b/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift index 938cb2c7..667c78e8 100644 --- a/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift +++ b/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift @@ -24,7 +24,7 @@ struct FlickSensitivitySettingView: View { } } - private var explanation: LocalizedStringKey { + @MainActor private var explanation: LocalizedStringKey { switch setting.value { case 0.33 ... 0.5: return "とても反応しにくい" case 0.5 ... 0.8: return "反応しにくい" diff --git a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift index 2bcbedf7..c469b9b1 100644 --- a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift +++ b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift @@ -197,8 +197,6 @@ struct OpenSourceSoftwaresLicenseView: View { Spacer() Text("azooKeyを使ってくれてありがとう!") } - .animation(.interpolatingSpring(stiffness: 30, damping: 5)) - } } .multilineTextAlignment(.leading) diff --git a/MainApp/Setting/Template/TemplateListView.swift b/MainApp/Setting/Template/TemplateListView.swift index ac5f2bfe..20dfe56c 100644 --- a/MainApp/Setting/Template/TemplateListView.swift +++ b/MainApp/Setting/Template/TemplateListView.swift @@ -58,7 +58,7 @@ struct TemplateListView: View { } } } - .onDelete(perform: delete) + .onDelete(perform: {self.delete(at: $0)}) } }.navigationBarTitle(Text("テンプレートの管理"), displayMode: .inline) .navigationBarItems(trailing: addButton) From ca3caaaea7f0e50390209ea3a1971c9e71fa29ab Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 4 Aug 2023 15:29:57 +0900 Subject: [PATCH 002/124] Fix more warnings in concurrency --- Keyboard/Display/KeyboardActionManager.swift | 46 +++++++++---------- MainApp/ContentView.swift | 2 +- MainApp/Customize/CustomizeTabView.swift | 2 +- .../Customize/CustomizeTabWalkthrough.swift | 5 +- MainApp/Customize/ManageCustardView.swift | 24 ++++------ MainApp/DataUpdateView/DataUpdateView.swift | 24 ++++------ .../ContainerInternalSetting.swift | 3 +- MainApp/LOUDSLogic/LOUDSBuilder.swift | 16 +++---- MainApp/MainApp.swift | 2 + .../AdditionalDictManageView.swift | 17 +++---- .../AzooKeyUserDictionary.swift | 3 +- MainApp/Setting/SettingTab.swift | 2 +- MainApp/Setting/ShareWordView.swift | 2 +- MainApp/Theme/ThemeEditView.swift | 2 +- MainApp/Utils/RequestReviewManager.swift | 2 - 15 files changed, 65 insertions(+), 87 deletions(-) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index eac2376d..f88a2bb1 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -20,17 +20,17 @@ import SwiftUtils private unowned var delegate: KeyboardViewController! // 即時変数 - private var timers: [(type: LongpressActionType, timer: Timer)] = [] + private var tasks: [(type: LongpressActionType, task: Task)] = [] private var tempTextData: (left: String, center: String, right: String)? // キーボードを閉じる際に呼び出す // inputManagerはキーボードを閉じる際にある種の操作を行う func closeKeyboard() { self.inputManager.closeKeyboard() - for (_, timer) in self.timers { - timer.invalidate() + for (_, task) in self.tasks { + task.cancel() } - self.timers = [] + self.tasks = [] self.tempTextData = nil } @@ -311,37 +311,37 @@ import SwiftUtils /// - Parameters: /// - action: 長押しで起こる動作のタイプ。 override func reserveLongPressAction(_ action: LongpressActionType, variableStates: VariableStates) { - if timers.contains(where: {$0.type == action}) { + if tasks.contains(where: {$0.type == action}) { return } - let startTime = Date() - - let startTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: {[weak self] (timer) in - let span: TimeInterval = timer.fireDate.timeIntervalSince(startTime) - if span > 0.4 { + let startTask = Task { + try await Task.sleep(nanoseconds: 0_400_000_000) + action.start.first?.feedback(variableStates: variableStates, extension: AzooKeyKeyboardViewExtension.self) + self.registerActions(action.start, variableStates: variableStates) + } + self.tasks.append((type: action, task: startTask)) + + let repeatTask = Task { + try await Task.sleep(nanoseconds: 0_400_000_000) + while !Task.isCancelled { action.repeat.first?.feedback(variableStates: variableStates, extension: AzooKeyKeyboardViewExtension.self) - self?.registerActions(action.repeat, variableStates: variableStates) + self.registerActions(action.repeat, variableStates: variableStates) + try await Task.sleep(nanoseconds: 0_100_000_000) } - }) - self.timers.append((type: action, timer: startTimer)) - - let repeatTimer = Timer.scheduledTimer(withTimeInterval: 0.4, repeats: false, block: {[weak self] _ in - action.start.first?.feedback(variableStates: variableStates, extension: AzooKeyKeyboardViewExtension.self) - self?.registerActions(action.start, variableStates: variableStates) - }) - self.timers.append((type: action, timer: repeatTimer)) + } + self.tasks.append((type: action, task: repeatTask)) } /// 長押しを終了する関数。継続的な動作、例えば連続的な文字削除を行っていたタイマーを停止する。 /// - Parameters: /// - action: どの動作を終了するか判定するために用いる。 override func registerLongPressActionEnd(_ action: LongpressActionType) { - timers = timers.compactMap {timer in - if timer.type == action { - timer.timer.invalidate() + tasks = tasks.compactMap {task in + if task.type == action { + task.task.cancel() return nil } - return timer + return task } } diff --git a/MainApp/ContentView.swift b/MainApp/ContentView.swift index a42cdb51..104338ef 100644 --- a/MainApp/ContentView.swift +++ b/MainApp/ContentView.swift @@ -49,7 +49,7 @@ struct ContentView: View { }) .onChange(of: selection) {value in if value == .customize { - if ContainerInternalSetting.shared.walkthroughState.shouldDisplay(identifier: .extensions) { + if appStates.internalSettingManager.walkthroughState.shouldDisplay(identifier: .extensions) { self.showWalkthrough = true } } diff --git a/MainApp/Customize/CustomizeTabView.swift b/MainApp/Customize/CustomizeTabView.swift index acd962f7..096d3d0b 100644 --- a/MainApp/Customize/CustomizeTabView.swift +++ b/MainApp/Customize/CustomizeTabView.swift @@ -50,7 +50,7 @@ struct CustomizeTabView: View { } .navigationBarTitle(Text("拡張"), displayMode: .large) .onAppear { - if RequestReviewManager.shared.shouldTryRequestReview, RequestReviewManager.shared.shouldRequestReview() { + if appStates.requestReviewManager.shouldTryRequestReview, appStates.requestReviewManager.shouldRequestReview() { if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { SKStoreReviewController.requestReview(in: scene) } diff --git a/MainApp/Customize/CustomizeTabWalkthrough.swift b/MainApp/Customize/CustomizeTabWalkthrough.swift index e114bb11..cb1527f7 100644 --- a/MainApp/Customize/CustomizeTabWalkthrough.swift +++ b/MainApp/Customize/CustomizeTabWalkthrough.swift @@ -18,6 +18,7 @@ private struct Item: Identifiable { struct CustomizeTabWalkthroughView: View { @Binding private var isShowing: Bool + @EnvironmentObject private var appStates: MainAppStates init(isShowing: Binding) { self._isShowing = isShowing @@ -43,7 +44,7 @@ struct CustomizeTabWalkthroughView: View { ] var body: some View { - if ContainerInternalSetting.shared.walkthroughState.shouldDisplay(identifier: .extensions) { + if appStates.internalSettingManager.walkthroughState.shouldDisplay(identifier: .extensions) { GeometryReader {geometry in ScrollView { VStack(spacing: 20) { @@ -92,7 +93,7 @@ struct CustomizeTabWalkthroughView: View { .onChange(of: isShowing) {value in // コードの明確化のためにfalseと比較している if value == false { - ContainerInternalSetting.shared.update(\.walkthroughState) {value in + appStates.internalSettingManager.update(\.walkthroughState) {value in value.done(identifier: .extensions) } } diff --git a/MainApp/Customize/ManageCustardView.swift b/MainApp/Customize/ManageCustardView.swift index dcffed02..29297246 100644 --- a/MainApp/Customize/ManageCustardView.swift +++ b/MainApp/Customize/ManageCustardView.swift @@ -356,23 +356,15 @@ struct ManageCustardView: View { return } let request = URLRequest(url: url) - - URLSession.shared.dataTask(with: request) { data, _, error in - if let data { - let decoder = JSONDecoder() - guard let decodedResponse = try? decoder.decode(WebCustardList.self, from: data) else { - debug("Failed to load https://azooKey.netlify.com/static/custard/all") - return - } - - DispatchQueue.main.async { - self.webCustards = decodedResponse - } - } else { - debug("Fetch failed", error) + Task { + let result = try await URLSession.shared.data(from: url).0 + let decoder = JSONDecoder() + guard let decodedResponse = try? decoder.decode(WebCustardList.self, from: result) else { + debug("Failed to load https://azooKey.netlify.com/static/custard/all") + return } - - }.resume() + self.webCustards = decodedResponse + } } } diff --git a/MainApp/DataUpdateView/DataUpdateView.swift b/MainApp/DataUpdateView/DataUpdateView.swift index 5122e6a8..775ba59c 100644 --- a/MainApp/DataUpdateView/DataUpdateView.swift +++ b/MainApp/DataUpdateView/DataUpdateView.swift @@ -9,6 +9,7 @@ import AzooKeyUtils import KeyboardViews import SwiftUI +import func SwiftUtils.debug struct DataUpdateView: View { @@ -44,23 +45,14 @@ struct DataUpdateView: View { } } else { ProgressView("データの更新処理中です") - .onAppear { - let dispatchGroup = DispatchGroup() - let dispatchQueue = DispatchQueue(label: "queue", attributes: .concurrent) - - // 非同期処理を実行 - dispatchGroup.enter() - dispatchQueue.async(group: dispatchGroup) { + .task { + do { process() - } - dispatchGroup.leave() - - // 全ての非同期処理完了後にメインスレッドで処理 - // 更新処理が短くても何が起こったかわかりやすいよう、1秒間余分に待つ - dispatchGroup.notify(queue: .main) { - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { - done = true - } + // 更新処理が短くても何が起こったかわかりやすいよう、1秒間余分に待つ + try await Task.sleep(nanoseconds: 1_000_000_000) + self.done = true + } catch { + debug(error) } } } diff --git a/MainApp/InternalSetting/ContainerInternalSetting.swift b/MainApp/InternalSetting/ContainerInternalSetting.swift index 5efacfea..96a745a2 100644 --- a/MainApp/InternalSetting/ContainerInternalSetting.swift +++ b/MainApp/InternalSetting/ContainerInternalSetting.swift @@ -10,8 +10,7 @@ import Foundation import SwiftUtils struct ContainerInternalSetting: UserDefaultsManager { - static var shared = Self() - private init() { + init() { self.walkthroughState = Self.load(key: .walkthrough_state, userDefaults: self.userDefaults) } var userDefaults: UserDefaults = UserDefaults.standard diff --git a/MainApp/LOUDSLogic/LOUDSBuilder.swift b/MainApp/LOUDSLogic/LOUDSBuilder.swift index 77f7b8b6..c98c3fd3 100644 --- a/MainApp/LOUDSLogic/LOUDSBuilder.swift +++ b/MainApp/LOUDSLogic/LOUDSBuilder.swift @@ -14,30 +14,26 @@ import KeyboardViews import SwiftUtils extension LOUDSBuilder { - static var char2UInt8: [Character: UInt8] = [:] - - static func loadCharID() { + static func loadCharID() -> [Character: UInt8] { do { let chidURL = Bundle.main.bundleURL.appendingPathComponent("charID.chid", isDirectory: false) let string = try String(contentsOf: chidURL, encoding: .utf8) - Self.char2UInt8 = [Character: UInt8].init(uniqueKeysWithValues: string.enumerated().map {($0.element, UInt8($0.offset))}) + return [Character: UInt8].init(uniqueKeysWithValues: string.enumerated().map {($0.element, UInt8($0.offset))}) } catch { debug("ファイルが存在しません: \(error)") + return [:] } } - - static func getID(from char: Character) -> UInt8? { - Self.char2UInt8[char] - } } struct LOUDSBuilder { let txtFileSplit: Int let templateData: [TemplateData] + let char2UInt8: [Character: UInt8] init(txtFileSplit: Int) { self.txtFileSplit = txtFileSplit - Self.loadCharID() + self.char2UInt8 = Self.loadCharID() self.templateData = TemplateData.load() } @@ -258,7 +254,7 @@ struct LOUDSBuilder { } do { - let uint8s = nodes2Characters.map {Self.getID(from: $0) ?? 0} // エラー回避。0は"\0"に対応し、呼ばれることはない。 + let uint8s = nodes2Characters.map {self.char2UInt8[$0] ?? 0} // エラー回避。0は"\0"に対応し、呼ばれることはない。 let binary = Data(bytes: uint8s, count: uint8s.count) try binary.write(to: loudsCharsFileURL) } catch { diff --git a/MainApp/MainApp.swift b/MainApp/MainApp.swift index f80265d4..dddb03e4 100644 --- a/MainApp/MainApp.swift +++ b/MainApp/MainApp.swift @@ -16,6 +16,8 @@ final class MainAppStates: ObservableObject { @Published var japaneseLayout: LanguageLayout = .flick @Published var englishLayout: LanguageLayout = .flick @Published var custardManager: CustardManager + @Published var internalSettingManager = ContainerInternalSetting() + @Published var requestReviewManager = RequestReviewManager() @MainActor init() { let keyboardActivation = SharedStore.checkKeyboardActivation() diff --git a/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift b/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift index 725da684..44274c78 100644 --- a/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift +++ b/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift @@ -80,23 +80,19 @@ struct AdditionalDictBlockManager: OnOffSettingSet { } final class AdditionalDictManager: ObservableObject { - @Published var systemDict: AdditionalSystemDictManager { + @MainActor @Published var systemDict: AdditionalSystemDictManager { didSet { - Task.detached { - await self.userDictUpdate() - } + self.userDictUpdate() } } - @Published var blockTargets: AdditionalDictBlockManager { + @MainActor @Published var blockTargets: AdditionalDictBlockManager { didSet { - Task.detached { - await self.userDictUpdate() - } + self.userDictUpdate() } } - init() { + @MainActor init() { let systemDictList = UserDefaults.standard.array(forKey: "additional_dict") as? [String] self.systemDict = .init(dataList: systemDictList ?? []) @@ -163,13 +159,14 @@ struct AdditionalDictManageViewMain: View { } struct AdditionalDictManageView: View { + @EnvironmentObject private var appStates: MainAppStates var body: some View { Form { AdditionalDictManageViewMain() } .navigationBarTitle(Text("絵文字と顔文字"), displayMode: .inline) .onDisappear { - RequestReviewManager.shared.shouldTryRequestReview = true + appStates.requestReviewManager.shouldTryRequestReview = true } } } diff --git a/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift b/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift index 3b5707c8..7e78baf9 100644 --- a/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift +++ b/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift @@ -44,6 +44,7 @@ private final class UserDictManagerVariables: ObservableObject { struct AzooKeyUserDictionaryView: View { @ObservedObject private var variables: UserDictManagerVariables = UserDictManagerVariables() + @EnvironmentObject private var appStates: MainAppStates var body: some View { Group { @@ -57,7 +58,7 @@ struct AzooKeyUserDictionaryView: View { } } .onDisappear { - RequestReviewManager.shared.shouldTryRequestReview = true + appStates.requestReviewManager.shouldTryRequestReview = true } } } diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index c54f586d..08559f78 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -137,7 +137,7 @@ struct SettingTabView: View { } .navigationBarTitle(Text("設定"), displayMode: .large) .onAppear { - if RequestReviewManager.shared.shouldTryRequestReview, RequestReviewManager.shared.shouldRequestReview() { + if appStates.requestReviewManager.shouldTryRequestReview, appStates.requestReviewManager.shouldRequestReview() { if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { SKStoreReviewController.requestReview(in: scene) } diff --git a/MainApp/Setting/ShareWordView.swift b/MainApp/Setting/ShareWordView.swift index eb404dea..e57c2828 100644 --- a/MainApp/Setting/ShareWordView.swift +++ b/MainApp/Setting/ShareWordView.swift @@ -41,7 +41,7 @@ struct ShareWordView: View { } Section(footer: Text("この単語をazooKeyの本体辞書に追加することを申請します。\n個人情報を含む単語は申請しないでください。")) { Button("申請する") { - Task.detached { + Task { self.sending = true _ = await SharedStore.sendSharedWord(word: word, ruby: ruby.toKatakana(), options: []) self.sending = false diff --git a/MainApp/Theme/ThemeEditView.swift b/MainApp/Theme/ThemeEditView.swift index 44809d47..db5006e1 100644 --- a/MainApp/Theme/ThemeEditView.swift +++ b/MainApp/Theme/ThemeEditView.swift @@ -255,7 +255,7 @@ struct ThemeEditView: CancelableEditor { case .themeShareView: ThemeShareView(theme: self.theme, shareImage: shareImage) { self.dismiss() - RequestReviewManager.shared.shouldTryRequestReview = true + appStates.requestReviewManager.shouldTryRequestReview = true } .navigationBarTitle(Text("完了"), displayMode: .inline) .navigationBarItems(leading: EmptyView(), trailing: EmptyView()) diff --git a/MainApp/Utils/RequestReviewManager.swift b/MainApp/Utils/RequestReviewManager.swift index 8734cfb3..00c1e6bb 100644 --- a/MainApp/Utils/RequestReviewManager.swift +++ b/MainApp/Utils/RequestReviewManager.swift @@ -9,8 +9,6 @@ import Foundation struct RequestReviewManager { - static var shared = RequestReviewManager() - private init() {} var shouldTryRequestReview: Bool = false mutating func shouldRequestReview() -> Bool { From 641b9b8d7f40b516b44b29534c2102ebce146d23 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 4 Aug 2023 16:04:40 +0900 Subject: [PATCH 003/124] =?UTF-8?q?=E5=86=8D=E5=A4=89=E6=8F=9B=E6=99=82?= =?UTF-8?q?=E3=81=AE=E4=BA=88=E6=B8=AC=E5=A4=89=E6=8F=9B=E3=82=92=E3=82=AA?= =?UTF-8?q?=E3=83=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard/Display/InputManager.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 9e04544a..753079ab 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -747,11 +747,14 @@ import UIKit let requireJapanesePrediction: Bool let requireEnglishPrediction: Bool - switch inputData.input.last?.inputStyle ?? .direct { - case .direct: + switch (isSelected, inputData.input.last?.inputStyle ?? .direct) { + case (true, _): + requireJapanesePrediction = false + requireEnglishPrediction = false + case (false, .direct): requireJapanesePrediction = true requireEnglishPrediction = true - case .roman2kana: + case (false, .roman2kana): requireJapanesePrediction = keyboardLanguage == .ja_JP requireEnglishPrediction = keyboardLanguage == .en_US } From c26507e5063ec47c0372c932e9035499a2543502 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 4 Aug 2023 18:48:54 +0900 Subject: [PATCH 004/124] =?UTF-8?q?UserDefaults=E3=81=AE"AppleKeyboards"?= =?UTF-8?q?=E3=81=AF=E4=BB=8A=E5=BE=8C=E4=BD=BF=E3=81=88=E3=81=AA=E3=81=8F?= =?UTF-8?q?=E3=81=AA=E3=82=8B=E3=81=AE=E3=81=A7=E3=80=81UITextInputMode?= =?UTF-8?q?=E3=81=A7=E4=BB=A3=E6=9B=BF=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EnableAzooKeyView/EnableAzooKeyView.swift | 40 ++++++++++++++----- MainApp/MainApp.swift | 1 + MainApp/Utils/checkKeyboardActivation.swift | 10 ++--- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift index 23c5e51e..8b001329 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift @@ -9,6 +9,7 @@ import AzooKeyUtils import SwiftUI import SwiftUIUtils +import func SwiftUtils.debug private enum EnableAzooKeyViewStep { case menu @@ -141,12 +142,13 @@ struct EnableAzooKeyView: View { } .onReceive(NotificationCenter.default.publisher(for: UIApplication.keyboardDidShowNotification)) {_ in // キーボードが開いた時 - // 参考:https://stackoverflow.com/questions/26153336/how-do-i-find-out-the-current-keyboard-used-on-ios8 - let currentKeyboardIdentifier = NSArray(array: UITextInputMode.activeInputModes) - .filtered(using: NSPredicate(format: "isDisplayed = YES")) - .first - .flatMap {($0 as? UITextInputMode)?.value(forKey: "identifier") as? String} - if currentKeyboardIdentifier == SharedStore.bundleName { + if checkActiveKeyboardIsAzooKey() { + showDoneMessage = true + } + } + .onReceive(NotificationCenter.default.publisher(for: UITextInputMode.currentInputModeDidChangeNotification)) {_ in + // アクティブなキーボードが変化したとき + if checkActiveKeyboardIsAzooKey() { showDoneMessage = true } } @@ -157,11 +159,29 @@ struct EnableAzooKeyView: View { } .animation(.interactiveSpring(), value: step) .animation(.spring(), value: showDoneMessage) - .onEnterForeground { _ in - if SharedStore.checkKeyboardActivation() { - self.step = .setting - appStates.isKeyboardActivated = true + .task { + // 0.2秒に一度チェックを挟んでkeyboardの状態をチェックする + while !Task.isCancelled && !appStates.isKeyboardActivated { + if SharedStore.checkKeyboardActivation() { + self.step = .setting + appStates.isKeyboardActivated = true + } + do { + try await Task.sleep(nanoseconds: 0_200_000_000) + } catch { + debug(error) + } } } } + + private func checkActiveKeyboardIsAzooKey() -> Bool { + // キーボードが開いた時 + // 参考:https://stackoverflow.com/questions/26153336/how-do-i-find-out-the-current-keyboard-used-on-ios8 + let currentKeyboardIdentifier = NSArray(array: UITextInputMode.activeInputModes) + .filtered(using: NSPredicate(format: "isDisplayed = YES")) + .first + .flatMap {($0 as? UITextInputMode)?.value(forKey: "identifier") as? String} + return currentKeyboardIdentifier == SharedStore.bundleName + } } diff --git a/MainApp/MainApp.swift b/MainApp/MainApp.swift index dddb03e4..16c8d8f9 100644 --- a/MainApp/MainApp.swift +++ b/MainApp/MainApp.swift @@ -11,6 +11,7 @@ import KeyboardViews import SwiftUI final class MainAppStates: ObservableObject { + /// キーボードが有効化(キーボードリストに追加)されているかどうかを示す @Published var isKeyboardActivated: Bool @Published var requireFirstOpenView: Bool @Published var japaneseLayout: LanguageLayout = .flick diff --git a/MainApp/Utils/checkKeyboardActivation.swift b/MainApp/Utils/checkKeyboardActivation.swift index 2100f0c8..b0420ea8 100644 --- a/MainApp/Utils/checkKeyboardActivation.swift +++ b/MainApp/Utils/checkKeyboardActivation.swift @@ -7,14 +7,12 @@ // import Foundation +import class UIKit.UITextInputMode import enum AzooKeyUtils.SharedStore extension SharedStore { - static func checkKeyboardActivation() -> Bool { - let bundleName = SharedStore.bundleName - guard let keyboards = UserDefaults.standard.dictionaryRepresentation()["AppleKeyboards"] as? [String] else { - return true - } - return keyboards.contains(bundleName) + @MainActor static func checkKeyboardActivation() -> Bool { + let keyboards = UITextInputMode.activeInputModes.compactMap {$0.value(forKey: "identifier") as? String} + return keyboards.contains(SharedStore.bundleName) } } From 609483ccab3c52ab8545cb537eceb25e2f5a035d Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 4 Aug 2023 19:31:52 +0900 Subject: [PATCH 005/124] =?UTF-8?q?=20*=20foregroundColor=E3=81=8CiOS17?= =?UTF-8?q?=E4=BB=A5=E9=99=8Ddeprecated=E3=81=AA=E3=81=AE=E3=81=A7?= =?UTF-8?q?=E3=81=9D=E3=81=A1=E3=82=89=E3=81=AB=E7=A7=BB=E8=A1=8C=20*=20Az?= =?UTF-8?q?ooKeyCore=E3=81=AEminimum=20os=20version=E3=82=92=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=20*=20Color=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AzooKeyCore/Package.swift | 2 +- .../Sources/KeyboardViews/AzooKeyIcon.swift | 20 +++++++++---------- .../View/Components/KeyLabel.swift | 12 +++++------ .../View/Components/MessageView.swift | 4 ++-- .../View/Components/ResizingRect.swift | 12 +++++------ .../View/Components/TemporalMessageView.swift | 5 ++--- .../View/CustomKeybaord/CustomKeyboard.swift | 2 -- .../FlickKeyboard/FlickKeyboardView.swift | 1 - .../View/KeyboardBar/EmojiTabResultBar.swift | 3 +-- .../View/KeyboardBar/KeyboardBarView.swift | 3 +-- .../View/KeyboardBar/MoveCursorBar.swift | 10 +++++----- .../View/KeyboardBar/ResultBar.swift | 2 +- .../KeyboardViews/View/KeyboardView.swift | 1 - .../KeyView/QwertyVariationsView.swift | 2 +- .../SpecialTabs/ClipboardHistoryTab.swift | 5 ++--- .../View/SpecialTabs/EmojiTab.swift | 2 +- .../Sources/SwiftUIUtils/Availability.swift | 1 - AzooKeyCore/Sources/SwiftUIUtils/Color.swift | 14 +++++++++++++ .../SwiftUIUtils/IntegerTextField.swift | 1 - .../SwiftUIUtils/StringInterpolation.swift | 2 ++ MainApp/ContentView.swift | 2 +- .../Customize/CodableActionDataEditor.swift | 2 +- .../Customize/CustardInformationView.swift | 4 ++-- .../Customize/CustardInterfaceKeyEditor.swift | 12 +++++------ MainApp/Customize/CustomizeTabView.swift | 4 ++-- .../Customize/CustomizeTabWalkthrough.swift | 6 +++--- MainApp/Customize/EditingTabBarView.swift | 2 +- .../Customize/EditingTenkeyCustardView.swift | 8 ++++---- MainApp/Customize/ManageCustardView.swift | 18 ++++++++--------- .../EnableAzooKeyViewComponent.swift | 4 ++-- MainApp/General/DisclosuringList.swift | 2 +- MainApp/General/DraggableView.swift | 2 +- MainApp/General/HeaderLogoView.swift | 2 +- MainApp/General/PasteButton.swift | 2 +- .../AzooKeyUserDictionary.swift | 6 +++--- .../BooleanSetting/BoolSettingView.swift | 2 +- .../FlickCustomKeySettingView.swift | 12 +++++------ .../CustomKeysSettingView.swift | 4 ++-- .../QwertyCustomKeysItemView.swift | 6 +++--- .../MemoryResetSetting.swift | 2 +- MainApp/Setting/SettingTab.swift | 4 ++-- .../Template/TemplateEditingView.swift | 2 +- .../Setting/Template/TemplateListView.swift | 2 +- MainApp/Theme/ThemeEditView.swift | 4 ++-- MainApp/Theme/ThemeShareView.swift | 4 ++-- MainApp/Theme/ThemeTab.swift | 6 +++--- MainApp/Tips/TipsView.swift | 2 +- 47 files changed, 118 insertions(+), 112 deletions(-) diff --git a/AzooKeyCore/Package.swift b/AzooKeyCore/Package.swift index 40a674a1..db36dd89 100644 --- a/AzooKeyCore/Package.swift +++ b/AzooKeyCore/Package.swift @@ -14,7 +14,7 @@ let swiftSettings: [SwiftSetting] = [ ] let package = Package( name: "AzooKeyCore", - platforms: [.iOS(.v14), .macOS(.v11)], + platforms: [.iOS(.v15), .macOS(.v12)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( diff --git a/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift b/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift index ee9052b2..8727933e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift +++ b/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift @@ -60,33 +60,33 @@ public struct AzooKeyIcon: View { switch looks { case .normal: Text("1") - .foregroundColor(foregroundColor) + .foregroundStyle(foregroundColor) case .king: ZStack(alignment: .center) { Text("α") - .foregroundColor(foregroundColor) + .foregroundStyle(foregroundColor) Text("\u{EA00}") - .foregroundColor(.orange) + .foregroundStyle(.orange) } case .strawHat: ZStack(alignment: .center) { Text("β") - .foregroundColor(foregroundColor) + .foregroundStyle(foregroundColor) Text("\u{EA10}") - .foregroundColor(SwiftUI.Color(red: 243 / 255, green: 210 / 255, blue: 82 / 255)) + .foregroundStyle(SwiftUI.Color(red: 243 / 255, green: 210 / 255, blue: 82 / 255)) Text("\u{EA11}") - .foregroundColor(.white) + .foregroundStyle(.white) } case .santaClaus: ZStack(alignment: .center) { Text("γ") - .foregroundColor(foregroundColor) + .foregroundStyle(foregroundColor) Text("\u{EA20}") - .foregroundColor(.black) + .foregroundStyle(.black) Text("\u{EA21}") - .foregroundColor(.white) + .foregroundStyle(.white) Text("\u{EA22}") - .foregroundColor(.red) + .foregroundStyle(.red) } } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift index 437979fe..e048a5c1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift @@ -48,7 +48,7 @@ public struct KeyLabel: Vie let font = Design.fonts.keyLabelFont(text: text, width: width, fontSize: self.textSize, userDecidedSize: keyViewFontSize, layout: variableStates.keyboardLayout, theme: theme) Text(text) .font(font) - .foregroundColor(mainKeyColor) + .foregroundStyle(mainKeyColor) .allowsHitTesting(false) case let .symbols(symbols): @@ -62,13 +62,13 @@ public struct KeyLabel: Vie Text(subText) .font(subFont) } - .foregroundColor(mainKeyColor) + .foregroundStyle(mainKeyColor) .allowsHitTesting(false) case let .image(imageName): Image(systemName: imageName) .font(Design.fonts.iconImageFont(keyViewFontSizePreference: Extension.SettingProvider.keyViewFontSize, theme: theme)) - .foregroundColor(mainKeyColor) + .foregroundStyle(mainKeyColor) .allowsHitTesting(false) case let .customImage(imageName): @@ -79,7 +79,7 @@ public struct KeyLabel: Vie case .changeKeyboard: (self.action.makeChangeKeyboardButtonView() as ChangeKeyboardButtonView) - .foregroundColor(mainKeyColor) + .foregroundStyle(mainKeyColor) case let .selectable(primary, secondery): let font = Design.fonts.keyLabelFont(text: primary + primary, width: width, fontSize: self.textSize, userDecidedSize: keyViewFontSize, layout: variableStates.keyboardLayout, theme: theme) @@ -89,10 +89,10 @@ public struct KeyLabel: Vie Text(primary) .font(font) .padding(.trailing, -5) - .foregroundColor(mainKeyColor) + .foregroundStyle(mainKeyColor) Text(secondery) .font(subFont.bold()) - .foregroundColor(.gray) + .foregroundStyle(.gray) .padding(.leading, -5) .offset(y: -1) }.allowsHitTesting(false) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift index 10a6eb19..58aec81e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift @@ -89,11 +89,11 @@ struct MessageView: View { Text(data.title) .font(.title.bold()) .padding(.top) - .foregroundColor(.black) + .foregroundStyle(.black) ScrollView { Text(data.description) .padding(.horizontal) - .foregroundColor(.black) + .foregroundStyle(.black) .lineLimit(nil) .fixedSize(horizontal: false, vertical: true) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift index 09846d80..a73378b5 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift @@ -233,7 +233,7 @@ struct ResizingRect: View { .frame(width: r, height: r) .overlay( Image(systemName: "arrow.up.and.down.and.arrow.left.and.right") - .foregroundColor(.white) + .foregroundStyle(.white) .font(Font.system(size: r * 0.5)) ) .gesture(moveGesture) @@ -254,7 +254,7 @@ struct ResizingRect: View { .frame(width: r, height: r) .overlay( Image(systemName: "arrow.triangle.2.circlepath") - .foregroundColor(.white) + .foregroundStyle(.white) .font(Font.system(size: r * 0.5)) ) } @@ -270,7 +270,7 @@ struct ResizingRect: View { .frame(width: r, height: r) .overlay( Image(systemName: "checkmark") - .foregroundColor(.white) + .foregroundStyle(.white) .font(Font.system(size: r * 0.5)) ) } @@ -333,7 +333,7 @@ struct ResizingBindingFrame .frame(width: r, height: r) .overlay( Image(systemName: "aspectratio") - .foregroundColor(.white) + .foregroundStyle(.white) .font(Font.system(size: r * 0.5)) ) } @@ -347,7 +347,7 @@ struct ResizingBindingFrame .frame(width: r, height: r) .overlay( Image(systemName: "arrow.up.backward.and.arrow.down.forward") - .foregroundColor(.white) + .foregroundStyle(.white) .font(Font.system(size: r * 0.5)) ) } @@ -370,7 +370,7 @@ struct ResizingBindingFrame .frame(width: r, height: r) .overlay( Image(systemName: "arrow.triangle.2.circlepath") - .foregroundColor(.white) + .foregroundStyle(.white) .font(Font.system(size: r * 0.5)) ) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift index 73d91629..e84072be 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift @@ -9,7 +9,6 @@ import Foundation import SwiftUI -@available(iOS 15, *) struct TemporalMessageView: View { let message: TemporalMessage let onDismiss: () -> Void @@ -22,7 +21,7 @@ struct TemporalMessageView: View { case .auto: Text(message.title) .bold() - .foregroundColor(.black) + .foregroundStyle(.black) .onAppear { Task { // 1.5秒待機してからdismissを実行する @@ -34,7 +33,7 @@ struct TemporalMessageView: View { VStack { Text(message.title) .bold() - .foregroundColor(.black) + .foregroundStyle(.black) Button("OK", action: onDismiss) } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index 22e95d11..9fdc9982 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -253,7 +253,6 @@ extension CustardInterfaceKey { } } -@available(iOS 15, *) struct CustomKeyboardView: View { private let custard: Custard private var tabDesign: TabDependentDesign { @@ -322,7 +321,6 @@ struct CustomKeyboardView: } } -@available(iOS 15, *) public struct CustardFlickKeysView: View { @State private var suggestState = FlickSuggestState() diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift index 7c5283fe..b7e1ca64 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift @@ -10,7 +10,6 @@ import CustardKit import Foundation import SwiftUI -@available(iOS 15, *) struct FlickKeyboardView: View { @State private var suggestState = FlickSuggestState() diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift index 0897d78a..ced5b41f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift @@ -9,7 +9,6 @@ import SwiftUI import SwiftUIUtils -@available(iOS 15, *) struct EmojiTabResultBar: View { init() {} @Environment(Extension.Theme.self) private var theme @@ -112,7 +111,7 @@ struct EmojiTabResultBarButtonStyle: View { @EnvironmentObject private var variableStates: VariableStates @Binding private var isResultViewExpanded: Bool @@ -81,7 +80,7 @@ struct KeyboardBarButton: V case let .systemImage(name): Image(systemName: name) .frame(width: iconSize, height: iconSize) - .foregroundColor(buttonLabelColor) + .foregroundStyle(buttonLabelColor) } } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift index a7cdfb16..14ec6ee2 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift @@ -208,7 +208,7 @@ struct MoveCursorBarBeta: V } } .allowsHitTesting(false) - .foregroundColor(theme.resultTextColor.color.opacity(0.4)) + .foregroundStyle(theme.resultTextColor.color.opacity(0.4)) .drawingGroup() .frame(width: viewWidth) .clipped() @@ -221,7 +221,7 @@ struct MoveCursorBarBeta: V Image(systemName: "chevron.left.2") .font(symbolFont(size: 18)) - .foregroundColor(symbolsColor) + .foregroundStyle(symbolsColor) .padding() .overlay( TouchDownAndTouchUpGestureView { @@ -242,12 +242,12 @@ struct MoveCursorBarBeta: V Spacer() Text(verbatim: "│") .font(.system(size: fontSize + 4)) - .foregroundColor(symbolsColor) + .foregroundStyle(symbolsColor) .allowsHitTesting(false) Spacer() Image(systemName: "chevron.right.2") .font(symbolFont(size: 18)) - .foregroundColor(symbolsColor) + .foregroundStyle(symbolsColor) .padding() .overlay( TouchDownAndTouchUpGestureView { @@ -365,7 +365,7 @@ struct MoveCursorBar: View .padding() }) Spacer() - }.foregroundColor(symbolsColor)) + }.foregroundStyle(symbolsColor)) } } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index c3749a12..6fe875d7 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -201,7 +201,7 @@ struct ResultButtonStyle: B .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: self.userSizePreference)) .frame(height: height) .padding(.all, 5) - .foregroundColor(theme.resultTextColor.color) // 文字色は常に不透明度1で描画する + .foregroundStyle(theme.resultTextColor.color) // 文字色は常に不透明度1で描画する .background( configuration.isPressed ? theme.pushedKeyFillColor.color.opacity(0.5) : diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift index 44a7ff00..90d725c9 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift @@ -9,7 +9,6 @@ import Foundation import SwiftUI -@available(iOS 15, *) public struct KeyboardView: View { @State private var messageManager = MessageManager(necessaryMessages: Extension.MessageProvider.messages, userDefaults: Extension.MessageProvider.userDefaults) @State private var isResultViewExpanded = false diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift index 3828d6c3..ade4b9e6 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift @@ -30,7 +30,7 @@ struct QwertyVariationsView ForEach(model.variations.indices, id: \.self) {(index: Int) in ZStack { Rectangle() - .foregroundColor(index == selection ? Color.blue : suggestColor) + .foregroundStyle(index == selection ? Color.blue : suggestColor) .frame(width: tabDesign.keyViewWidth, height: tabDesign.keyViewHeight * 0.9, alignment: .center) .cornerRadius(10.0) getLabel(model.variations[index].label) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift index 9e413ed9..940c5d3b 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift @@ -47,7 +47,6 @@ private final class ClipboardHistory: ObservableObject { } } -@available(iOS 15, *) struct ClipboardHistoryTab: View { @EnvironmentObject private var variableStates: VariableStates @StateObject private var target = ClipboardHistory() @@ -72,7 +71,7 @@ struct ClipboardHistoryTab: if pinned { HStack { Image(systemName: "pin.circle.fill") - .foregroundColor(.orange) + .foregroundStyle(.orange) Text(string) .lineLimit(2) } @@ -225,7 +224,7 @@ struct ClipboardHistoryTab: } } .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: Extension.SettingProvider.resultViewFontSize)) - .foregroundColor(theme.resultTextColor.color) + .foregroundStyle(theme.resultTextColor.color) .onAppear { self.target.reload(manager: variableStates.clipboardHistoryManager) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift index 3d6ca470..14baa953 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift @@ -293,7 +293,7 @@ struct EmojiTab: View { Label(genre.title, systemImage: systemImage) .labelStyle(.iconOnly) .font(.largeTitle) - .foregroundColor(theme.resultTextColor.color) + .foregroundStyle(theme.resultTextColor.color) .frame(width: footerHeight, height: scrollViewHeight) .contentShape(Rectangle()) } diff --git a/AzooKeyCore/Sources/SwiftUIUtils/Availability.swift b/AzooKeyCore/Sources/SwiftUIUtils/Availability.swift index 0db497df..f1db98e7 100644 --- a/AzooKeyCore/Sources/SwiftUIUtils/Availability.swift +++ b/AzooKeyCore/Sources/SwiftUIUtils/Availability.swift @@ -10,7 +10,6 @@ import Foundation import SwiftUI public extension View { - @available(iOS 15, macOS 12, *) @ViewBuilder func iOS16_scrollContentBackground(_ visibility: Visibility) -> some View { if #available(iOS 16, macOS 13, *) { diff --git a/AzooKeyCore/Sources/SwiftUIUtils/Color.swift b/AzooKeyCore/Sources/SwiftUIUtils/Color.swift index 3b3d218d..77d95aa3 100644 --- a/AzooKeyCore/Sources/SwiftUIUtils/Color.swift +++ b/AzooKeyCore/Sources/SwiftUIUtils/Color.swift @@ -21,6 +21,20 @@ public extension Color { static let background = Color(UIColor.systemBackground) static let label = Color(UIColor.label) } + +public extension ShapeStyle where Self == Color { + static var accentColor: Self { .accentColor } + static var systemGray: Self { .systemGray } + static var systemGray2: Self { .systemGray2 } + static var systemGray3: Self { .systemGray3 } + static var systemGray4: Self { .systemGray4 } + static var systemGray5: Self { .systemGray5 } + static var systemGray6: Self { .systemGray6 } + static var background: Self { .background } + static var secondarySystemBackground: Self { .secondarySystemBackground } + static var label: Self { .label } +} + #elseif os(macOS) import AppKit public extension Color { diff --git a/AzooKeyCore/Sources/SwiftUIUtils/IntegerTextField.swift b/AzooKeyCore/Sources/SwiftUIUtils/IntegerTextField.swift index 9f2eafd1..a399221d 100644 --- a/AzooKeyCore/Sources/SwiftUIUtils/IntegerTextField.swift +++ b/AzooKeyCore/Sources/SwiftUIUtils/IntegerTextField.swift @@ -8,7 +8,6 @@ import SwiftUI -@available(iOS 15.0, macOS 12.0, *) public struct IntegerTextField: View { public init(_ title: LocalizedStringKey, text: Binding, range: ClosedRange = .min ... .max) { self.title = title diff --git a/AzooKeyCore/Sources/SwiftUIUtils/StringInterpolation.swift b/AzooKeyCore/Sources/SwiftUIUtils/StringInterpolation.swift index d736152d..5c3db34f 100644 --- a/AzooKeyCore/Sources/SwiftUIUtils/StringInterpolation.swift +++ b/AzooKeyCore/Sources/SwiftUIUtils/StringInterpolation.swift @@ -8,6 +8,8 @@ import Foundation import SwiftUI + +// TODO: in iOS 17, Text.foregroundColor is deprecated. Use Text.foregroundStyle instead. public extension LocalizedStringKey.StringInterpolation { mutating func appendInterpolation(_ value: LocalizedStringKey, color: Color? = nil) { self.appendInterpolation(Text(value).foregroundColor(color)) diff --git a/MainApp/ContentView.swift b/MainApp/ContentView.swift index 104338ef..af20769e 100644 --- a/MainApp/ContentView.swift +++ b/MainApp/ContentView.swift @@ -114,7 +114,7 @@ private struct TabItem: View { var body: some View { VStack { Image(systemName: systemImage).font(.system(size: 20, weight: .light)) - .foregroundColor(.systemGray2) + .foregroundStyle(.systemGray2) Text(title) } } diff --git a/MainApp/Customize/CodableActionDataEditor.swift b/MainApp/Customize/CodableActionDataEditor.swift index 9934d4cd..560bd779 100644 --- a/MainApp/Customize/CodableActionDataEditor.swift +++ b/MainApp/Customize/CodableActionDataEditor.swift @@ -554,6 +554,6 @@ private struct ActionPicker: View { } } } - .foregroundColor(.primary) + .foregroundStyle(.primary) } } diff --git a/MainApp/Customize/CustardInformationView.swift b/MainApp/Customize/CustardInformationView.swift index 772f5910..45875192 100644 --- a/MainApp/Customize/CustardInformationView.swift +++ b/MainApp/Customize/CustardInformationView.swift @@ -120,10 +120,10 @@ struct CustardInformationView: View { switch userdata { case let .gridScroll(value): NavigationLink("編集する", destination: EditingScrollCustardView(manager: $manager, editingItem: value)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) case let .tenkey(value): NavigationLink("編集する", destination: EditingTenkeyCustardView(manager: $manager, editingItem: value)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } } } diff --git a/MainApp/Customize/CustardInterfaceKeyEditor.swift b/MainApp/Customize/CustardInterfaceKeyEditor.swift index 6798a77d..5d3cff67 100644 --- a/MainApp/Customize/CustardInterfaceKeyEditor.swift +++ b/MainApp/Customize/CustardInterfaceKeyEditor.swift @@ -466,7 +466,7 @@ struct CustardInterfaceKeyEditor: View { Section { Button("リセット") { key = .custom(.empty) - }.foregroundColor(.red) + }.foregroundStyle(.red) } } } @@ -503,7 +503,7 @@ struct CustardInterfaceKeyEditor: View { Button("入力を設定する") { key[.custom][.inputAction, position] = "" } - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } } Section(header: Text("ラベル")) { @@ -574,12 +574,12 @@ struct CustardInterfaceKeyEditor: View { Section(header: Text("アクション")) { Text("キーを押したときの動作をより詳しく設定します。") NavigationLink("アクションを編集する", destination: CodableActionDataEditor($key[.custom][.pressAction, position], availableCustards: CustardManager.load().availableCustards)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } Section(header: Text("長押しアクション")) { Text("キーを長押ししたときの動作をより詳しく設定します。") NavigationLink("長押しアクションを編集する", destination: CodableLongpressActionDataEditor($key[.custom][.longpressAction, position], availableCustards: CustardManager.load().availableCustards)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } if position == .center { @@ -592,7 +592,7 @@ struct CustardInterfaceKeyEditor: View { Section { Button("リセット") { key = .custom(.empty) - }.foregroundColor(.red) + }.foregroundStyle(.red) } } if let direction = position.flickDirection { @@ -600,7 +600,7 @@ struct CustardInterfaceKeyEditor: View { key[.custom].variations.removeAll { $0.type == .flickVariation(direction) } - }.foregroundColor(.red) + }.foregroundStyle(.red) } } } diff --git a/MainApp/Customize/CustomizeTabView.swift b/MainApp/Customize/CustomizeTabView.swift index 096d3d0b..0612e193 100644 --- a/MainApp/Customize/CustomizeTabView.swift +++ b/MainApp/Customize/CustomizeTabView.swift @@ -23,7 +23,7 @@ struct CustomizeTabView: View { .listRowSeparator(.hidden, edges: .bottom) Text("好きな文字や文章を並べたオリジナルのタブを作成することができます。") NavigationLink("カスタムタブの管理", destination: ManageCustardView(manager: $appStates.custardManager)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } Section(header: Text("タブバー")) { @@ -41,7 +41,7 @@ struct CustomizeTabView: View { } BoolSettingView(.displayTabBarButton) NavigationLink("タブバーを編集", destination: EditingTabBarView(manager: $appStates.custardManager)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } Section(header: Text("カスタムキー")) { diff --git a/MainApp/Customize/CustomizeTabWalkthrough.swift b/MainApp/Customize/CustomizeTabWalkthrough.swift index cb1527f7..2b6925f9 100644 --- a/MainApp/Customize/CustomizeTabWalkthrough.swift +++ b/MainApp/Customize/CustomizeTabWalkthrough.swift @@ -65,12 +65,12 @@ struct CustomizeTabWalkthroughView: View { Image(systemName: item.image) .font(imagesFont) .frame(width: geometry.size.width / 7.0, height: geometry.size.width / 7.0) - .foregroundColor(.blue) + .foregroundStyle(.blue) VStack(alignment: .leading) { Text(item.headline) .font(.subheadline.bold()) Text(item.body) - .foregroundColor(.gray) + .foregroundStyle(.gray) .font(.subheadline) } } @@ -83,7 +83,7 @@ struct CustomizeTabWalkthroughView: View { isShowing = false } .buttonStyle(LargeButtonStyle(backgroundColor: .blue)) - .foregroundColor(.white) + .foregroundStyle(.white) .padding(.top, 30) } .background(Color.background) diff --git a/MainApp/Customize/EditingTabBarView.swift b/MainApp/Customize/EditingTabBarView.swift index b6e9865f..a41a8bb2 100644 --- a/MainApp/Customize/EditingTabBarView.swift +++ b/MainApp/Customize/EditingTabBarView.swift @@ -63,7 +63,7 @@ struct EditingTabBarView: View { Label("アクション", systemImage: "terminal") Text(makeLabelText(item: item)) - .foregroundColor(.gray) + .foregroundStyle(.gray) } } label: { item in label(labelType: item.label) diff --git a/MainApp/Customize/EditingTenkeyCustardView.swift b/MainApp/Customize/EditingTenkeyCustardView.swift index 2b50ea97..46f2e80f 100644 --- a/MainApp/Customize/EditingTenkeyCustardView.swift +++ b/MainApp/Customize/EditingTenkeyCustardView.swift @@ -162,7 +162,7 @@ struct EditingTenkeyCustardView: CancelableEditor { ) .overlay( Image(systemName: "plus.circle") - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) ) } } @@ -277,19 +277,19 @@ struct EditingTenkeyCustardView: CancelableEditor { editingItem.emptyKeys.insert(.gridFit(x: x, y: y)) } label: { Label("削除する", systemImage: "trash") - .foregroundColor(.red) + .foregroundStyle(.red) } Button(role: .destructive) { removeRow(y: y) } label: { Label("この行を削除", systemImage: "trash") - .foregroundColor(.red) + .foregroundStyle(.red) } Button(role: .destructive) { removeColumn(x: x) } label: { Label("この列を削除", systemImage: "trash") - .foregroundColor(.red) + .foregroundStyle(.red) } } } diff --git a/MainApp/Customize/ManageCustardView.swift b/MainApp/Customize/ManageCustardView.swift index 29297246..233285ab 100644 --- a/MainApp/Customize/ManageCustardView.swift +++ b/MainApp/Customize/ManageCustardView.swift @@ -191,10 +191,10 @@ struct ManageCustardView: View { Section(header: Text("作る")) { Text("登録したい文字や単語を順番に書いていくだけでスクロール式のカスタムタブを作成することができます。") NavigationLink("スクロール式のカスタムタブを作る", destination: EditingScrollCustardView(manager: $manager)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) Text("フリック式のカスタムタブを作成することができます。") NavigationLink("フリック式のカスタムタブを作る", destination: EditingTenkeyCustardView(manager: $manager)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } if let custards = data.custards { ForEach(custards, id: \.identifier) {custard in @@ -219,7 +219,7 @@ struct ManageCustardView: View { selectedDocument = Data() data.reset() } - .foregroundColor(.red) + .foregroundStyle(.red) } else { Section(header: Text("おすすめ")) { @@ -229,7 +229,7 @@ struct ManageCustardView: View { data.download(from: "https://azookey.netlify.app/static/custard/\(item.file)") } label: { Image(systemName: "square.and.arrow.down") - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) .padding(.horizontal, 5) } Text(verbatim: item.name) @@ -263,7 +263,7 @@ struct ManageCustardView: View { if let failure = data.failureData { HStack { Image(systemName: "exclamationmark.triangle") - Text(failure.description).foregroundColor(.red) + Text(failure.description).foregroundStyle(.red) } } Section { @@ -406,7 +406,7 @@ struct URLImportCustardView: View { data.reset() url = nil } - .foregroundColor(.red) + .foregroundStyle(.red) } else if let text = data.processState.description { Section(header: Text("読み込み中")) { ProgressView(text) @@ -414,21 +414,21 @@ struct URLImportCustardView: View { data.reset() url = nil } - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } } else { Section(header: Text("読み込み失敗")) { if let failure = data.failureData { HStack { Image(systemName: "exclamationmark.triangle") - Text(failure.description).foregroundColor(.red) + Text(failure.description).foregroundStyle(.red) } } Button("閉じる") { data.reset() url = nil } - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } } } diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift index 3c730601..6f73f7b9 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift @@ -75,7 +75,7 @@ struct EnableAzooKeyViewButton: View { } } .buttonStyle(LargeButtonStyle(backgroundColor: .blue)) - .foregroundColor(.white) + .foregroundStyle(.white) case .destructive: Button(action: action) { if let systemName { @@ -84,7 +84,7 @@ struct EnableAzooKeyViewButton: View { Text(text) } } - .foregroundColor(.red) + .foregroundStyle(.red) } } } diff --git a/MainApp/General/DisclosuringList.swift b/MainApp/General/DisclosuringList.swift index 198c2ea7..e40db1c8 100644 --- a/MainApp/General/DisclosuringList.swift +++ b/MainApp/General/DisclosuringList.swift @@ -91,7 +91,7 @@ private struct MiniDisclosureGroup: View { } label: { Image(systemName: hidden ? "chevron.right" : "chevron.down") .font(.system(.caption).bold()) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } } if !hidden { diff --git a/MainApp/General/DraggableView.swift b/MainApp/General/DraggableView.swift index bb89761c..6e924914 100644 --- a/MainApp/General/DraggableView.swift +++ b/MainApp/General/DraggableView.swift @@ -33,7 +33,7 @@ struct DraggableView: View { } if SettingKey.requireFullAccess { Image(systemName: "f.circle.fill") - .foregroundColor(.purple) + .foregroundStyle(.purple) } } } diff --git a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift index ccb3b89f..a37ee7d6 100644 --- a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift +++ b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift @@ -170,7 +170,7 @@ struct FlickCustomKeySettingView: Vie Button("入力を設定する") { setting.value[.input, selectedPosition] = "" } - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } } case .tab: @@ -201,22 +201,22 @@ struct FlickCustomKeySettingView: Vie Section(header: Text("アクション")) { Text("キーを押したときの動作をより詳しく設定します。") NavigationLink("アクションを編集する", destination: CodableActionDataEditor($setting.value[keyPath: selectedPosition.bindedKeyPath].actions, availableCustards: CustardManager.load().availableCustards)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } Section(header: Text("長押しアクション")) { Text("キーを長押ししたときの動作をより詳しく設定します。") NavigationLink("長押しアクションを編集する", destination: CodableLongpressActionDataEditor($setting.value[keyPath: selectedPosition.bindedKeyPath].longpressActions, availableCustards: CustardManager.load().availableCustards)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } Button("リセット") { self.reload() } - .foregroundColor(.red) + .foregroundStyle(.red) } else { Text("このキーは編集できません") } } - .foregroundColor(.primary) + .foregroundStyle(.primary) } } } @@ -226,7 +226,7 @@ struct FlickCustomKeySettingView: Vie Button("タブを設定する") { setting.value[keyPath: keyPath].actions = [.moveTab(.system(.user_japanese))] } - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } @MainActor private func isPossiblePosition(_ position: FlickKeyPosition) -> Bool { diff --git a/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift b/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift index d7f8ebed..8c207198 100644 --- a/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift +++ b/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift @@ -14,13 +14,13 @@ struct CustomKeysSettingView: View { .listRowSeparator(.hidden, edges: .bottom) Text("「小゙゚」キーと「、。?!」キーで入力する文字をカスタマイズすることができます。") NavigationLink("設定する", destination: FlickCustomKeysSettingSelectView()) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) .listRowSeparator(.visible, edges: .all) ImageSlideshowView(pictures: ["qwertyCustomKeySetting0", "qwertyCustomKeySetting1", "qwertyCustomKeySetting2"]) .listRowSeparator(.hidden, edges: .bottom) Text("数字タブの青枠部分に好きな記号や文字を割り当てられます。") NavigationLink("設定する", destination: QwertyCustomKeysSettingView(.numberTabCustomKeys)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) .listRowSeparator(.visible, edges: .all) } } diff --git a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift index a26a6ac8..35df07b8 100644 --- a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift +++ b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift @@ -222,7 +222,7 @@ struct QwertyCustomKeysSettingView: Button("入力を設定する") { setting.value[.input, selection] = "" } - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } } Section(header: Text("ラベル")) { @@ -234,7 +234,7 @@ struct QwertyCustomKeysSettingView: Section(header: Text("アクション")) { Text("キーを押したときの動作をより詳しく設定します。") NavigationLink("アクションを編集する", destination: CodableActionDataEditor(binded[selection].actions, availableCustards: CustardManager.load().availableCustards)) - .foregroundColor(.accentColor) + .foregroundStyle(.accentColor) } Button("削除") { bottomSheetShown = false @@ -253,7 +253,7 @@ struct QwertyCustomKeysSettingView: } } } - .foregroundColor(.red) + .foregroundStyle(.red) } else { Button("キーを追加する") { self.addPressKey() diff --git a/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift b/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift index 6348a2aa..b2e37305 100644 --- a/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift +++ b/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift @@ -16,7 +16,7 @@ struct MemoryResetSettingItemView: View { Button("学習のリセット") { self.showAlert = true } - .foregroundColor(.red) + .foregroundStyle(.red) .alert(isPresented: $showAlert) { Alert( title: Text("学習履歴をリセットします。よろしいですか?"), diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index 08559f78..6f5a30ef 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -119,9 +119,9 @@ struct SettingTabView: View { Section(header: Text("このアプリについて")) { NavigationLink("お問い合わせ", destination: ContactView()) FallbackLink("プライバシーポリシー", destination: URL(string: "https://azookey.netlify.app/PrivacyPolicy")!) - .foregroundColor(.primary) + .foregroundStyle(.primary) FallbackLink("利用規約", destination: URL(string: "https://azookey.netlify.app/TermsOfService")!) - .foregroundColor(.primary) + .foregroundStyle(.primary) NavigationLink("更新履歴", destination: UpdateInformationView()) HStack { Text("URL Scheme") diff --git a/MainApp/Setting/Template/TemplateEditingView.swift b/MainApp/Setting/Template/TemplateEditingView.swift index 7794bad9..e9f6c974 100644 --- a/MainApp/Setting/Template/TemplateEditingView.swift +++ b/MainApp/Setting/Template/TemplateEditingView.swift @@ -52,7 +52,7 @@ struct TemplateEditingView: CancelableEditor { } if case let .nameError(message) = validation() { Label(message, systemImage: "exclamationmark.triangle") - .foregroundColor(.primary) + .foregroundStyle(.primary) } } } diff --git a/MainApp/Setting/Template/TemplateListView.swift b/MainApp/Setting/Template/TemplateListView.swift index 20dfe56c..c6dc943f 100644 --- a/MainApp/Setting/Template/TemplateListView.swift +++ b/MainApp/Setting/Template/TemplateListView.swift @@ -46,7 +46,7 @@ struct TemplateListView: View { Text(value.item.name) Spacer() Text(value.item.previewString) - .foregroundColor(.gray) + .foregroundStyle(.gray) } } } diff --git a/MainApp/Theme/ThemeEditView.swift b/MainApp/Theme/ThemeEditView.swift index db5006e1..ae341c09 100644 --- a/MainApp/Theme/ThemeEditView.swift +++ b/MainApp/Theme/ThemeEditView.swift @@ -146,7 +146,7 @@ struct ThemeEditView: CancelableEditor { pickedImage = nil trimmedImage = nil } - .foregroundColor(.red) + .foregroundStyle(.red) } else { Button("\(systemImage: "photo")画像を選ぶ") { self.isSheetPresented = true @@ -183,7 +183,7 @@ struct ThemeEditView: CancelableEditor { self.trimmedImage = nil self.theme = self.base } - .foregroundColor(.red) + .foregroundStyle(.red) } } let tab: Tab.ExistentialTab = { diff --git a/MainApp/Theme/ThemeShareView.swift b/MainApp/Theme/ThemeShareView.swift index 5e16c5ce..89997950 100644 --- a/MainApp/Theme/ThemeShareView.swift +++ b/MainApp/Theme/ThemeShareView.swift @@ -157,9 +157,9 @@ private struct ShareButtonStyle: ButtonStyle { configuration .label .font(.body.bold()) - .foregroundColor(.white) + .foregroundStyle(.white) .padding() - .background(RoundedRectangle(cornerRadius: 3).foregroundColor(.blue)) + .background(RoundedRectangle(cornerRadius: 3).foregroundStyle(.blue)) .padding() } } diff --git a/MainApp/Theme/ThemeTab.swift b/MainApp/Theme/ThemeTab.swift index 639ecfb8..b6c45f92 100644 --- a/MainApp/Theme/ThemeTab.swift +++ b/MainApp/Theme/ThemeTab.swift @@ -38,7 +38,7 @@ struct ThemeTabView: View { .overlay( Image(systemName: systemName) .font(Font.system(size: width / 2).weight(.bold)) - .foregroundColor(.white) + .foregroundStyle(.white) ) } @@ -133,7 +133,7 @@ struct ThemeTabView: View { manager.remove(index: index) } label: { Label("削除する", systemImage: "trash") - .foregroundColor(.red) + .foregroundStyle(.red) } .disabled(index == 0) } @@ -150,7 +150,7 @@ struct ThemeTabView: View { editViewIndex = nil editViewEnabled = true } - .foregroundColor(.primary) + .foregroundStyle(.primary) if editViewIndex == nil { NavigationLink(destination: ThemeEditView(index: editViewIndex, manager: $manager), isActive: $editViewEnabled) { EmptyView() diff --git a/MainApp/Tips/TipsView.swift b/MainApp/Tips/TipsView.swift index d71015e3..39f29b77 100644 --- a/MainApp/Tips/TipsView.swift +++ b/MainApp/Tips/TipsView.swift @@ -32,7 +32,7 @@ struct TipsTabView: View { HStack { if !readArticle_iOS14_service_termination { Image(systemName: "exclamationmark.circle.fill") - .foregroundColor(.red) + .foregroundStyle(.red) } NavigationLink("iOS14のサポートを終了します", destination: iOS14TerminationNewsView($readArticle_iOS14_service_termination)) } From 2304caa4b6df1ea987ec53f9dac397474b467c80 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 4 Aug 2023 23:33:04 +0900 Subject: [PATCH 006/124] Remove Alert.init --- MainApp/Customize/ManageCustardView.swift | 57 ++++++++-------- MainApp/General/FallbackLink.swift | 16 ++--- .../AzooKeyUserDictionary.swift | 14 ++-- .../BooleanSetting/BoolSettingView.swift | 68 ++++++++----------- .../FlickSensitivitySettingView.swift | 6 +- .../FontSizeSettingItemView.swift | 6 +- .../KeyboardHeightSettingView.swift | 6 +- .../MarkedTextSettingView.swift | 11 ++- .../MemoryResetSetting.swift | 22 +++--- 9 files changed, 96 insertions(+), 110 deletions(-) diff --git a/MainApp/Customize/ManageCustardView.swift b/MainApp/Customize/ManageCustardView.swift index 233285ab..968b1b53 100644 --- a/MainApp/Customize/ManageCustardView.swift +++ b/MainApp/Customize/ManageCustardView.swift @@ -14,8 +14,7 @@ import SwiftUIUtils import SwiftUtils import UniformTypeIdentifiers -private enum AlertType { - case none +private enum AlertType: Equatable { case overlapCustard(custard: Custard) } @@ -147,7 +146,7 @@ struct ManageCustardView: View { @ObservedObject private var data = ImportedCustardData() @State private var urlString: String = "" @State private var showAlert = false - @State private var alertType = AlertType.none + @State private var alertType: AlertType? = nil @Binding private var manager: CustardManager @State private var webCustards: WebCustardList = .init(last_update: "", custards: []) @State private var showDocumentPicker = false @@ -273,19 +272,20 @@ struct ManageCustardView: View { } } .navigationBarTitle(Text("カスタムタブの管理"), displayMode: .inline) - .alert(isPresented: $showAlert) { + .alert("注意", isPresented: $showAlert, presenting: alertType) { alertType in switch alertType { - case .none: - return Alert(title: Text("アラート")) - case let .overlapCustard(custard): - return Alert( - title: Text("注意"), - message: Text("識別子\(custard.identifier)を持つカスタムタブが既に登録されています。上書きしますか?"), - primaryButton: .default(Text("上書き")) { - self.saveCustard(custard: custard) - }, - secondaryButton: .cancel() - ) + case let .overlapCustard(custard: custard): + Button("上書き", role: .destructive) { + self.saveCustard(custard: custard) + } + Button("キャンセル", role: .cancel) { + self.showAlert = false + } + } + } message: { alertType in + switch alertType { + case let .overlapCustard(custard: custard): + Text("識別子\(custard.identifier)を持つカスタムタブが既に登録されています。上書きしますか?") } } .fileImporter(isPresented: $showDocumentPicker, allowedContentTypes: ["txt", "custard", "json"].compactMap {UTType(filenameExtension: $0, conformingTo: .text)}) {result in @@ -372,7 +372,7 @@ struct ManageCustardView: View { struct URLImportCustardView: View { @ObservedObject private var data = ImportedCustardData() @State private var showAlert = false - @State private var alertType = AlertType.none + @State private var alertType: AlertType? = nil @Binding private var manager: CustardManager @Binding private var url: URL? @State private var addTabBar = true @@ -439,19 +439,20 @@ struct URLImportCustardView: View { data.download(from: url) } } - .alert(isPresented: $showAlert) { + .alert("注意", isPresented: $showAlert, presenting: alertType) { alertType in + switch alertType { + case let .overlapCustard(custard: custard): + Button("上書き", role: .destructive) { + self.saveCustard(custard: custard) + } + Button("キャンセル", role: .cancel) { + self.showAlert = false + } + } + } message: { alertType in switch alertType { - case .none: - return Alert(title: Text("アラート")) - case let .overlapCustard(custard): - return Alert( - title: Text("注意"), - message: Text("識別子\(custard.identifier)を持つカスタムタブが既に登録されています。上書きしますか?"), - primaryButton: .default(Text("上書き")) { - self.saveCustard(custard: custard) - }, - secondaryButton: .cancel() - ) + case let .overlapCustard(custard: custard): + Text("識別子\(custard.identifier)を持つカスタムタブが既に登録されています。上書きしますか?") } } } diff --git a/MainApp/General/FallbackLink.swift b/MainApp/General/FallbackLink.swift index 22268976..e58b511d 100644 --- a/MainApp/General/FallbackLink.swift +++ b/MainApp/General/FallbackLink.swift @@ -47,15 +47,13 @@ struct FallbackLink: View { } label: { Label(title, systemImage: icon.systemImage) } - .alert(isPresented: $showAlert) { - Alert( - title: Text("ブラウザを開けませんでした"), - message: Text("URLをコピーします。"), - dismissButton: .default(Text("OK")) { - UIPasteboard.general.string = url.absoluteString - self.showAlert = false - } - ) + .alert("ブラウザを開けませんでした", isPresented: $showAlert) { + Button("OK") { + UIPasteboard.general.string = url.absoluteString + self.showAlert = false + } + } message: { + Text("URLをコピーします。") } } } diff --git a/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift b/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift index 616d03d4..97f0d817 100644 --- a/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift +++ b/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift @@ -328,14 +328,12 @@ private struct UserDictionaryDataEditor: CancelableEditor { } } .toggleStyle(.switch) - .alert(isPresented: $showExplanation) { - Alert( - title: Text("この単語をシェアする"), - message: Text("この単語をazooKeyの本体辞書に追加することを申請します。\n個人情報を含む単語は申請しないでください。"), - dismissButton: .default(Text("OK")) { - showExplanation = false - } - ) + .alert("この単語をシェアする", isPresented: $showExplanation) { + Button("OK") { + showExplanation = false + } + } message: { + Text("この単語をazooKeyの本体辞書に追加することを申請します。\n個人情報を含む単語は申請しないでください。") } } if #available(iOS 16.0, *), let selectedTemplate { diff --git a/MainApp/Setting/BooleanSetting/BoolSettingView.swift b/MainApp/Setting/BooleanSetting/BoolSettingView.swift index d3aaa3bb..bfcb6e15 100644 --- a/MainApp/Setting/BooleanSetting/BoolSettingView.swift +++ b/MainApp/Setting/BooleanSetting/BoolSettingView.swift @@ -11,12 +11,10 @@ import KeyboardViews import SwiftUI struct BoolSettingView: View { - private enum AlertMessage { - case `default` - case message(LocalizedStringKey) - } - @State private var isOn = false - @State private var alertMessage = AlertMessage.default + @State private var showExplanation = false + @State private var showRequireFullAccessAlert = false + @State private var showOnEnabledMessageAlert = false + @State private var onEnabledAlertMessage: LocalizedStringKey? = nil @State private var setting: SettingUpdater @MainActor init(_ key: SettingKey) { @@ -28,7 +26,7 @@ struct BoolSettingView: View { HStack { Text(SettingKey.title) Button { - isOn = true + showExplanation = true } label: { Image(systemName: "questionmark.circle") } @@ -47,7 +45,7 @@ struct BoolSettingView: View { toggle .disabled(true) .onTapGesture { - isOn = true + showRequireFullAccessAlert = true } } else { toggle @@ -59,44 +57,34 @@ struct BoolSettingView: View { .onChange(of: setting.value) { newValue in if newValue { if let message = SettingKey.onEnabled() { - self.alertMessage = .message(message) - self.isOn = true + self.onEnabledAlertMessage = message + self.showOnEnabledMessageAlert = true } } else { SettingKey.onDisabled() } } - .alert(isPresented: $isOn) { - switch self.alertMessage { - case .default: - if disabled, let url = URL(string: UIApplication.openSettingsURLString) { - return Alert( - title: Text(SettingKey.explanation), - message: Text("この機能にはフルアクセスが必要です。この機能を使いたい場合は、「設定」>「キーボード」でフルアクセスを有効にしてください。"), - primaryButton: .cancel { - isOn = false - }, - secondaryButton: .default(Text("「設定」アプリを開く")) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - isOn = false - } - ) - } else { - return Alert( - title: Text(SettingKey.explanation), - dismissButton: .default(Text("OK")) { - isOn = false - } - ) + .alert(SettingKey.explanation, isPresented: $showExplanation) { + Button("OK") { + self.showExplanation = false + } + } + .alert(SettingKey.explanation, isPresented: $showRequireFullAccessAlert) { + Button("キャンセル", role: .cancel) { + showRequireFullAccessAlert = false + } + if let url = URL(string: UIApplication.openSettingsURLString) { + Button("「設定」アプリを開く") { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + showRequireFullAccessAlert = false } - case let .message(message): - return Alert( - title: Text(message), - dismissButton: .default(Text("OK")) { - self.alertMessage = .default - isOn = false - } - ) + } + } message: { + Text("この機能にはフルアクセスが必要です。この機能を使いたい場合は、「設定」>「キーボード」でフルアクセスを有効にしてください。") + } + .alert(onEnabledAlertMessage ?? "", isPresented: $showOnEnabledMessageAlert) { + Button("OK") { + showOnEnabledMessageAlert = false } } } diff --git a/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift b/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift index 667c78e8..abc8d011 100644 --- a/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift +++ b/MainApp/Setting/FlickSensitivitySetting/FlickSensitivitySettingView.swift @@ -50,8 +50,10 @@ struct FlickSensitivitySettingView: View { setting.value = 1 } } - .alert(isPresented: $showAlert) { - Alert(title: Text(SettingKey.explanation), dismissButton: .default(Text("OK"))) + .alert(SettingKey.explanation, isPresented: $showAlert) { + Button("OK") { + showAlert = false + } } if enabled { VStack { diff --git a/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift b/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift index f1973e40..3f7a9212 100644 --- a/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift +++ b/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift @@ -48,8 +48,10 @@ struct FontSizeSettingView: View { setting.value = SettingKey.defaultValue } } - .alert(isPresented: $showAlert) { - Alert(title: Text(SettingKey.explanation), dismissButton: .default(Text("OK"))) + .alert(SettingKey.explanation, isPresented: $showAlert) { + Button("OK") { + showAlert = false + } } .listRowSeparator(.hidden) diff --git a/MainApp/Setting/KeyboardHeightSetting/KeyboardHeightSettingView.swift b/MainApp/Setting/KeyboardHeightSetting/KeyboardHeightSettingView.swift index af6356bc..b26439d9 100644 --- a/MainApp/Setting/KeyboardHeightSetting/KeyboardHeightSettingView.swift +++ b/MainApp/Setting/KeyboardHeightSetting/KeyboardHeightSettingView.swift @@ -39,8 +39,10 @@ struct KeyboardHeightSettingView: View { setting.value = 1 } } - .alert(isPresented: $showAlert) { - Alert(title: Text(SettingKey.explanation), dismissButton: .default(Text("OK"))) + .alert(SettingKey.explanation, isPresented: $showAlert) { + Button("OK") { + showAlert = false + } } if enabled { diff --git a/MainApp/Setting/MarkedTextSetting/MarkedTextSettingView.swift b/MainApp/Setting/MarkedTextSetting/MarkedTextSettingView.swift index e4172e77..3c68ff96 100644 --- a/MainApp/Setting/MarkedTextSetting/MarkedTextSettingView.swift +++ b/MainApp/Setting/MarkedTextSetting/MarkedTextSettingView.swift @@ -49,13 +49,10 @@ struct MarkedTextSettingView: View { .onAppear { setting.reload() } - .alert(isPresented: $isOn) { - Alert( - title: Text(SettingKey.explanation), - dismissButton: .default(Text("OK")) { - isOn = false - } - ) + .alert(SettingKey.explanation, isPresented: $isOn) { + Button("OK") { + isOn = false + } } } } diff --git a/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift b/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift index b2e37305..dff0f578 100644 --- a/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift +++ b/MainApp/Setting/MemoryResetSetting/MemoryResetSetting.swift @@ -17,18 +17,16 @@ struct MemoryResetSettingItemView: View { self.showAlert = true } .foregroundStyle(.red) - .alert(isPresented: $showAlert) { - Alert( - title: Text("学習履歴をリセットします。よろしいですか?"), - message: Text("この操作は取り消せません。"), - primaryButton: .cancel(Text("キャンセル"), action: { - self.showAlert = false - }), - secondaryButton: .destructive(Text("リセットする"), action: { - MemoryResetCondition.set(value: .need) - self.showAlert = false - }) - ) + .alert("学習履歴をリセットします。よろしいですか?", isPresented: $showAlert) { + Button("キャンセル", role: .cancel) { + self.showAlert = false + } + Button("リセットする", role: .destructive) { + MemoryResetCondition.set(value: .need) + self.showAlert = false + } + } message: { + Text("この操作は取り消せません。") } } } From 6de3fe2240b11e5e905e2bd35a47a7980d9085d7 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 7 Aug 2023 00:44:21 +0900 Subject: [PATCH 007/124] Update version for TestFlight --- azooKey.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index 6c4bfce9..f5cf5252 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -1642,7 +1642,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.1.2; + MARKETING_VERSION = 2.2; OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey; PRODUCT_NAME = azooKey; @@ -1678,7 +1678,7 @@ "@executable_path/Frameworks", ); LLVM_LTO = YES_THIN; - MARKETING_VERSION = 2.1.2; + MARKETING_VERSION = 2.2; OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ImplicitOpenExistentials"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey; PRODUCT_NAME = azooKey; @@ -1810,7 +1810,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.1.2; + MARKETING_VERSION = 2.2; OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey.keyboard; PRODUCT_NAME = Keyboard; @@ -1845,7 +1845,7 @@ "@executable_path/../../Frameworks", ); LLVM_LTO = YES_THIN; - MARKETING_VERSION = 2.1.2; + MARKETING_VERSION = 2.2; OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ImplicitOpenExistentials"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey.keyboard; PRODUCT_NAME = Keyboard; From bc5685f0c6d31fa5acb046b5a108b632f79a3a67 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 12 Aug 2023 01:43:33 +0900 Subject: [PATCH 008/124] =?UTF-8?q?DoublePressActions=E3=81=AEAPI=E3=82=92?= =?UTF-8?q?QwertyKeyView=E3=81=A7=E5=87=A6=E7=90=86=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyView/QwertyKeyModelProtocol.swift | 5 ++ .../KeyView/QwertyKeyView.swift | 75 ++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift index f266eecc..6814c0ba 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift @@ -90,6 +90,8 @@ protocol QwertyKeyModelProtocol { var variationsModel: VariationsModel {get} @MainActor func pressActions(variableStates: VariableStates) -> [ActionType] + /// 二回連続で押した際に発火するActionを指定する + @MainActor func doublePressActions(variableStates: VariableStates) -> [ActionType] @MainActor func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel func backGroundColorWhenPressed(theme: Extension.Theme) -> Color var unpressedKeyColorType: QwertyUnpressedKeyColorType {get} @@ -101,4 +103,7 @@ extension QwertyKeyModelProtocol { func backGroundColorWhenPressed(theme: ThemeData) -> Color { theme.pushedKeyFillColor.color } + func doublePressActions(variableStates: VariableStates) -> [ActionType] { + [] + } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index 8ec7effa..7f6ecf37 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -36,11 +36,71 @@ enum QwertyKeyPressState { } +struct QwertyKeyDoublePressState { + enum State { + case inactive + case firstPressStarted + case firstPressCompleted + case secondPressStarted + case secondPressCompleted + } + + private var state: State = .inactive + private(set) var updateDate: Date = Date() + + var secondPressCompleted: Bool { + self.state == .secondPressCompleted + } + mutating func update(touchDownDate: Date) { + switch self.state { + case .inactive, .firstPressStarted, .secondPressStarted: + self.state = .firstPressStarted + case .firstPressCompleted: + // secondPressの開始までは最大0.1秒 + if touchDownDate.timeIntervalSince(updateDate) > 0.1 { + self.state = .firstPressStarted + } else { + self.state = .secondPressStarted + } + case .secondPressCompleted: + self.state = .firstPressStarted + } + self.updateDate = touchDownDate + } + mutating func update(touchUpDate: Date) { + switch self.state { + case .inactive, .firstPressCompleted, .secondPressCompleted: + self.state = .inactive + case .firstPressStarted: + // firstPressの終了までは最大0.2秒 + if touchUpDate.timeIntervalSince(updateDate) > 0.2 { + self.state = .inactive + } else { + self.state = .firstPressCompleted + } + case .secondPressStarted: + // secondPressは最大0.2秒 + if touchUpDate.timeIntervalSince(updateDate) > 0.2 { + self.state = .inactive + } else { + self.state = .secondPressCompleted + } + } + self.updateDate = touchUpDate + } + + mutating func reset() { + self.state = .inactive + self.updateDate = Date() + } +} + struct QwertyKeyView: View { private let model: any QwertyKeyModelProtocol @EnvironmentObject private var variableStates: VariableStates @State private var pressState: QwertyKeyPressState = .unpressed + @State private var doublePressState = QwertyKeyDoublePressState() @State private var suggest = false @Environment(Extension.Theme.self) private var theme @@ -60,8 +120,10 @@ struct QwertyKeyView: View self.suggest = true switch self.pressState { case .unpressed: + // 押し始め self.model.feedback(variableStates: variableStates) self.pressState = .started(Date()) + self.doublePressState.update(touchDownDate: Date()) self.action.reserveLongPressAction(self.model.longPressActions, variableStates: variableStates) DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { // すでに処理が終了済みでなければ @@ -88,16 +150,25 @@ struct QwertyKeyView: View .onEnded({_ in self.action.registerLongPressActionEnd(self.model.longPressActions) self.suggest = false + // 更新する + self.doublePressState.update(touchUpDate: Date()) // 状態に基づいて、必要な変更を加える switch self.pressState { case .unpressed: break case let .started(date): - // もし0.4秒未満押していたら - if Date().timeIntervalSince(date) < 0.4 { + // ダブルプレスアクションが存在し、かつダブルプレス判定が成立していたらこちらを優先的に実行 + let doublePressActions = self.model.doublePressActions(variableStates: variableStates) + if !doublePressActions.isEmpty, doublePressState.secondPressCompleted { + self.action.registerActions(doublePressActions, variableStates: variableStates) + // 実行したので更新する + self.doublePressState.reset() + } else if Date().timeIntervalSince(date) < 0.4 { + // もし0.4秒未満押していたら self.action.registerActions(self.model.pressActions(variableStates: variableStates), variableStates: variableStates) } case .longPressed: + // longPressの場合はlongPress判定が成立した時点で発火済みなので何もする必要がない break case let .variations(selection): self.model.variationsModel.performSelected(selection: selection, actionManager: action, variableStates: variableStates) From adbf56ecad6658250f4098d7ed52d264aa83c5e3 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 12 Aug 2023 11:47:58 +0900 Subject: [PATCH 009/124] =?UTF-8?q?=E9=80=A3=E6=89=93=E3=81=AE=E3=82=BF?= =?UTF-8?q?=E3=82=A4=E3=83=9F=E3=83=B3=E3=82=B0=E3=81=A7=E6=89=93=E3=81=A1?= =?UTF-8?q?=E6=BC=8F=E3=82=8C=E3=81=8C=E7=99=BA=E7=94=9F=E3=81=99=E3=82=8B?= =?UTF-8?q?=E4=B8=8D=E5=85=B7=E5=90=88=E3=81=AB=E5=AF=BE=E5=87=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyView/QwertyKeyModelProtocol.swift | 2 +- .../KeyView/QwertyKeyView.swift | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift index 6814c0ba..435dfa44 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift @@ -103,7 +103,7 @@ extension QwertyKeyModelProtocol { func backGroundColorWhenPressed(theme: ThemeData) -> Color { theme.pushedKeyFillColor.color } - func doublePressActions(variableStates: VariableStates) -> [ActionType] { + func doublePressActions(variableStates _: VariableStates) -> [ActionType] { [] } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index 7f6ecf37..75f65f3e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +import func SwiftUtils.debug import SwiftUIUtils enum QwertyKeyPressState { @@ -103,6 +104,8 @@ struct QwertyKeyView: View @State private var doublePressState = QwertyKeyDoublePressState() @State private var suggest = false + @State private var longPressStartTask: Task<(), Error>? = nil + @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action private let tabDesign: TabDependentDesign @@ -125,9 +128,15 @@ struct QwertyKeyView: View self.pressState = .started(Date()) self.doublePressState.update(touchDownDate: Date()) self.action.reserveLongPressAction(self.model.longPressActions, variableStates: variableStates) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { + self.longPressStartTask = Task { + do { + // 0.4秒待つ + try await Task.sleep(nanoseconds: 0_400_000_000) + } catch { + debug(error) + } // すでに処理が終了済みでなければ - if self.pressState.isActive { + if !Task.isCancelled && self.pressState.isActive { // 長押し状態に設定する。 if self.model.variationsModel.variations.isEmpty { self.pressState = .longPressed @@ -148,10 +157,13 @@ struct QwertyKeyView: View }) // タップの終了時 .onEnded({_ in + // 更新する + let endDate = Date() + self.doublePressState.update(touchUpDate: endDate) self.action.registerLongPressActionEnd(self.model.longPressActions) self.suggest = false - // 更新する - self.doublePressState.update(touchUpDate: Date()) + self.longPressStartTask?.cancel() + self.longPressStartTask = nil // 状態に基づいて、必要な変更を加える switch self.pressState { case .unpressed: @@ -163,7 +175,7 @@ struct QwertyKeyView: View self.action.registerActions(doublePressActions, variableStates: variableStates) // 実行したので更新する self.doublePressState.reset() - } else if Date().timeIntervalSince(date) < 0.4 { + } else if endDate.timeIntervalSince(date) < 0.4 { // もし0.4秒未満押していたら self.action.registerActions(self.model.pressActions(variableStates: variableStates), variableStates: variableStates) } From 286acd7f05d0ab4fb56652c46c9216d97d687357 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 12 Aug 2023 10:45:09 +0900 Subject: [PATCH 010/124] Add Shift Key implementation --- .../AzooKeyKeyboardViewExtension.swift | 4 ++ ...nSpecificKeyboardViewSettingProvider.swift | 1 + .../KeyboardViews/VariableStates.swift | 8 +++ .../KeyView/QwertyKeyModel.swift | 2 +- .../KeyView/QwertyShiftKeyModel.swift | 56 +++++++++++++++++++ .../QwertyKeyboard/QwertyDataProvider.swift | 36 ++++++++---- Keyboard/Display/KeyboardActionManager.swift | 20 ++++++- 7 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift diff --git a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift index 0f6edc77..0793ff54 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift @@ -93,6 +93,10 @@ public enum AzooKeyKeyboardViewExtension: ApplicationSpecificKeyboardViewExtensi public static var useBetaMoveCursorBar: Bool { UseBetaMoveCursorBar.value } + + public static var useShiftKey: Bool { + false + } public static var canResetLearningForCandidate: Bool { LearningTypeSetting.value.needUsingMemory diff --git a/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift b/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift index 44b50c47..615f07dd 100644 --- a/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift +++ b/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift @@ -31,6 +31,7 @@ import Foundation static var displayTabBarButton: Bool { get } static var hideResetButtonInOneHandedMode: Bool { get } static var useBetaMoveCursorBar: Bool { get } + static var useShiftKey: Bool { get } static var canResetLearningForCandidate: Bool { get } diff --git a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift index fae0d81c..6eb11fd1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift +++ b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift @@ -45,8 +45,10 @@ public final class VariableStates: ObservableObject { var isTextMagnifying = false var hasUpsideComponent = false public var isCapsLocked = false + public var isShifted = false static let isCapsLockedKey = "isCapsLocked" + public static let isShiftedKey = "isShifted" static let hasUpsideComponentKey = "is_screen_expanded" static let hasFullAccessKey = "has_full_access" // ビルトインのステートとカスタムのステートの両方を適切に扱いたい @@ -80,6 +82,8 @@ public final class VariableStates: ObservableObject { return SemiStaticStates.shared.hasFullAccess } else if key == Self.isCapsLockedKey { return self.isCapsLocked + } else if key == Self.isShiftedKey { + return self.isShifted } else if key == Self.hasUpsideComponentKey { return self.hasUpsideComponent } @@ -92,7 +96,11 @@ public final class VariableStates: ObservableObject { return } else if key == "isTextMagnifying" { self.isTextMagnifying = newValue + } else if key == Self.isShiftedKey { + self.isCapsLocked = self.isCapsLocked && !newValue + self.isShifted = newValue } else if key == Self.isCapsLockedKey { + self.isShifted = self.isShifted && !newValue self.isCapsLocked = newValue } else { custardStates[key] = newValue diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift index 0046d775..683598ab 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift @@ -32,7 +32,7 @@ struct QwertyKeyModel: Qwer } func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { - if states.boolStates.isCapsLocked, states.keyboardLanguage == .en_US, case let .text(text) = self.labelType { + if (states.boolStates.isCapsLocked || states.boolStates.isShifted), states.keyboardLanguage == .en_US, case let .text(text) = self.labelType { return KeyLabel(.text(text.uppercased()), width: width, textColor: color) } return KeyLabel(self.labelType, width: width, textColor: color) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift new file mode 100644 index 00000000..52637ed5 --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift @@ -0,0 +1,56 @@ +// +// QwertyShiftKeyModel.swift +// +// +// Created by ensan on 2023/08/11. +// + +import SwiftUI + +struct QwertyShiftKeyModel: QwertyKeyModelProtocol { + static var shared: Self { QwertyShiftKeyModel() } + + let keySizeType: QwertyKeySizeType = .normal(of: 1, for: 1) + var variationsModel = VariationsModel([]) + + let needSuggestView: Bool = false + + func pressActions(variableStates: VariableStates) -> [ActionType] { + if variableStates.boolStates.isCapsLocked { + return [.setBoolState(VariableStates.BoolStates.isCapsLockedKey, .off)] + } else if variableStates.boolStates.isShifted { + return [.setBoolState(VariableStates.BoolStates.isShiftedKey, .off)] + } else { + return [.setBoolState(VariableStates.BoolStates.isShiftedKey, .on)] + } + } + + var longPressActions: LongpressActionType { + .init(start: [.setBoolState(VariableStates.BoolStates.isCapsLockedKey, .toggle)]) + } + + func doublePressActions(variableStates: VariableStates) -> [ActionType] { + if variableStates.boolStates.isCapsLocked { + return [] + } else { + return [.setBoolState(VariableStates.BoolStates.isCapsLockedKey, .on)] + } + } + + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + if states.boolStates.isCapsLocked { + return KeyLabel(.image("capslock.fill"), width: width, textColor: color) + } else if states.boolStates.isShifted { + return KeyLabel(.image("shift.fill"), width: width, textColor: color) + } else { + return KeyLabel(.image("shift"), width: width, textColor: color) + } + } + + let unpressedKeyColorType: QwertyUnpressedKeyColorType = .special + + func feedback(variableStates: VariableStates) { + KeyboardFeedback.tabOrOtherKey() + } + +} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift index d54a0869..89c4ecd1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift @@ -526,18 +526,30 @@ struct QwertyDataProvider { QwertyKeyModel(labelType: .text("o"), pressActions: [.input("o")]), QwertyKeyModel(labelType: .text("p"), pressActions: [.input("p")]) ], - [ - QwertyKeyModel(labelType: .text("a"), pressActions: [.input("a")]), - QwertyKeyModel(labelType: .text("s"), pressActions: [.input("s")]), - QwertyKeyModel(labelType: .text("d"), pressActions: [.input("d")]), - QwertyKeyModel(labelType: .text("f"), pressActions: [.input("f")]), - QwertyKeyModel(labelType: .text("g"), pressActions: [.input("g")]), - QwertyKeyModel(labelType: .text("h"), pressActions: [.input("h")]), - QwertyKeyModel(labelType: .text("j"), pressActions: [.input("j")]), - QwertyKeyModel(labelType: .text("k"), pressActions: [.input("k")]), - QwertyKeyModel(labelType: .text("l"), pressActions: [.input("l")]), - QwertyAaKeyModel.shared - ], + Extension.SettingProvider.useShiftKey ? + [ + QwertyShiftKeyModel.shared, + QwertyKeyModel(labelType: .text("a"), pressActions: [.input("a")]), + QwertyKeyModel(labelType: .text("s"), pressActions: [.input("s")]), + QwertyKeyModel(labelType: .text("d"), pressActions: [.input("d")]), + QwertyKeyModel(labelType: .text("f"), pressActions: [.input("f")]), + QwertyKeyModel(labelType: .text("g"), pressActions: [.input("g")]), + QwertyKeyModel(labelType: .text("h"), pressActions: [.input("h")]), + QwertyKeyModel(labelType: .text("j"), pressActions: [.input("j")]), + QwertyKeyModel(labelType: .text("k"), pressActions: [.input("k")]), + QwertyKeyModel(labelType: .text("l"), pressActions: [.input("l")]), + ] : [ + QwertyKeyModel(labelType: .text("a"), pressActions: [.input("a")]), + QwertyKeyModel(labelType: .text("s"), pressActions: [.input("s")]), + QwertyKeyModel(labelType: .text("d"), pressActions: [.input("d")]), + QwertyKeyModel(labelType: .text("f"), pressActions: [.input("f")]), + QwertyKeyModel(labelType: .text("g"), pressActions: [.input("g")]), + QwertyKeyModel(labelType: .text("h"), pressActions: [.input("h")]), + QwertyKeyModel(labelType: .text("j"), pressActions: [.input("j")]), + QwertyKeyModel(labelType: .text("k"), pressActions: [.input("k")]), + QwertyKeyModel(labelType: .text("l"), pressActions: [.input("l")]), + QwertyAaKeyModel.shared, + ], [ Self.tabKeys(rowInfo: (7, 2, 0, 0)).languageKey, QwertyKeyModel(labelType: .text("z"), pressActions: [.input("z")]), diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index f88a2bb1..564a14c5 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -96,32 +96,41 @@ import SwiftUtils variableStates.barState = .none } + private func shiftStateOff(variableStates: VariableStates) { + variableStates.boolStates[VariableStates.BoolStates.isShiftedKey] = false + } + private func doAction(_ action: ActionType, requireSetResult: Bool = true, variableStates: VariableStates) { debug("doAction", action) var undoAction: ActionType? switch action { case let .input(text, simpleInsert): self.showResultView(variableStates: variableStates) - if variableStates.boolStates.isCapsLocked && [.en_US, .el_GR].contains(variableStates.keyboardLanguage) { + if (variableStates.boolStates.isCapsLocked || variableStates.boolStates.isShifted) && [.en_US, .el_GR].contains(variableStates.keyboardLanguage) { let input = text.uppercased() self.inputManager.input(text: input, requireSetResult: requireSetResult, simpleInsert: simpleInsert, inputStyle: variableStates.inputStyle) } else { self.inputManager.input(text: text, requireSetResult: requireSetResult, simpleInsert: simpleInsert, inputStyle: variableStates.inputStyle) } + self.shiftStateOff(variableStates: variableStates) case let .insertMainDisplay(text): self.inputManager.insertMainDisplayText(text) + self.shiftStateOff(variableStates: variableStates) case let .delete(count): self.showResultView(variableStates: variableStates) + self.shiftStateOff(variableStates: variableStates) self.inputManager.deleteBackward(convertTargetCount: count, requireSetResult: requireSetResult) - case .smoothDelete: KeyboardFeedback.smoothDelete() self.showResultView(variableStates: variableStates) + self.shiftStateOff(variableStates: variableStates) let deletedText = self.inputManager.smoothDelete(requireSetResult: requireSetResult) if !deletedText.isEmpty { undoAction = .input(deletedText, simplyInsert: true) } case let .smartDelete(item): + self.showResultView(variableStates: variableStates) + self.shiftStateOff(variableStates: variableStates) let deletedText: String switch item.direction { case .forward: @@ -133,14 +142,17 @@ import SwiftUtils undoAction = .input(deletedText, simplyInsert: true) } case .paste: + // ペーストではシフトを解除しない if SemiStaticStates.shared.hasFullAccess { self.inputManager.paste() } case .deselectAndUseAsInputting: + self.shiftStateOff(variableStates: variableStates) self.inputManager.edit() case let .moveCursor(count): + // カーソル移動ではシフトを解除しない self.inputManager.moveCursor(count: count, requireSetResult: requireSetResult) case let .smartMoveCursor(item): @@ -169,18 +181,22 @@ import SwiftUtils case .enter: self.showResultView(variableStates: variableStates) + self.shiftStateOff(variableStates: variableStates) let actions = self.inputManager.enter() self.registerActions(actions, variableStates: variableStates) case .changeCharacterType: self.showResultView(variableStates: variableStates) + self.shiftStateOff(variableStates: variableStates) self.inputManager.changeCharacter(requireSetResult: requireSetResult, inputStyle: variableStates.inputStyle) case let .replaceLastCharacters(table): self.showResultView(variableStates: variableStates) + self.shiftStateOff(variableStates: variableStates) self.inputManager.replaceLastCharacters(table: table, requireSetResult: requireSetResult, inputStyle: variableStates.inputStyle) case let .moveTab(type): + // タブ移動ではシフトを解除しない variableStates.setTab(type) case let .setUpsideComponent(type): From fb079c88fd73a6d6858b2ff214698998497677ff Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 12 Aug 2023 15:36:52 +0900 Subject: [PATCH 011/124] =?UTF-8?q?=E3=82=B7=E3=83=95=E3=83=88=E3=82=AD?= =?UTF-8?q?=E3=83=BC=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E8=A8=98=E8=BF=B0?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/advice_for_azooKey_based_development.md | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/docs/advice_for_azooKey_based_development.md b/docs/advice_for_azooKey_based_development.md index fad43673..fba90ac6 100644 --- a/docs/advice_for_azooKey_based_development.md +++ b/docs/advice_for_azooKey_based_development.md @@ -28,7 +28,7 @@ azooKeyは一般の場合の再変換をサポートしていません。つま ### シフト -azooKeyのUIは英字のシフトに対応していません。 +azooKeyのデフォルトのUIは英字のシフトに対応していませんが、`ApplicationSpecificKeyboardViewSettingProvider`を実装する際に`useShiftKey`を`true`にすることでデフォルトのローマ字キーボードでシフトキーを実装することができます。 ### 「次候補」ボタン @@ -36,19 +36,6 @@ azooKeyのUIは英字のシフトに対応していません。 ## 修正されるべき実装 -### Qwerty英語キーボードの大文字化ボタン - -azooKeyはQwertyの英語キーボードで少しクセのあるUIを用いていて、標準キーボードのような「シフト→入力」ではなく、「入力→大文字化」というUIを搭載しています。 - -このUIの選定には2つの背景がありました。 - -1. 単純にローコストだった(フリックの英語キーボードと処理を揃えることができる) -1. 個人的にステートレスの方が好みだった(普段フリックのキーボードを使っているので、標準キーボードのQwerty英語キーボードではシフトをすぐに押し忘れる) - -ただ、キーボードにおいては「どれだけ一般的なUIか」というところが重要なので、デフォルトをこのUIにしたのはやや失敗だったと思っています。 - -もちろん今から変更するわけにはいかないので、今後「シフト」の方のボタンを使うオプションを導入することになりそうです。 - ### データの保存 azooKeyでは歴史的事情により、データの保存がナイーブな方法で行われています。具体的には、UserDefaultsと内部ディレクトリへのファイルの保存によって管理されており、Core DataやRealmなどユーザデータを保存するのに適した仕組みは利用していません。 @@ -63,4 +50,4 @@ azooKeyはアプリケーションと辞書をバンドルしています。し ### ポータビリティ -azooKeyはSwiftによる実装のため、AndroidやWindowsへの移植が困難となる可能性があります。これが問題となる場合、Mozcなどの利用をおすすめします。 \ No newline at end of file +azooKeyはSwiftによる実装のため、AndroidやWindowsへの移植が困難となる可能性があります。これが問題となる場合、Mozcなどの利用をおすすめします。 From 2dfb095317f504207566e99afd9c7c5c50194d3c Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 12 Aug 2023 17:11:11 +0900 Subject: [PATCH 012/124] Make it possible to add shadow via theme (currrently, theme editor does not support it tho) --- .../AzooKeyTheme/AzooKeySpecificTheme.swift | 6 ++++-- .../Sources/KeyboardThemes/ThemeData.swift | 20 ++++++++++++++++++- .../FlickKeyboard/KeyView/FlickKeyView.swift | 2 ++ .../KeyView/QwertyKeyView.swift | 2 ++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift index ebb6c137..bb7a7b64 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift @@ -55,7 +55,8 @@ public extension AzooKeyTheme { normalKeyFillColor: .color(Color(.displayP3, white: 1, opacity: 1)), specialKeyFillColor: .color(Color(.displayP3, red: 0.804, green: 0.808, blue: 0.835)), pushedKeyFillColor: .color(Color(.displayP3, red: 0.929, green: 0.929, blue: 0.945)), - suggestKeyFillColor: nil + suggestKeyFillColor: nil, + keyShadow: nil ) } @@ -73,7 +74,8 @@ extension AzooKeySpecificTheme: ApplicationSpecificKeyboardViewExtensionLayoutDe normalKeyFillColor: .system(layout == .qwerty ? .qwertyNormalKeyColor : .normalKeyColor), specialKeyFillColor: .system(.specialKeyColor), pushedKeyFillColor: .system(layout == .qwerty ? .qwertyHighlightedKeyColor : .highlightedKeyColor), - suggestKeyFillColor: nil + suggestKeyFillColor: nil, + keyShadow: nil ) } } diff --git a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift index dc33a196..8ec27a73 100644 --- a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift +++ b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift @@ -24,8 +24,9 @@ public struct ThemeData: Codable public var specialKeyFillColor: ColorData public var pushedKeyFillColor: ColorData // 自動で設定する public var suggestKeyFillColor: ColorData? // 自動で設定する + public var keyShadow: ThemeShadowData? - public init(id: Int? = nil, backgroundColor: ColorData, picture: ThemePicture, textColor: ColorData, textFont: ThemeFontWeight, resultTextColor: ColorData, resultBackgroundColor: ColorData, borderColor: ColorData, borderWidth: Double, normalKeyFillColor: ColorData, specialKeyFillColor: ColorData, pushedKeyFillColor: ColorData, suggestKeyFillColor: ColorData? = nil) { + public init(id: Int? = nil, backgroundColor: ColorData, picture: ThemePicture, textColor: ColorData, textFont: ThemeFontWeight, resultTextColor: ColorData, resultBackgroundColor: ColorData, borderColor: ColorData, borderWidth: Double, normalKeyFillColor: ColorData, specialKeyFillColor: ColorData, pushedKeyFillColor: ColorData, suggestKeyFillColor: ColorData? = nil, keyShadow: ThemeShadowData? = nil) { self.id = id self.backgroundColor = backgroundColor self.picture = picture @@ -39,6 +40,7 @@ public struct ThemeData: Codable self.specialKeyFillColor = specialKeyFillColor self.pushedKeyFillColor = pushedKeyFillColor self.suggestKeyFillColor = suggestKeyFillColor + self.keyShadow = keyShadow } enum CodingKeys: CodingKey { @@ -55,6 +57,7 @@ public struct ThemeData: Codable case specialKeyFillColor case pushedKeyFillColor case suggestKeyFillColor + case keyShadow } public init(from decoder: any Decoder) throws { @@ -73,10 +76,25 @@ public struct ThemeData: Codable self.specialKeyFillColor = try container.decode(ColorData.self, forKey: .specialKeyFillColor) self.pushedKeyFillColor = try container.decode(ColorData.self, forKey: .pushedKeyFillColor) self.suggestKeyFillColor = try? container.decode(ColorData?.self, forKey: .suggestKeyFillColor) + self.keyShadow = try? container.decode(ThemeShadowData?.self, forKey: .keyShadow) } } +public struct ThemeShadowData: Codable, Equatable, Sendable where ColorData: Codable & Equatable & Sendable { + public init(color: ColorData, radius: CGFloat, x: CGFloat, y: CGFloat) { + self.color = color + self.radius = radius + self.x = x + self.y = y + } + + public var color: ColorData + public var radius: CGFloat + public var x: CGFloat + public var y: CGFloat +} + public enum ThemeFontWeight: Int, Codable, Sendable { case ultraLight = 1 case thin = 2 diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift index ff30c6a7..5a59aa2d 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift @@ -226,6 +226,8 @@ public struct FlickKeyView: .strokeAndFill(fillContent: keyFillColor, strokeContent: keyBorderColor, lineWidth: theme.borderWidth) .frame(width: keySize.width, height: keySize.height) .gesture(gesture) + .compositingGroup() + .shadow(color: theme.keyShadow?.color.color ?? .clear, radius: theme.keyShadow?.radius ?? 0, x: theme.keyShadow?.x ?? 0, y: theme.keyShadow?.y ?? 0) .overlay(self.label(width: keySize.width)) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index 75f65f3e..d59ef845 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -235,6 +235,8 @@ struct QwertyKeyView: View .size(CGSize(width: size.width + tabDesign.horizontalSpacing, height: size.height + tabDesign.verticalSpacing)) ) .gesture(gesture) + .compositingGroup() + .shadow(color: theme.keyShadow?.color.color ?? .clear, radius: theme.keyShadow?.radius ?? 0, x: theme.keyShadow?.x ?? 0, y: theme.keyShadow?.y ?? 0) .overlay(label(width: size.width, color: nil)) } .overlay(Group { From 084637c38614c73b5787a9ad84689c516080706a Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 13 Aug 2023 00:42:04 +0900 Subject: [PATCH 013/124] fix concurrency build error --- DictionaryDebugger/KanaKanjiConvertResultViewer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DictionaryDebugger/KanaKanjiConvertResultViewer.swift b/DictionaryDebugger/KanaKanjiConvertResultViewer.swift index 4c1df4be..73b7cde8 100644 --- a/DictionaryDebugger/KanaKanjiConvertResultViewer.swift +++ b/DictionaryDebugger/KanaKanjiConvertResultViewer.swift @@ -13,7 +13,7 @@ import SwiftUIUtils struct KanaKanjiConvertResultViewer: View { private let converter: KanaKanjiConverter - init (dicdataStore: DicdataStore) { + @MainActor init (dicdataStore: DicdataStore) { self.converter = KanaKanjiConverter(dicdataStore: dicdataStore) } @@ -21,7 +21,7 @@ struct KanaKanjiConvertResultViewer: View { @State private var n_best = 10 @State private var prefix = 10 - private func requestConversion() -> [Candidate] { + @MainActor private func requestConversion() -> [Candidate] { var c = ComposingText() c.insertAtCursorPosition(query, inputStyle: .roman2kana) var options = ConvertRequestOptions.appDefault From 3eca7375efef807c446841d483a741d3c9133032 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 13 Aug 2023 19:04:14 +0900 Subject: [PATCH 014/124] Add more test case to understand more on the accuracy --- .../ConverterTests/ConverterTests.swift | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift b/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift index 56601dfd..d328d3e0 100644 --- a/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift +++ b/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift @@ -236,7 +236,25 @@ import XCTest ("よとうもやとうもでぃすればちゅうりつ", ["与党も野党もディスれば中立"]), ("だいすきなえしさん", ["大好きな絵師さん"]), ("ぱいそんでかかれたそーすこーど", ["Pythonで書かれたソースコード"]), - ("SwiftでつくったApp", ["Swiftで作ったApp"]) + ("SwiftでつくったApp", ["Swiftで作ったApp"]), + ("かんじょうなんてむだなもん", ["感情なんて無駄なもん"]), + ("ひびをすごす", ["日々を過ごす"]), + ("あたらしいほんをかった", ["新しい本を買った"]), + ("かれのはなしはおもしろい", ["彼の話は面白い"]), + ("ろーかるでうごかす", ["ローカルで動かす"]), + ("よのなかにひつようなのはてすうりょうぜろのでんしけっさい", ["世の中に必要なのは手数料ゼロの電子決済"]), + ("こんしゅうはとてもそーしゃる", ["今週はとてもソーシャル"]), + ("でかすぎるそーすこーど", ["デカすぎるソースコード"]), + ("らちがあかないんだよね", ["埒が開かないんだよね"]), + ("まいなんばーかーどでじゅうみんひょうだせてべんり", ["マイナンバーカードで住民票出せて便利"]), + ("でじたるかなんですか", ["デジタル化なんですか"]), + ("じぶんのひとつしたのせだいがゆうしゅうすぎる", ["自分の一つ下の世代が優秀すぎる"]), + ("みんなしごととごらくとべんきょうをぜんぶやってる", ["みんな仕事と娯楽と勉強を全部やってる"]), + ("ばいようにくたべてみたいね", ["培養肉食べてみたいね"]), + ("おどらされははらすめんと", ["踊らされはハラスメント"]), + ("じんじょうならびょういんにいくれべるのいたみ", ["尋常なら病院に行くレベルの痛み"]), + ("ろぐいんぼーなすてきなしくみがきらい", ["ログインボーナス的な仕組みが嫌い"]), + ("かいにいくのはおまえね", ["買いに行くのはお前ね"]) ] var score: Double = 0 From cae24dacdbef06b94c7868615137e58a6009e7b2 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 13 Aug 2023 19:52:11 +0900 Subject: [PATCH 015/124] =?UTF-8?q?Failure=E3=82=B1=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=82=92print=E3=80=81verbal=E3=81=AE=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E3=80=81meaningBased=E3=81=AE=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConverterTests/ConverterTests.swift | 83 ++++++++++++++++++- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift b/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift index d328d3e0..89e92f82 100644 --- a/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift +++ b/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift @@ -245,7 +245,7 @@ import XCTest ("よのなかにひつようなのはてすうりょうぜろのでんしけっさい", ["世の中に必要なのは手数料ゼロの電子決済"]), ("こんしゅうはとてもそーしゃる", ["今週はとてもソーシャル"]), ("でかすぎるそーすこーど", ["デカすぎるソースコード"]), - ("らちがあかないんだよね", ["埒が開かないんだよね"]), + ("らちがあかないんだよね", ["埒が明かないんだよね"]), ("まいなんばーかーどでじゅうみんひょうだせてべんり", ["マイナンバーカードで住民票出せて便利"]), ("でじたるかなんですか", ["デジタル化なんですか"]), ("じぶんのひとつしたのせだいがゆうしゅうすぎる", ["自分の一つ下の世代が優秀すぎる"]), @@ -268,10 +268,61 @@ import XCTest score += 1 } else if results.mainResults.count > 1 && expect.contains(results.mainResults[1].text) { score += 0.5 + } else { + print("\(#function) Failure: input \(input), expect \(expect.joined(separator: " | ")), result: \(results.mainResults.map(\.text).prefix(5).joined(separator: ", "))") } } let accuracy = score / Double(cases.count) - print("testAccuracy Result: accuracy \(accuracy), score \(score), count \(cases.count)") + print("\(#function) Result: accuracy \(accuracy), score \(score), count \(cases.count)") + XCTAssertGreaterThan(accuracy, 0.7) // 0.7 < acuracy + } + + // 変換結果が比較的一意なテストケースを無数に持ち、一定の割合を正解することを要求する + // 辞書を更新した結果性能が悪化したら気付ける + // 口語表現を中心にテストする + func testVerbalAccuracy() throws { + let cases: [(input: String, expect: [String])] = [ + ("うわああああ、まじか", ["うわああああ、マジか", "うわああああ、まじか"]), + ("は?", ["は?"]), + ("おまえなんなん", ["お前なんなん"]), + ("めっちゃくさ", ["めっちゃ草"]), + ("はやってんだなぁやっぱり", ["流行ってんだなぁやっぱり"]), + ("そっちかぁ", ["そっちかぁ"]), + ("かみすぎます…!", ["神すぎます…!"]), + ("うおー、りかいした", ["うおー、理解した"]), + ("あ、なるほど", ["あ、なるほど"]), + ("あらま", ["あらま"]), + ("さすがやな…", ["流石やな…"]), + ("のれないんでしょうね。", ["乗れないんでしょうね。"]), + ("おつかれさまですわら", ["お疲れ様です笑", "おつかれさまです笑"]), + ("よううれたのぉわらわら", ["よう売れたのぉ笑笑"]), + ("わーそれはもう", ["わーそれはもう"]), + ("よねんまえやで??", ["4年前やで??", "四年前やで??"]), + ("おうしょうもいいなぁ", ["王将もいいなぁ", "王将も良いなぁ"]), + ("それなすぎる", ["それなすぎる"]), + ("じじつなんでしゃーないです", ["事実なんでしゃーないです"]), + ("がんばりまーーーす!", ["がんばりまーーーす!", "頑張りまーーーす!"]), + ("うるさいよな", ["うるさいよな"]), + ("ほんとどゆことわらわら", ["ほんとどゆこと笑笑"]) + ] + + var score: Double = 0 + for (input, expect) in cases { + let converter = KanaKanjiConverter() + var c = ComposingText() + c.insertAtCursorPosition(input, inputStyle: .direct) + let results = converter.requestCandidates(c, options: requestOptions()) + + if expect.contains(results.mainResults[0].text) { + score += 1 + } else if results.mainResults.count > 1 && expect.contains(results.mainResults[1].text) { + score += 0.5 + } else { + print("\(#function) Failure: input \(input), expect \(expect.joined(separator: " | ")), result: \(results.mainResults.map(\.text).prefix(5).joined(separator: ", "))") + } + } + let accuracy = score / Double(cases.count) + print("\(#function) Result: accuracy \(accuracy), score \(score), count \(cases.count)") XCTAssertGreaterThan(accuracy, 0.7) // 0.7 < acuracy } @@ -322,6 +373,15 @@ import XCTest ("じこ、ちめい、しぼう", "事故、致命、死亡"), ("ちず、ちめい、ちり", "地図、地名、地理"), + + ("なんべい、ちり、りょこう", "南米、チリ、旅行"), + ("よごれ、ちり、そうじ", "汚れ、塵、掃除"), + ("ちがく、ちり、べんきょう", "地学、地理、勉強"), + + ("ごおん、ほうこう、ばくふ", "御恩、奉公、幕府"), + ("なんせい、ほうこう、いどう", "南西、方向、移動"), + ("こうすい、ほうこう、におい", "香水、芳香、匂い"), + ("けもの、ほうこう、おたけび", "獣、咆哮、雄叫び"), ("つみ、りょうしん、かしゃく", "罪、良心、呵責"), ("ちち、りょうしん、はは", "父、両親、母"), @@ -363,6 +423,21 @@ import XCTest ("もしゃ、せいぶつ、すけっち", "模写、静物、スケッチ"), ("どうぶつ、せいぶつ、しよくぶつ", "動物、生物、植物"), + ("かんのうてき、せいてき、えろ", "官能的、性的、エロ"), + ("どうてき、せいてき、すたてぃっく", "動的、静的、スタティック"), + ("せいじか、せいてき、さくりゃく", "政治家、政敵、策略"), + + ("えくせる、ちかん、けつごう", "Excel、置換、結合"), + ("でんしゃ、ちかん、たいほ", "電車、痴漢、逮捕"), + + ("ふぁんたじー、ようせい、どらごん", "ファンタジー、妖精、ドラゴン"), + ("ころな、ようせい、いんせい", "コロナ、陽性、陰性"), + ("じしゅく、ようせい、むし", "自粛、要請、無視"), + ("いじん、ようせい、わかさ", "偉人、夭逝、若さ"), + + ("いじめ、むし、ほうち", "いじめ、無視、放置"), + ("こんちゅう、むし、ようちゅう", "昆虫、虫、幼虫"), + ("けんぼう、かいせい、ろんぎ", "憲法、改正、論議"), ("みょうじ、かいせい、かいめい", "苗字、改姓、改名"), ("ほんじつ、かいせい、てんき", "本日、快晴、天気"), @@ -543,10 +618,12 @@ import XCTest score += 1 } else if results.mainResults.count > 1 && results.mainResults[1].text == expect { score += 0.5 + } else { + print("\(#function) Failure: input \(input), expect \(expect), result: \(results.mainResults.map(\.text).prefix(5).joined(separator: ", "))") } } let accuracy = score / Double(cases.count) - print("testMeaningBasedConversionAccuracy Result: accuracy \(accuracy), score \(score), count \(cases.count)") + print("\(#function) Result: accuracy \(accuracy), score \(score), count \(cases.count)") XCTAssertGreaterThan(accuracy, 0.7) // 0.7 < accuracy } } From f4d019c59da3b3321eb8527cd3f97c2173b9c9e9 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Wed, 16 Aug 2023 18:55:14 +0900 Subject: [PATCH 016/124] =?UTF-8?q?\n=E3=81=8C=E5=A4=89=E6=8F=9B=E3=81=AB?= =?UTF-8?q?=E7=8F=BE=E3=82=8C=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MainApp/LOUDSLogic/LOUDSBuilder.swift | 2 +- .../KeyboardTests/DicdataStoreTests/DicdataStoreTests.swift | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MainApp/LOUDSLogic/LOUDSBuilder.swift b/MainApp/LOUDSLogic/LOUDSBuilder.swift index c98c3fd3..c448252c 100644 --- a/MainApp/LOUDSLogic/LOUDSBuilder.swift +++ b/MainApp/LOUDSLogic/LOUDSBuilder.swift @@ -150,7 +150,7 @@ struct LOUDSBuilder { let right = word[range.upperBound.. Date: Wed, 16 Aug 2023 18:55:14 +0900 Subject: [PATCH 017/124] =?UTF-8?q?\n=E3=81=8C=E5=A4=89=E6=8F=9B=E3=81=AB?= =?UTF-8?q?=E7=8F=BE=E3=82=8C=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MainApp/LOUDSLogic/LOUDSBuilder.swift | 2 +- .../KeyboardTests/DicdataStoreTests/DicdataStoreTests.swift | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MainApp/LOUDSLogic/LOUDSBuilder.swift b/MainApp/LOUDSLogic/LOUDSBuilder.swift index c98c3fd3..c448252c 100644 --- a/MainApp/LOUDSLogic/LOUDSBuilder.swift +++ b/MainApp/LOUDSLogic/LOUDSBuilder.swift @@ -150,7 +150,7 @@ struct LOUDSBuilder { let right = word[range.upperBound.. Date: Wed, 16 Aug 2023 22:32:18 +0900 Subject: [PATCH 018/124] Add Mozc Evaluation --- .../ConverterTests/ConverterTests.swift | 135 +++++++++++++++++- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift b/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift index 89e92f82..4c274060 100644 --- a/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift +++ b/azooKeyTests/KeyboardTests/ConverterTests/ConverterTests.swift @@ -6,6 +6,7 @@ // Copyright © 2023 ensan. All rights reserved. // +import Foundation import KanaKanjiConverterModule import XCTest @@ -373,11 +374,11 @@ import XCTest ("じこ、ちめい、しぼう", "事故、致命、死亡"), ("ちず、ちめい、ちり", "地図、地名、地理"), - + ("なんべい、ちり、りょこう", "南米、チリ、旅行"), ("よごれ、ちり、そうじ", "汚れ、塵、掃除"), ("ちがく、ちり、べんきょう", "地学、地理、勉強"), - + ("ごおん、ほうこう、ばくふ", "御恩、奉公、幕府"), ("なんせい、ほうこう、いどう", "南西、方向、移動"), ("こうすい、ほうこう、におい", "香水、芳香、匂い"), @@ -426,15 +427,15 @@ import XCTest ("かんのうてき、せいてき、えろ", "官能的、性的、エロ"), ("どうてき、せいてき、すたてぃっく", "動的、静的、スタティック"), ("せいじか、せいてき、さくりゃく", "政治家、政敵、策略"), - + ("えくせる、ちかん、けつごう", "Excel、置換、結合"), ("でんしゃ、ちかん、たいほ", "電車、痴漢、逮捕"), - + ("ふぁんたじー、ようせい、どらごん", "ファンタジー、妖精、ドラゴン"), ("ころな、ようせい、いんせい", "コロナ、陽性、陰性"), ("じしゅく、ようせい、むし", "自粛、要請、無視"), ("いじん、ようせい、わかさ", "偉人、夭逝、若さ"), - + ("いじめ、むし、ほうち", "いじめ、無視、放置"), ("こんちゅう、むし、ようちゅう", "昆虫、虫、幼虫"), @@ -626,4 +627,128 @@ import XCTest print("\(#function) Result: accuracy \(accuracy), score \(score), count \(cases.count)") XCTAssertGreaterThan(accuracy, 0.7) // 0.7 < accuracy } + + func testMozcEvaluationData() async throws { + // ダウンロードするURL + let urlString = "https://raw.githubusercontent.com/google/mozc/master/src/data/dictionary_oss/evaluation.tsv" + let url = URL(string: urlString)! + // URLを元にURLオブジェクトを生成 + let (data, _) = try await URLSession.shared.data(from: url) + let content = String(data: data, encoding: .utf8)! + + var mozcScore: Double = 0 + var azooKeyScore: Double = 0 + var cases = 0 + for line in content.split(separator: "\n") { + if line.hasPrefix("#") { + continue + } + let items = line.split(separator: "\t", omittingEmptySubsequences: false) + if items.count != 6 { + continue + } + // 必要な情報を取り出す + let mozcStatus = items[0] == "OK:" + let input = String(items[1]) + let mozcOutput = String(items[2]) + let commandString = items[3] + let command: MozcCommand + if commandString == "Conversion Match" { + command = .conversionMatch + } else if commandString == "Conversion Not Match" { + command = .conversionNotMatch + } else if commandString == "Suggestion Not Expected" { + command = .suggestionNotExpected + } else if commandString.hasPrefix("Conversion Expected") { + if commandString == "Conversion Expected" { + command = .conversionExpected(within: 1) + } else { + let countString = commandString.split(separator: " ").last! + command = .conversionExpected(within: Int(countString)!) + } + } else { + fatalError("Unknown command \(commandString)") + } + + if command == .suggestionNotExpected { + // azooKeyでは扱えないため + continue + } + + if mozcStatus { + mozcScore += 1 + } + + let argument = items[4] + let converter = KanaKanjiConverter() + var c = ComposingText() + c.insertAtCursorPosition(input, inputStyle: .direct) + var options = requestOptions() + options.requireJapanesePrediction = false + let results = converter.requestCandidates(c, options: options).mainResults + cases += 1 + let azooKeyStatus = mozcEvaluation(command: command, argument: argument, results: results) + if azooKeyStatus { + azooKeyScore += 1 + if !mozcStatus { + print("\(#function) Success over Mozc: \(commandString) \(argument) for input \(input) \(results.prefix(command.requiredCount).map(\.text)), mozcResult: \(mozcOutput)") + } + } else { + if mozcStatus { + print("\(#function) Failure over Mozc: \(commandString) \(argument) for input \(input) \(results.prefix(command.requiredCount).map(\.text)), mozcResult: \(mozcOutput)") + } else { + print("\(#function) Failure: \(commandString) \(argument) for input \(input) \(results.prefix(command.requiredCount).map(\.text)), mozcResult: \(mozcOutput)") + } + } + } + print("\(#function) Result: Mozc Score: \(mozcScore), azooKeyScore \(azooKeyScore), count \(cases)") + XCTAssertTrue(mozcScore > 0) + XCTAssertTrue(azooKeyScore > 0) + XCTExpectFailure("azooKey is not as accurate as Mozc currently in this mertics, due to some reason") { + XCTAssertTrue(mozcScore < azooKeyScore) + } + } + + enum MozcCommand: Equatable { + /// 変換に`arg`が現れる + case conversionMatch + /// 変換に`arg`が現れない + case conversionNotMatch + /// n番目までに`arg`が登場 + case conversionExpected(within: Int) + /// サジェストに`arg`が登場しない + case suggestionNotExpected + + var requiredCount: Int { + switch self { + case .conversionMatch, .conversionNotMatch, .suggestionNotExpected: + return 1 + case .conversionExpected(within: let count): + return count + } + } + } + + private func mozcEvaluation(command: MozcCommand, argument: some StringProtocol, results: [Candidate]) -> Bool { + guard let first = results.first else { + return false + } + switch command { + case .conversionMatch: + if first.text.contains(argument) { + return true + } + case .conversionNotMatch: + if !first.text.contains(argument) { + return true + } + case .suggestionNotExpected: + fatalError("mozcEvaluation does not support command \(command)") + case .conversionExpected(within: let count): + if results.prefix(count).contains(where: {$0.text == argument}) { + return true + } + } + return false + } } From ead9361936212f742611be14d8e029cd285cfa59 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 20 Aug 2023 23:58:59 +0900 Subject: [PATCH 019/124] =?UTF-8?q?FlickSuggestView=E3=81=AE=E3=83=AA?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF=E3=83=AA=E3=83=B3=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 複数の型を別ファイルに分けた * FlickedKeyModel側がViewを作成していた問題を修正 * ThemeDataに新たにsuggestLabelTextColorを追加し、文字色を変えやすく * コメントを追加 --- .../Sources/KeyboardThemes/ThemeData.swift | 8 +- .../FlickKeyboard/FlickKeyboardView.swift | 2 +- .../FlickKeyboard/KeyView/FlickKeyModel.swift | 1 - .../FlickKeyboard/KeyView/FlickKeyView.swift | 4 +- .../SuggestView/FlickSuggestState.swift | 12 +++ .../SuggestView/FlickSuggestType.swift | 15 ++++ .../SuggestView/FlickSuggestView.swift | 86 +++++++++++++++++++ .../SuggestView/FlickedKeyModel.swift | 51 +---------- .../SuggestView/SuggestView.swift | 73 ---------------- .../extension FlickDirection.swift | 23 +++++ .../KeyView/QwertyVariationsView.swift | 7 +- 11 files changed, 149 insertions(+), 133 deletions(-) create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift delete mode 100644 AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/SuggestView.swift create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift diff --git a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift index 8ec27a73..bc116883 100644 --- a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift +++ b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift @@ -24,9 +24,10 @@ public struct ThemeData: Codable public var specialKeyFillColor: ColorData public var pushedKeyFillColor: ColorData // 自動で設定する public var suggestKeyFillColor: ColorData? // 自動で設定する - public var keyShadow: ThemeShadowData? + public var suggestLabelTextColor: ColorData? // 設定は露出させない + public var keyShadow: ThemeShadowData? // 設定は露出させない - public init(id: Int? = nil, backgroundColor: ColorData, picture: ThemePicture, textColor: ColorData, textFont: ThemeFontWeight, resultTextColor: ColorData, resultBackgroundColor: ColorData, borderColor: ColorData, borderWidth: Double, normalKeyFillColor: ColorData, specialKeyFillColor: ColorData, pushedKeyFillColor: ColorData, suggestKeyFillColor: ColorData? = nil, keyShadow: ThemeShadowData? = nil) { + public init(id: Int? = nil, backgroundColor: ColorData, picture: ThemePicture, textColor: ColorData, textFont: ThemeFontWeight, resultTextColor: ColorData, resultBackgroundColor: ColorData, borderColor: ColorData, borderWidth: Double, normalKeyFillColor: ColorData, specialKeyFillColor: ColorData, pushedKeyFillColor: ColorData, suggestKeyFillColor: ColorData? = nil, suggestLabelTextColor: ColorData? = nil, keyShadow: ThemeShadowData? = nil) { self.id = id self.backgroundColor = backgroundColor self.picture = picture @@ -40,6 +41,7 @@ public struct ThemeData: Codable self.specialKeyFillColor = specialKeyFillColor self.pushedKeyFillColor = pushedKeyFillColor self.suggestKeyFillColor = suggestKeyFillColor + self.suggestLabelTextColor = suggestLabelTextColor self.keyShadow = keyShadow } @@ -57,6 +59,7 @@ public struct ThemeData: Codable case specialKeyFillColor case pushedKeyFillColor case suggestKeyFillColor + case suggestLabelTextColor case keyShadow } @@ -76,6 +79,7 @@ public struct ThemeData: Codable self.specialKeyFillColor = try container.decode(ColorData.self, forKey: .specialKeyFillColor) self.pushedKeyFillColor = try container.decode(ColorData.self, forKey: .pushedKeyFillColor) self.suggestKeyFillColor = try? container.decode(ColorData?.self, forKey: .suggestKeyFillColor) + self.suggestLabelTextColor = try? container.decode(ColorData?.self, forKey: .suggestLabelTextColor) self.keyShadow = try? container.decode(ThemeShadowData?.self, forKey: .keyShadow) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift index b7e1ca64..efff5fca 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift @@ -40,7 +40,7 @@ struct FlickKeyboardView: V } @MainActor - private func suggestView(h: Int, v: Int, suggestType: FlickSuggestState.SuggestType) -> FlickSuggestView { + private func suggestView(h: Int, v: Int, suggestType: FlickSuggestType) -> FlickSuggestView { let model = self.keyModels[h][v] let size: CGSize if model is FlickEnterKeyModel { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift index f873e0ea..3157b215 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift @@ -11,7 +11,6 @@ import Foundation import KeyboardThemes import SwiftUI -// M:基本は変わらない struct FlickKeyModel: FlickKeyModelProtocol { static var delete: Self { Self(labelType: .image("delete.left"), pressActions: [.delete(1)], longPressActions: .init(repeat: [.delete(1)]), flickKeys: [ .left: FlickedKeyModel( diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift index 5a59aa2d..eeee76d3 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift @@ -52,10 +52,10 @@ public struct FlickKeyView: Animation.easeIn(duration: 0.1).delay(0.5) } - private func getSuggestState() -> FlickSuggestState.SuggestType? { + private func getSuggestState() -> FlickSuggestType? { self.suggestState.items[self.position.x, default: [:]][self.position.y] } - private func setSuggestState(_ state: FlickSuggestState.SuggestType?) { + private func setSuggestState(_ state: FlickSuggestType?) { self.suggestState.items[self.position.x, default: [:]][self.position.y] = state } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift new file mode 100644 index 00000000..4e226b1f --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift @@ -0,0 +1,12 @@ +// +// FlickSuggestState.swift +// +// +// Created by miwa on 2023/08/20. +// + + +struct FlickSuggestState: Equatable, Hashable, Sendable { + /// 横:縦:サジェストタイプ + var items: [Int: [Int: FlickSuggestType]] = [:] +} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift new file mode 100644 index 00000000..0895295c --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift @@ -0,0 +1,15 @@ +// +// FlickSuggestType.swift +// +// +// Created by miwa on 2023/08/20. +// + +import enum CustardKit.FlickDirection + +public enum FlickSuggestType: Equatable, Hashable, Sendable { + /// all suggest is shown + case all + /// suggest is only shown to the direction + case flick(FlickDirection) +} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift new file mode 100644 index 00000000..9d583299 --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -0,0 +1,86 @@ +// +// FlickSuggestView.swift +// KeyboardViews +// +// Created by ensan on 2020/04/10. +// Copyright © 2020 ensan. All rights reserved. +// + +import CustardKit +import Foundation +import SwiftUI + + +struct FlickSuggestView: View { + @EnvironmentObject private var variableStates: VariableStates + @Environment(Extension.Theme.self) private var theme + private let model: any FlickKeyModelProtocol + private let suggestType: FlickSuggestType + private let tabDesign: TabDependentDesign + private let size: CGSize + + init(model: any FlickKeyModelProtocol, tabDesign: TabDependentDesign, size: CGSize, suggestType: FlickSuggestType) { + self.model = model + self.tabDesign = tabDesign + self.size = size + self.suggestType = suggestType + } + + private func getSuggestView(for model: FlickedKeyModel, isHidden: Bool, isPointed: Bool = false) -> some View { + var pointedColor: Color { + theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray4 + } + var unpointedColor: Color { + theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray5 + } + + let color = isPointed ? pointedColor : unpointedColor + return RoundedRectangle(cornerRadius: 5.0) + .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth) + .frame(width: size.width, height: size.height) + .overlay { + // ラベル + KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color ?? .black) + } + .allowsHitTesting(false) + .opacity(isHidden ? 0 : 1) + } + + /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 + @ViewBuilder private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { + switch self.suggestType { + case .all: + if let model = self.model.flickKeys(variableStates: variableStates)[direction] { + getSuggestView(for: model, isHidden: false) + } else { + getSuggestView(for: .empty, isHidden: true) + } + case .flick(let targetDirection): + if targetDirection == direction, let model = self.model.flickKeys(variableStates: variableStates)[direction] { + getSuggestView(for: model, isHidden: false, isPointed: true) + } else { + getSuggestView(for: .empty, isHidden: true) + } + } + } + + var body: some View { + VStack(spacing: tabDesign.verticalSpacing) { + self.getSuggestViewIfNecessary(direction: .top) + HStack(spacing: tabDesign.horizontalSpacing) { + self.getSuggestViewIfNecessary(direction: .left) + RoundedRectangle(cornerRadius: 5.0) + .strokeAndFill( + fillContent: theme.specialKeyFillColor.color, + strokeContent: theme.borderColor.color, + lineWidth: theme.borderWidth + ) + .frame(width: size.width, height: size.height) + self.getSuggestViewIfNecessary(direction: .right) + } + self.getSuggestViewIfNecessary(direction: .bottom) + } + .frame(width: size.width, height: size.height) + .allowsHitTesting(false) + } +} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift index 38b764b1..a89d3ba6 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickedKeyModel.swift @@ -1,34 +1,13 @@ // -// FlickedView.swift -// Keyboard +// FlickedKeyModel.swift +// KeyboardViews // // Created by ensan on 2020/04/11. // Copyright © 2020 ensan. All rights reserved. // -import CustardKit -import Foundation -import KeyboardThemes -import SwiftUI -import SwiftUIUtils - -extension FlickDirection: CustomStringConvertible { - public var description: String { - switch self { - case .left: - return "左" - case .top: - return "上" - case .right: - return "右" - case .bottom: - return "下" - } - } -} - public struct FlickedKeyModel { - static var zero: Self { FlickedKeyModel(labelType: .text(""), pressActions: []) } + static var empty: Self { FlickedKeyModel(labelType: .text(""), pressActions: []) } let labelType: KeyLabelType let pressActions: [ActionType] let longPressActions: LongpressActionType @@ -38,28 +17,4 @@ public struct FlickedKeyModel { self.pressActions = pressActions self.longPressActions = longPressActions } - - @MainActor func getSuggestView(size: CGSize, isHidden: Bool, isPointed: Bool = false, theme: Extension.Theme, extension: Extension.Type) -> some View { - var pointedColor: Color { - theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray4 - } - var unpointedColor: Color { - theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray5 - } - - let color = isPointed ? pointedColor : unpointedColor - return RoundedRectangle(cornerRadius: 5.0) - .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth) - .frame(width: size.width, height: size.height) - .overlay(self.label(width: size.width, theme: theme, extension: Extension.self)) - .allowsHitTesting(false) - .opacity(isHidden ? 0 : 1) - } - - @MainActor func label(width: CGFloat, theme: Extension.Theme, extension: Extension.Type) -> some View { - if theme != Extension.ThemeExtension.default(layout: .flick) { - return KeyLabel(self.labelType, width: width, textColor: .black) - } - return KeyLabel(self.labelType, width: width) - } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/SuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/SuggestView.swift deleted file mode 100644 index 1cc18ac1..00000000 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/SuggestView.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// SuggestView.swift -// azooKey -// -// Created by ensan on 2020/04/10. -// Copyright © 2020 ensan. All rights reserved. -// - -import CustardKit -import Foundation -import SwiftUI - -struct FlickSuggestState { - enum SuggestType { - case all - case flick(FlickDirection) - } - var items: [Int: [Int: SuggestType]] = [:] -} - -struct FlickSuggestView: View { - @EnvironmentObject private var variableStates: VariableStates - @Environment(Extension.Theme.self) private var theme - private let model: any FlickKeyModelProtocol - private let suggestType: FlickSuggestState.SuggestType - private let tabDesign: TabDependentDesign - private let size: CGSize - - init(model: any FlickKeyModelProtocol, tabDesign: TabDependentDesign, size: CGSize, suggestType: FlickSuggestState.SuggestType) { - self.model = model - self.tabDesign = tabDesign - self.size = size - self.suggestType = suggestType - } - - private func neededAppearView(direction: FlickDirection) -> some View { - if case .flick(direction) = self.suggestType { - if let model = self.model.flickKeys(variableStates: variableStates)[direction] { - return model.getSuggestView(size: size, isHidden: false, isPointed: true, theme: theme, extension: Extension.self) - } else { - return FlickedKeyModel.zero.getSuggestView(size: size, isHidden: true, theme: theme, extension: Extension.self) - } - } - if case .all = self.suggestType { - if let model = self.model.flickKeys(variableStates: variableStates)[direction] { - return model.getSuggestView(size: size, isHidden: false, theme: theme, extension: Extension.self) - } else { - return FlickedKeyModel.zero.getSuggestView(size: size, isHidden: true, theme: theme, extension: Extension.self) - } - } - return FlickedKeyModel.zero.getSuggestView(size: size, isHidden: true, theme: theme, extension: Extension.self) - } - - var body: some View { - VStack(spacing: tabDesign.verticalSpacing) { - self.neededAppearView(direction: .top) - HStack(spacing: tabDesign.horizontalSpacing) { - self.neededAppearView(direction: .left) - RoundedRectangle(cornerRadius: 5.0) - .strokeAndFill( - fillContent: theme.specialKeyFillColor.color, - strokeContent: theme.borderColor.color, - lineWidth: theme.borderWidth - ) - .frame(width: size.width, height: size.height) - self.neededAppearView(direction: .right) - } - self.neededAppearView(direction: .bottom) - } - .frame(width: size.width, height: size.height) - .allowsHitTesting(false) - } -} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift new file mode 100644 index 00000000..8f850f0b --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift @@ -0,0 +1,23 @@ +// +// extension FlickDirection.swift +// +// +// Created by miwa on 2023/08/20. +// + +import enum CustardKit.FlickDirection + +extension FlickDirection: CustomStringConvertible { + public var description: String { + switch self { + case .left: + return "左" + case .top: + return "上" + case .right: + return "右" + case .bottom: + return "下" + } + } +} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift index ade4b9e6..c55d9a64 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift @@ -40,11 +40,6 @@ struct QwertyVariationsView } @MainActor private func getLabel(_ labelType: KeyLabelType) -> KeyLabel { - let width = tabDesign.keyViewWidth - if theme != Extension.ThemeExtension.default(layout: .qwerty) { - return KeyLabel(labelType, width: width, textColor: .black) - } - return KeyLabel(labelType, width: width) + KeyLabel(labelType, width: tabDesign.keyViewWidth, textColor: theme.suggestLabelTextColor?.color ?? .black) } - } From 0db29e6b9253004c2063c3fdfaf417dfe23f75f5 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 21 Aug 2023 00:08:04 +0900 Subject: [PATCH 020/124] Add comment --- .../View/FlickKeyboard/SuggestView/FlickSuggestView.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 9d583299..0b78f6f9 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -27,6 +27,7 @@ struct FlickSuggestView: Vi } private func getSuggestView(for model: FlickedKeyModel, isHidden: Bool, isPointed: Bool = false) -> some View { + // 着せ替えが有効の場合、サジェストの背景色はwhiteにする。 var pointedColor: Color { theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray4 } @@ -40,6 +41,7 @@ struct FlickSuggestView: Vi .frame(width: size.width, height: size.height) .overlay { // ラベル + // 特に指定がなければラベルの色は黒にする KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color ?? .black) } .allowsHitTesting(false) From ec456be4841d12d6c264f6dc415588f01cfe2fcc Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 21 Aug 2023 00:11:03 +0900 Subject: [PATCH 021/124] change default behavior --- .../AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift | 2 ++ .../View/FlickKeyboard/SuggestView/FlickSuggestView.swift | 3 +-- .../View/QwertyKeyboard/KeyView/QwertyVariationsView.swift | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift index bb7a7b64..12dfc39a 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyTheme/AzooKeySpecificTheme.swift @@ -56,6 +56,7 @@ public extension AzooKeyTheme { specialKeyFillColor: .color(Color(.displayP3, red: 0.804, green: 0.808, blue: 0.835)), pushedKeyFillColor: .color(Color(.displayP3, red: 0.929, green: 0.929, blue: 0.945)), suggestKeyFillColor: nil, + suggestLabelTextColor: .color(Color(.displayP3, white: 0, opacity: 1)), keyShadow: nil ) } @@ -75,6 +76,7 @@ extension AzooKeySpecificTheme: ApplicationSpecificKeyboardViewExtensionLayoutDe specialKeyFillColor: .system(.specialKeyColor), pushedKeyFillColor: .system(layout == .qwerty ? .qwertyHighlightedKeyColor : .highlightedKeyColor), suggestKeyFillColor: nil, + suggestLabelTextColor: nil, keyShadow: nil ) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 0b78f6f9..fd488c01 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -41,8 +41,7 @@ struct FlickSuggestView: Vi .frame(width: size.width, height: size.height) .overlay { // ラベル - // 特に指定がなければラベルの色は黒にする - KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color ?? .black) + KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color) } .allowsHitTesting(false) .opacity(isHidden ? 0 : 1) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift index c55d9a64..876d427f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift @@ -40,6 +40,6 @@ struct QwertyVariationsView } @MainActor private func getLabel(_ labelType: KeyLabelType) -> KeyLabel { - KeyLabel(labelType, width: tabDesign.keyViewWidth, textColor: theme.suggestLabelTextColor?.color ?? .black) + KeyLabel(labelType, width: tabDesign.keyViewWidth, textColor: theme.suggestLabelTextColor?.color) } } From e160e09326fb69fbaaa64f5ee18c99da061a0b3e Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 21 Aug 2023 00:15:28 +0900 Subject: [PATCH 022/124] =?UTF-8?q?=E3=83=9E=E3=82=A4=E3=82=B0=E3=83=AC?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift index bc116883..938c2d3e 100644 --- a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift +++ b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift @@ -79,7 +79,8 @@ public struct ThemeData: Codable self.specialKeyFillColor = try container.decode(ColorData.self, forKey: .specialKeyFillColor) self.pushedKeyFillColor = try container.decode(ColorData.self, forKey: .pushedKeyFillColor) self.suggestKeyFillColor = try? container.decode(ColorData?.self, forKey: .suggestKeyFillColor) - self.suggestLabelTextColor = try? container.decode(ColorData?.self, forKey: .suggestLabelTextColor) + /// エントリがない場合はデフォルトで黒にする + self.suggestLabelTextColor = (try? container.decode(ColorData?.self, forKey: .suggestLabelTextColor)) ?? .color(Color(white: 0)) self.keyShadow = try? container.decode(ThemeShadowData?.self, forKey: .keyShadow) } From 424361de20f8d26e7e0f1696cc1c33af21b9460d Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 27 Aug 2023 10:01:55 +0900 Subject: [PATCH 023/124] Update destination --- .../xcshareddata/xcschemes/Keyboard.xcscheme | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/azooKey.xcodeproj/xcshareddata/xcschemes/Keyboard.xcscheme b/azooKey.xcodeproj/xcshareddata/xcschemes/Keyboard.xcscheme index 7f3f7773..6f0368d6 100644 --- a/azooKey.xcodeproj/xcshareddata/xcschemes/Keyboard.xcscheme +++ b/azooKey.xcodeproj/xcshareddata/xcschemes/Keyboard.xcscheme @@ -2,7 +2,7 @@ + version = "2.0"> @@ -50,15 +50,17 @@ selectedDebuggerIdentifier = "" selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn" launchStyle = "0" + askForAppToLaunch = "Yes" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" - allowLocationSimulation = "YES"> + allowLocationSimulation = "YES" + launchAutomaticallySubstyle = "2"> + RemotePath = "/var/containers/Bundle/Application/427FC692-DDE1-43EB-A5AE-9921EF0B0EA8/MobileNotes.app"> Date: Sun, 27 Aug 2023 10:02:23 +0900 Subject: [PATCH 024/124] Fix ExistentialAny error --- .../View/QwertyKeyboard/KeyView/QwertyKeyView.swift | 2 +- Keyboard/Display/KeyboardActionManager.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index d59ef845..68fcfa9d 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -104,7 +104,7 @@ struct QwertyKeyView: View @State private var doublePressState = QwertyKeyDoublePressState() @State private var suggest = false - @State private var longPressStartTask: Task<(), Error>? = nil + @State private var longPressStartTask: Task<(), any Error>? = nil @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 564a14c5..d7779871 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -20,7 +20,7 @@ import SwiftUtils private unowned var delegate: KeyboardViewController! // 即時変数 - private var tasks: [(type: LongpressActionType, task: Task)] = [] + private var tasks: [(type: LongpressActionType, task: Task)] = [] private var tempTextData: (left: String, center: String, right: String)? // キーボードを閉じる際に呼び出す From 167c5cbe0c2b0eaf82908c56591f3e30586336d0 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 28 Aug 2023 01:32:38 +0900 Subject: [PATCH 025/124] Support Reconversion in general case by CFStringTokenizer --- Keyboard/Display/InputManager.swift | 40 +++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 753079ab..3e48ef9c 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -698,6 +698,41 @@ import UIKit self.stopComposition() } + // Reference: https://teratail.com/questions/57039?link=qa_related_pc + func getReadingFromSystemAPI(_ text: String) -> String { + let inputText = text as NSString + let outputText = NSMutableString() + + // トークナイザ + let tokenizer: CFStringTokenizer = CFStringTokenizerCreate( + kCFAllocatorDefault, + inputText as CFString, + CFRangeMake(0, inputText.length), + kCFStringTokenizerUnitWordBoundary, + CFLocaleCopyCurrent() + ) + + // 形態素解析した結果を順に得る + var tokenType: CFStringTokenizerTokenType = CFStringTokenizerGoToTokenAtIndex(tokenizer, 0) + while tokenType.rawValue != 0 { + let range = CFStringTokenizerGetCurrentTokenRange(tokenizer) + let original = inputText.substring(with: NSRange(location: range.location, length: range.length)) + if original.isEnglishSentence { + outputText.append(original) + } else if let romaji = CFStringTokenizerCopyCurrentTokenAttribute(tokenizer, kCFStringTokenizerAttributeLatinTranscription) as? NSString { + // ローマ字をまず得て、そのあとでカタカナにする + let reading: NSMutableString = romaji.mutableCopy() as! NSMutableString + CFStringTransform(reading as CFMutableString, nil, kCFStringTransformLatinKatakana, false) + outputText.append(reading as String) + } else { + // タイ語の文字など扱えない文字が入ってくるとここに来うる + outputText.append(original) + } + tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer) + } + return outputText as String + } + // ユーザが文章を選択した場合、その部分を入力中であるとみなす(再変換) func userSelectedText(text: String) { if text.isEmpty { @@ -721,11 +756,12 @@ import UIKit // 過去のログを見て、再変換に利用する self.composingText.stopComposition() if let ruby = self.getRubyIfPossible(text: text) { - debug("Evaluated ruby:", ruby) + let ruby = getReadingFromSystemAPI(ruby) // rubyはひらがなである self.composingText.insertAtCursorPosition(ruby, inputStyle: .direct) } else { - self.composingText.insertAtCursorPosition(text, inputStyle: .direct) + let ruby = getReadingFromSystemAPI(text) + self.composingText.insertAtCursorPosition(ruby, inputStyle: .direct) } self.isSelected = true From 0bba07a82aa943eb2737def5904d469458656376 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 31 Aug 2023 19:23:04 +0900 Subject: [PATCH 026/124] Simplify dependency structure --- azooKey.xcodeproj/project.pbxproj | 41 ------------------------------- 1 file changed, 41 deletions(-) diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index f5cf5252..ca5a733b 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -82,10 +82,6 @@ 1A606B06292E53BA00CEDB15 /* CustardExpressionEvaluator in Frameworks */ = {isa = PBXBuildFile; productRef = 1A606B05292E53BA00CEDB15 /* CustardExpressionEvaluator */; }; 1A606B08292E53C500CEDB15 /* CustardExpressionEvaluator in Frameworks */ = {isa = PBXBuildFile; productRef = 1A606B07292E53C500CEDB15 /* CustardExpressionEvaluator */; }; 1A61E8F028CCD93000C5107A /* FlickSensitivitySettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A61E8EF28CCD93000C5107A /* FlickSensitivitySettingView.swift */; }; - 1A62CB472A6D0856005DBBCE /* KanaKanjiConverterModule in Frameworks */ = {isa = PBXBuildFile; productRef = 1A62CB462A6D0856005DBBCE /* KanaKanjiConverterModule */; }; - 1A62CB492A6D0856005DBBCE /* SwiftUtils in Frameworks */ = {isa = PBXBuildFile; productRef = 1A62CB482A6D0856005DBBCE /* SwiftUtils */; }; - 1A62CB4B2A6D0866005DBBCE /* KanaKanjiConverterModule in Frameworks */ = {isa = PBXBuildFile; productRef = 1A62CB4A2A6D0866005DBBCE /* KanaKanjiConverterModule */; }; - 1A62CB4D2A6D0866005DBBCE /* SwiftUtils in Frameworks */ = {isa = PBXBuildFile; productRef = 1A62CB4C2A6D0866005DBBCE /* SwiftUtils */; }; 1A64A897257B4AFD0022C081 /* UpdateInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A64A896257B4AFD0022C081 /* UpdateInformationView.swift */; }; 1A64A8BD257B55360022C081 /* AzooKeyUserDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A64A8BC257B55360022C081 /* AzooKeyUserDictionary.swift */; }; 1A64A8CF257C7F760022C081 /* ConjunctionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A64A8CE257C7F760022C081 /* ConjunctionBuilder.swift */; }; @@ -381,12 +377,10 @@ 1A70DFFD291F2D1E00A83849 /* CustardKit in Frameworks */, 1A7F37832A69874C009AC382 /* KeyboardThemes in Frameworks */, 1A73F21229C0B36D00833C11 /* OrderedCollections in Frameworks */, - 1A62CB492A6D0856005DBBCE /* SwiftUtils in Frameworks */, 1A7F37742A683428009AC382 /* SwiftUIUtils in Frameworks */, 1AF306022A00070000B4DAC3 /* KanaKanjiConverterModule in Frameworks */, 1A7F37882A6A1A90009AC382 /* KeyboardViews in Frameworks */, 1AED0A5F2A6D22C3005B87E5 /* AzooKeyUtils in Frameworks */, - 1A62CB472A6D0856005DBBCE /* KanaKanjiConverterModule in Frameworks */, 1A606B06292E53BA00CEDB15 /* CustardExpressionEvaluator in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -413,12 +407,10 @@ 1A7F378A2A6A1A99009AC382 /* KeyboardViews in Frameworks */, 1A70DFFF291F2D3B00A83849 /* CustardKit in Frameworks */, 1A8E454A28E5711800133D3B /* OrderedCollections in Frameworks */, - 1A62CB4D2A6D0866005DBBCE /* SwiftUtils in Frameworks */, 1A9E908F2822CEC100E73846 /* DequeModule in Frameworks */, 1A7F37812A698741009AC382 /* KeyboardThemes in Frameworks */, 1AD96FB82A22F9C800FD4EA4 /* SwiftUIUtils in Frameworks */, 1AED0A612A6D22CB005B87E5 /* AzooKeyUtils in Frameworks */, - 1A62CB4B2A6D0866005DBBCE /* KanaKanjiConverterModule in Frameworks */, 1A606B08292E53C500CEDB15 /* CustardExpressionEvaluator in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -977,8 +969,6 @@ 1A7F37732A683428009AC382 /* SwiftUIUtils */, 1A7F37822A69874C009AC382 /* KeyboardThemes */, 1A7F37872A6A1A90009AC382 /* KeyboardViews */, - 1A62CB462A6D0856005DBBCE /* KanaKanjiConverterModule */, - 1A62CB482A6D0856005DBBCE /* SwiftUtils */, 1AED0A5E2A6D22C3005B87E5 /* AzooKeyUtils */, ); productName = MainApp; @@ -1047,8 +1037,6 @@ 1AD96FB72A22F9C800FD4EA4 /* SwiftUIUtils */, 1A7F37802A698741009AC382 /* KeyboardThemes */, 1A7F37892A6A1A99009AC382 /* KeyboardViews */, - 1A62CB4A2A6D0866005DBBCE /* KanaKanjiConverterModule */, - 1A62CB4C2A6D0866005DBBCE /* SwiftUtils */, 1AED0A602A6D22CB005B87E5 /* AzooKeyUtils */, ); productName = Keyboard; @@ -1099,7 +1087,6 @@ 1A9E908A2822CEB400E73846 /* XCRemoteSwiftPackageReference "swift-collections" */, 1A70DFFB291F2D1E00A83849 /* XCRemoteSwiftPackageReference "CustardKit" */, 1A606B00292E506200CEDB15 /* XCRemoteSwiftPackageReference "BoolExpressionEvaluator" */, - 1A62CB452A6D0856005DBBCE /* XCRemoteSwiftPackageReference "AzooKeyKanaKanjiConverter" */, ); productRefGroup = 1A3DC1C32500D44A002CAA93 /* Products */; projectDirPath = ""; @@ -1928,14 +1915,6 @@ kind = branch; }; }; - 1A62CB452A6D0856005DBBCE /* XCRemoteSwiftPackageReference "AzooKeyKanaKanjiConverter" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter"; - requirement = { - branch = develop; - kind = branch; - }; - }; 1A70DFFB291F2D1E00A83849 /* XCRemoteSwiftPackageReference "CustardKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ensan-hcl/CustardKit"; @@ -1969,26 +1948,6 @@ package = 1A606B00292E506200CEDB15 /* XCRemoteSwiftPackageReference "BoolExpressionEvaluator" */; productName = CustardExpressionEvaluator; }; - 1A62CB462A6D0856005DBBCE /* KanaKanjiConverterModule */ = { - isa = XCSwiftPackageProductDependency; - package = 1A62CB452A6D0856005DBBCE /* XCRemoteSwiftPackageReference "AzooKeyKanaKanjiConverter" */; - productName = KanaKanjiConverterModule; - }; - 1A62CB482A6D0856005DBBCE /* SwiftUtils */ = { - isa = XCSwiftPackageProductDependency; - package = 1A62CB452A6D0856005DBBCE /* XCRemoteSwiftPackageReference "AzooKeyKanaKanjiConverter" */; - productName = SwiftUtils; - }; - 1A62CB4A2A6D0866005DBBCE /* KanaKanjiConverterModule */ = { - isa = XCSwiftPackageProductDependency; - package = 1A62CB452A6D0856005DBBCE /* XCRemoteSwiftPackageReference "AzooKeyKanaKanjiConverter" */; - productName = KanaKanjiConverterModule; - }; - 1A62CB4C2A6D0866005DBBCE /* SwiftUtils */ = { - isa = XCSwiftPackageProductDependency; - package = 1A62CB452A6D0856005DBBCE /* XCRemoteSwiftPackageReference "AzooKeyKanaKanjiConverter" */; - productName = SwiftUtils; - }; 1A70DFFC291F2D1E00A83849 /* CustardKit */ = { isa = XCSwiftPackageProductDependency; package = 1A70DFFB291F2D1E00A83849 /* XCRemoteSwiftPackageReference "CustardKit" */; From e6ba322454b47adaddb234e139df716790af743f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 5 Sep 2023 19:35:08 +0900 Subject: [PATCH 027/124] Fix build errors due to update on AzooKeyKanaKanjiConverter --- Keyboard/Display/InputManager.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 753079ab..ac6a8df6 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -248,7 +248,7 @@ import UIKit ] ) } - let actions = self.kanaKanjiConverter.getApporopriateActions(candidate) + let actions = self.kanaKanjiConverter.getAppropriateActions(candidate) candidate.withActions(actions) candidate.parseTemplate() self.updateLog(candidate: candidate) @@ -786,9 +786,7 @@ import UIKit ) debug("InputManager.setResult: options", options) - let results: [Candidate] - let firstClauseResults: [Candidate] - (results, firstClauseResults) = self.kanaKanjiConverter.requestCandidates(inputData, options: options) + let results = self.kanaKanjiConverter.requestCandidates(inputData, options: options) // 表示を更新する if !self.isSelected { @@ -796,7 +794,7 @@ import UIKit self.previousSystemOperation = .setMarkedText } if liveConversionEnabled { - let liveConversionText = self.liveConversionManager.updateWithNewResults(inputData, results, firstClauseResults: firstClauseResults, convertTargetCursorPosition: inputData.convertTargetCursorPosition, convertTarget: inputData.convertTarget) + let liveConversionText = self.liveConversionManager.updateWithNewResults(inputData, results.mainResults, firstClauseResults: results.firstClauseResults, convertTargetCursorPosition: inputData.convertTargetCursorPosition, convertTarget: inputData.convertTarget) self.displayedTextManager.updateComposingText(composingText: self.composingText, newLiveConversionText: liveConversionText) } else { self.displayedTextManager.updateComposingText(composingText: self.composingText, newLiveConversionText: nil) @@ -804,7 +802,7 @@ import UIKit } if let updateResult { - updateResult(results) + updateResult(results.mainResults) // 自動確定の実施 if liveConversionEnabled, let firstClause = self.liveConversionManager.candidateForCompleteFirstClause() { debug("InputManager.setResult: Complete first clause", firstClause) From b3024a7ada9d77c9f49d3e5777e02d11bdff6919 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 5 Sep 2023 22:52:43 +0900 Subject: [PATCH 028/124] Fix an issue that ruby is katakana --- Keyboard/Display/InputManager.swift | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 3e48ef9c..2bb97530 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -730,7 +730,7 @@ import UIKit } tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer) } - return outputText as String + return (outputText as String).toHiragana() } // ユーザが文章を選択した場合、その部分を入力中であるとみなす(再変換) @@ -755,14 +755,8 @@ import UIKit } // 過去のログを見て、再変換に利用する self.composingText.stopComposition() - if let ruby = self.getRubyIfPossible(text: text) { - let ruby = getReadingFromSystemAPI(ruby) - // rubyはひらがなである - self.composingText.insertAtCursorPosition(ruby, inputStyle: .direct) - } else { - let ruby = getReadingFromSystemAPI(text) - self.composingText.insertAtCursorPosition(ruby, inputStyle: .direct) - } + let ruby = getReadingFromSystemAPI(self.getRubyIfPossible(text: text) ?? text) + self.composingText.insertAtCursorPosition(ruby, inputStyle: .direct) self.isSelected = true self.setResult() From cd7c338cecfcbda437e33fb74fda18e519dc5a2c Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 9 Sep 2023 18:03:57 +0900 Subject: [PATCH 029/124] Remove 'edit' feature --- .../Sources/KeyboardViews/Action.swift | 2 -- .../Sources/KeyboardViews/ActionUtils.swift | 2 +- .../Sources/KeyboardViews/Design.swift | 2 -- .../Sources/KeyboardViews/States.swift | 2 -- .../KeyboardViews/VariableStates.swift | 2 -- .../SimpleKeyView/SimpleKeyModel.swift | 6 ++-- .../KeyView/FlickEnterKeyModel.swift | 6 ++-- .../KeyView/QwertyEnterKeyModel.swift | 4 +-- .../KeyView/QwertyKeyModelProtocol.swift | 2 +- Keyboard/Display/InputManager.swift | 34 +++++++++---------- Keyboard/Display/KeyboardActionManager.swift | 4 --- 11 files changed, 23 insertions(+), 43 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/Action.swift b/AzooKeyCore/Sources/KeyboardViews/Action.swift index cc12dc1a..0ca7d7e1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/Action.swift +++ b/AzooKeyCore/Sources/KeyboardViews/Action.swift @@ -28,8 +28,6 @@ public indirect enum ActionType: Equatable, Sendable { /// - note: フルアクセスがない場合動作しない case paste - case deselectAndUseAsInputting // 選択を解除して編集中とみなす - // カーソル関係 case moveCursor(Int) case smartMoveCursor(ScanItem) diff --git a/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift b/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift index 55f8dc82..d2449242 100644 --- a/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift +++ b/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift @@ -97,7 +97,7 @@ public extension ActionType { KeyboardFeedback.smoothDelete() case .moveTab, .enter, .changeCharacterType, .setCursorBar, .moveCursor, .enableResizingMode, .replaceLastCharacters, .setTabBar, .setBoolState, .setUpsideComponent, .setSearchQuery/*, ._setBoolState*/: KeyboardFeedback.tabOrOtherKey() - case .deselectAndUseAsInputting, .openApp, .dismissKeyboard, .hideLearningMemory: + case .openApp, .dismissKeyboard, .hideLearningMemory: return case let .boolSwitch(compiledExpression, trueAction, falseAction): if let condition = variableStates.boolStates.evaluateExpression(compiledExpression) { diff --git a/AzooKeyCore/Sources/KeyboardViews/Design.swift b/AzooKeyCore/Sources/KeyboardViews/Design.swift index fd865cde..eddb7661 100644 --- a/AzooKeyCore/Sources/KeyboardViews/Design.swift +++ b/AzooKeyCore/Sources/KeyboardViews/Design.swift @@ -409,8 +409,6 @@ public enum Design { @unknown default: return "改行" } - case .edit: - return "編集" } } } diff --git a/AzooKeyCore/Sources/KeyboardViews/States.swift b/AzooKeyCore/Sources/KeyboardViews/States.swift index 835b6bd5..ae86577c 100644 --- a/AzooKeyCore/Sources/KeyboardViews/States.swift +++ b/AzooKeyCore/Sources/KeyboardViews/States.swift @@ -44,14 +44,12 @@ public enum KeyboardOrientation: Sendable { public enum RoughEnterKeyState: Sendable { case `return` - case edit case complete } public enum EnterKeyState: Sendable { case complete // 決定 case `return`(UIReturnKeyType) // 改行 - case edit // 編集 } public enum BarState: Sendable { diff --git a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift index 6eb11fd1..f7e94a68 100644 --- a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift +++ b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift @@ -246,8 +246,6 @@ public final class VariableStates: ObservableObject { switch state { case .return: self.enterKeyState = .return(enterKeyType) - case .edit: - self.enterKeyState = .edit case .complete: self.enterKeyState = .complete } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift index 14f7e93a..3ade17fd 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift @@ -29,7 +29,7 @@ enum SimpleUnpressedKeyColorType: UInt8 { return Color(white: 0, opacity: 0.001) case .enter: switch states.enterKeyState { - case .complete, .edit: + case .complete: return theme.specialKeyFillColor.color case let .return(type): switch type { @@ -103,8 +103,6 @@ struct SimpleEnterKeyModel: return [.enter] case .return: return [.input("\n")] - case .edit: - return [.deselectAndUseAsInputting] } } @@ -117,7 +115,7 @@ struct SimpleEnterKeyModel: func feedback(variableStates: VariableStates) { switch variableStates.enterKeyState { - case .complete, .edit: + case .complete: KeyboardFeedback.tabOrOtherKey() case .return: KeyboardFeedback.click() diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift index cb9c8be9..44082bc1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift @@ -21,8 +21,6 @@ struct FlickEnterKeyModel: return [.enter] case .return: return [.input("\n")] - case .edit: - return [.deselectAndUseAsInputting] } } @@ -39,7 +37,7 @@ struct FlickEnterKeyModel: func backGroundColorWhenUnpressed(states: VariableStates, theme: ThemeData) -> Color { switch states.enterKeyState { - case .complete, .edit: + case .complete: return theme.specialKeyFillColor.color case let .return(type): switch type { @@ -57,7 +55,7 @@ struct FlickEnterKeyModel: func feedback(variableStates: VariableStates) { switch variableStates.enterKeyState { - case .complete, .edit: + case .complete: KeyboardFeedback.tabOrOtherKey() case let .return(type): switch type { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift index a29f3d35..50faca4e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift @@ -27,8 +27,6 @@ struct QwertyEnterKeyModel: return [.enter] case .return: return [.input("\n")] - case .edit: - return [.deselectAndUseAsInputting] } } @@ -43,7 +41,7 @@ struct QwertyEnterKeyModel: func feedback(variableStates: VariableStates) { switch variableStates.enterKeyState { - case .complete, .edit: + case .complete: KeyboardFeedback.tabOrOtherKey() case let .return(type): switch type { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift index 435dfa44..d8bda6e1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift @@ -62,7 +62,7 @@ enum QwertyUnpressedKeyColorType: Sendable { return Color(white: 0, opacity: 0.001) case .enter: switch states.enterKeyState { - case .complete, .edit: + case .complete: return theme.specialKeyFillColor.color case let .return(type): switch type { diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 2a8e2efb..296221b4 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -52,9 +52,7 @@ import UIKit } func getEnterKeyState() -> RoughEnterKeyState { - if self.isSelected && !self.composingText.isEmpty { - return .edit - } else if !self.composingText.isEmpty { + if !self.isSelected && !self.composingText.isEmpty { return .complete } else { return .return @@ -227,8 +225,12 @@ import UIKit /// - parameters: /// - shouldModifyDisplayedText: DisplayedTextを操作して良いか否か。`textDidChange`などの場合は操作してはいけない。 func enter(shouldModifyDisplayedText: Bool = true) -> [ActionType] { + // selectedの場合、単に変換を止める + if isSelected { + self.stopComposition() + return [] + } var candidate: Candidate - // ライブ変換中に確定する場合、現在表示されているテキストそのものが候補となる。 if liveConversionEnabled, let _candidate = liveConversionManager.lastUsedCandidate { candidate = _candidate } else { @@ -284,10 +286,6 @@ import UIKit /// - simpleInsert: `ComposingText`を作るのではなく、直接文字を入力し、変換候補を表示しない。 /// - inputStyle: 入力スタイル func input(text: String, requireSetResult: Bool = true, simpleInsert: Bool = false, inputStyle: InputStyle) { - if self.isSelected { - // 選択部分を削除する - self.deleteSelection() - } // 直接入力の条件 if simpleInsert // flag || text == "\n" // 改行 @@ -295,10 +293,19 @@ import UIKit || self.keyboardLanguage == .none // 言語がnone { // 必要に応じて確定する - _ = self.enter() + if !self.isSelected { + _ = self.enter() + } else { + self.stopComposition() + } self.displayedTextManager.insertText(text) return } + // 直接入力にならない場合はまず選択部分を削除する + if self.isSelected { + // 選択部分を削除する + self.deleteSelection() + } self.composingText.insertAtCursorPosition(text, inputStyle: inputStyle) debug("Input Manager input:", composingText) if requireSetResult { @@ -554,15 +561,6 @@ import UIKit return left } - /// 選択状態にあるテキストを再度入力し、編集可能な状態にする - func edit() { - if isSelected { - let selectedText = composingText.convertTarget - self.stopComposition() - self.input(text: selectedText, inputStyle: .direct) - } - } - /// クリップボードの文字列をペーストする func paste() { guard let text = UIPasteboard.general.string else { diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index d7779871..a40341cb 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -147,10 +147,6 @@ import SwiftUtils self.inputManager.paste() } - case .deselectAndUseAsInputting: - self.shiftStateOff(variableStates: variableStates) - self.inputManager.edit() - case let .moveCursor(count): // カーソル移動ではシフトを解除しない self.inputManager.moveCursor(count: count, requireSetResult: requireSetResult) From 8c335f86f8d19e733197a352bc70bf7f135c179a Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 9 Sep 2023 18:44:40 +0900 Subject: [PATCH 030/124] =?UTF-8?q?FlickKeyboardView=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E8=A3=85=E3=82=92CustardFlickKeysView=E3=81=A7=E7=BD=AE?= =?UTF-8?q?=E3=81=8D=E6=8F=9B=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FlickKeyboard/FlickKeyboardView.swift | 63 ++++--------------- 1 file changed, 12 insertions(+), 51 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift index efff5fca..2b9eac2b 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift @@ -14,63 +14,24 @@ struct FlickKeyboardView: V @State private var suggestState = FlickSuggestState() private let tabDesign: TabDependentDesign - private let keyModels: [[any FlickKeyModelProtocol]] + private let models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)] init(keyModels: [[any FlickKeyModelProtocol]], interfaceSize: CGSize, keyboardOrientation: KeyboardOrientation) { - self.keyModels = keyModels self.tabDesign = TabDependentDesign(width: 5, height: 4, interfaceSize: interfaceSize, layout: .flick, orientation: keyboardOrientation) - } - - private var horizontalIndices: Range { - keyModels.indices - } - - private func verticalIndices(h: Int) -> Range { - keyModels[h].indices - } - - @MainActor private func keyView(h: Int, v: Int) -> FlickKeyView { - let model = self.keyModels[h][v] - let size: CGSize - if model is FlickEnterKeyModel { - size = CGSize(width: tabDesign.keyViewWidth, height: tabDesign.keyViewHeight(heightCount: 2)) - } else { - size = tabDesign.keyViewSize - } - return FlickKeyView(model: model, size: size, position: (x: h, y: v), suggestState: $suggestState) - } - - @MainActor - private func suggestView(h: Int, v: Int, suggestType: FlickSuggestType) -> FlickSuggestView { - let model = self.keyModels[h][v] - let size: CGSize - if model is FlickEnterKeyModel { - size = CGSize(width: tabDesign.keyViewWidth, height: tabDesign.keyViewHeight(heightCount: 2)) - } else { - size = tabDesign.keyViewSize + + var models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)] = [:] + for h in keyModels.indices { + for v in keyModels[h].indices { + let model = keyModels[h][v] + models[KeyPosition.gridFit(x: h, y: v)] = (keyModels[h][v], 1, model is FlickEnterKeyModel ? 2 : 1) + } } - return FlickSuggestView(model: model, tabDesign: tabDesign, size: size, suggestType: suggestType) + self.models = models } var body: some View { - ZStack { - HStack(spacing: tabDesign.horizontalSpacing) { - ForEach(self.horizontalIndices, id: \.self) {h in - let columnSuggestStates = self.suggestState.items[h, default: [:]] - VStack(spacing: tabDesign.verticalSpacing) { - ForEach(self.verticalIndices(h: h), id: \.self) {v in - self.keyView(h: h, v: v) - .zIndex(columnSuggestStates[v] != nil ? 1 : 0) - .overlay(alignment: .center) { - if let suggestType = columnSuggestStates[v] { - suggestView(h: h, v: v, suggestType: suggestType) - .zIndex(2) - } - } - } - } - .zIndex(columnSuggestStates.isEmpty ? 0 : 1) - } - } + let layout = CustardInterfaceLayoutGridValue(rowCount: Int(tabDesign.horizontalKeyCount), columnCount: Int(tabDesign.verticalKeyCount)) + CustardFlickKeysView(models: models, tabDesign: tabDesign, layout: layout) {(view: FlickKeyView, _, _) in + view } } } From fc9d471f3a099002153223c99ccdd5749e0dff83 Mon Sep 17 00:00:00 2001 From: nya3_neko2 Date: Fri, 15 Sep 2023 19:53:09 +0900 Subject: [PATCH 031/124] =?UTF-8?q?=E6=A9=9F=E8=83=BD=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard/Display/InputManager.swift | 32 +++++++++----------- Keyboard/Display/KeyboardActionManager.swift | 5 ++- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 296221b4..73f86aa4 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -225,12 +225,8 @@ import UIKit /// - parameters: /// - shouldModifyDisplayedText: DisplayedTextを操作して良いか否か。`textDidChange`などの場合は操作してはいけない。 func enter(shouldModifyDisplayedText: Bool = true) -> [ActionType] { - // selectedの場合、単に変換を止める - if isSelected { - self.stopComposition() - return [] - } var candidate: Candidate + // ライブ変換中に確定する場合、現在表示されているテキストそのものが候補となる。 if liveConversionEnabled, let _candidate = liveConversionManager.lastUsedCandidate { candidate = _candidate } else { @@ -286,6 +282,10 @@ import UIKit /// - simpleInsert: `ComposingText`を作るのではなく、直接文字を入力し、変換候補を表示しない。 /// - inputStyle: 入力スタイル func input(text: String, requireSetResult: Bool = true, simpleInsert: Bool = false, inputStyle: InputStyle) { + if self.isSelected { + // 選択部分を削除する + self.deleteSelection() + } // 直接入力の条件 if simpleInsert // flag || text == "\n" // 改行 @@ -293,19 +293,10 @@ import UIKit || self.keyboardLanguage == .none // 言語がnone { // 必要に応じて確定する - if !self.isSelected { - _ = self.enter() - } else { - self.stopComposition() - } + _ = self.enter() self.displayedTextManager.insertText(text) return } - // 直接入力にならない場合はまず選択部分を削除する - if self.isSelected { - // 選択部分を削除する - self.deleteSelection() - } self.composingText.insertAtCursorPosition(text, inputStyle: inputStyle) debug("Input Manager input:", composingText) if requireSetResult { @@ -680,15 +671,22 @@ import UIKit /// ユーザがキーボードを経由せずにカーソルを何かした場合の後処理を行う関数。 /// - note: この関数をユーティリティとして用いてはいけない。 - func userMovedCursor(count: Int) { + func userMovedCursor(count: Int) -> [ActionType]{ + var actions: [ActionType] = [] debug("userによるカーソル移動を検知、今の位置は\(composingText.convertTargetCursorPosition)、動かしたオフセットは\(count)") if composingText.isEmpty { // 入力がない場合はreturnしておかないと、入力していない時にカーソルを動かせなくなってしまう。 - return + actions.append(.setCursorBar(.on)) + return actions } let actualCount = composingText.moveCursorFromCursorPosition(count: count) self.previousSystemOperation = self.displayedTextManager.updateComposingText(composingText: self.composingText, userMovedCount: count, adjustedMovedCount: actualCount) ? .moveCursor : nil setResult() + // ライブ変換有効 + if liveConversionEnabled{ + actions.append(.setCursorBar(.on)) + } + return actions } /// ユーザがキーボードを経由せずカットした場合の処理 diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index a40341cb..86ca31be 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -539,7 +539,10 @@ import SwiftUtils if !wasSelected && !isSelected && b_left != a_left { debug("user operation id: 2", b_left, a_left) let offset = a_left.count - b_left.count - self.inputManager.userMovedCursor(count: offset) + let actions = self.inputManager.userMovedCursor(count: offset) + for action in actions{ + doAction(action, variableStates: variableStates) + } return } From 53deac88336cd7781d188528dea4c337f53b27c5 Mon Sep 17 00:00:00 2001 From: nya3_neko2 Date: Sun, 17 Sep 2023 15:44:14 +0900 Subject: [PATCH 032/124] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=81=AB=E5=AF=BE=E3=81=97=E3=81=A6=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard/Display/InputManager.swift | 35 ++++++++++++-------- Keyboard/Display/KeyboardActionManager.swift | 5 +-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 73f86aa4..b1023150 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -225,8 +225,12 @@ import UIKit /// - parameters: /// - shouldModifyDisplayedText: DisplayedTextを操作して良いか否か。`textDidChange`などの場合は操作してはいけない。 func enter(shouldModifyDisplayedText: Bool = true) -> [ActionType] { + // selectedの場合、単に変換を止める + if isSelected { + self.stopComposition() + return [] + } var candidate: Candidate - // ライブ変換中に確定する場合、現在表示されているテキストそのものが候補となる。 if liveConversionEnabled, let _candidate = liveConversionManager.lastUsedCandidate { candidate = _candidate } else { @@ -282,10 +286,6 @@ import UIKit /// - simpleInsert: `ComposingText`を作るのではなく、直接文字を入力し、変換候補を表示しない。 /// - inputStyle: 入力スタイル func input(text: String, requireSetResult: Bool = true, simpleInsert: Bool = false, inputStyle: InputStyle) { - if self.isSelected { - // 選択部分を削除する - self.deleteSelection() - } // 直接入力の条件 if simpleInsert // flag || text == "\n" // 改行 @@ -293,10 +293,19 @@ import UIKit || self.keyboardLanguage == .none // 言語がnone { // 必要に応じて確定する - _ = self.enter() + if !self.isSelected { + _ = self.enter() + } else { + self.stopComposition() + } self.displayedTextManager.insertText(text) return } + // 直接入力にならない場合はまず選択部分を削除する + if self.isSelected { + // 選択部分を削除する + self.deleteSelection() + } self.composingText.insertAtCursorPosition(text, inputStyle: inputStyle) debug("Input Manager input:", composingText) if requireSetResult { @@ -671,22 +680,20 @@ import UIKit /// ユーザがキーボードを経由せずにカーソルを何かした場合の後処理を行う関数。 /// - note: この関数をユーティリティとして用いてはいけない。 - func userMovedCursor(count: Int) -> [ActionType]{ - var actions: [ActionType] = [] + func userMovedCursor(count: Int) -> [ActionType] { debug("userによるカーソル移動を検知、今の位置は\(composingText.convertTargetCursorPosition)、動かしたオフセットは\(count)") if composingText.isEmpty { // 入力がない場合はreturnしておかないと、入力していない時にカーソルを動かせなくなってしまう。 - actions.append(.setCursorBar(.on)) - return actions + return [.setCursorBar(.on)] } let actualCount = composingText.moveCursorFromCursorPosition(count: count) self.previousSystemOperation = self.displayedTextManager.updateComposingText(composingText: self.composingText, userMovedCount: count, adjustedMovedCount: actualCount) ? .moveCursor : nil setResult() // ライブ変換有効 - if liveConversionEnabled{ - actions.append(.setCursorBar(.on)) + if liveConversionEnabled { + return [.setCursorBar(.on)] } - return actions + return [] } /// ユーザがキーボードを経由せずカットした場合の処理 @@ -701,7 +708,7 @@ import UIKit // トークナイザ let tokenizer: CFStringTokenizer = CFStringTokenizerCreate( - kCFAllocatorDefault, + kCFAllocatorDefault, inputText as CFString, CFRangeMake(0, inputText.length), kCFStringTokenizerUnitWordBoundary, diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 86ca31be..30d65eb7 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -539,10 +539,7 @@ import SwiftUtils if !wasSelected && !isSelected && b_left != a_left { debug("user operation id: 2", b_left, a_left) let offset = a_left.count - b_left.count - let actions = self.inputManager.userMovedCursor(count: offset) - for action in actions{ - doAction(action, variableStates: variableStates) - } + registerActions(self.inputManager.userMovedCursor(count: offset), variableStates: variableStates) return } From 55f4e91e0d50db89f8514a4387cd01187bf97274 Mon Sep 17 00:00:00 2001 From: nya3_neko2 Date: Sun, 17 Sep 2023 15:57:21 +0900 Subject: [PATCH 033/124] =?UTF-8?q?Swift=20lint=E3=81=A7=E3=81=AE=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=E5=88=86=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard/Display/KeyboardActionManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 30d65eb7..9d03b8e2 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -332,7 +332,7 @@ import SwiftUtils self.registerActions(action.start, variableStates: variableStates) } self.tasks.append((type: action, task: startTask)) - + let repeatTask = Task { try await Task.sleep(nanoseconds: 0_400_000_000) while !Task.isCancelled { From dce0f10ca9ed91a1564c437ad4b83aec5d9f3ce5 Mon Sep 17 00:00:00 2001 From: Miwa / Ensan <63481257+ensan-hcl@users.noreply.github.com> Date: Mon, 18 Sep 2023 00:44:33 +0900 Subject: [PATCH 034/124] About Linter installation --- docs/first_contribution.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/first_contribution.md b/docs/first_contribution.md index e31e8e48..3b011baf 100644 --- a/docs/first_contribution.md +++ b/docs/first_contribution.md @@ -26,7 +26,7 @@ GitHub上で「[Feature Request] 〇〇の絵文字に「△△」の読みを この変更は小さいので、管理者のOKを待つ必要はありません。次に進んでください。 -### 2.2. プロジェクトをフォークする +### 2.2. プロジェクトを準備する GitHub上で、azooKeyのプロジェクトをフォークしてください。 @@ -38,6 +38,17 @@ GitHub上で、azooKeyのプロジェクトをフォークしてください。 git remote add ``` +#### 2.2.1. linterをインストールする + +azooKeyではソースコードを整形するため、[SwiftLint](https://github.com/realm/SwiftLint)を用いています。`brew`などでインストールしてください。 + +```bash +brew install swiftlint +swiftlint --version +``` + +Xcodeでは、`swiftlint`が有効になっていれば自動でソースコードの整形が行われるようになっています。それ以外の環境では手動で`swiftlint --fix`を`azooKey/`で実行してください。 + ### 2.3. ブランチを切る azooKeyのディレクトリで、以下のコマンドを実行します。こうすることで、`develop`をベースにブランチを新しく作成できます。 From 1ccd5a4208feef6d4e5d3235b791c8df7dba3b43 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 18 Sep 2023 15:57:11 +0900 Subject: [PATCH 035/124] fix crash when execute enter with cursor movement --- Keyboard/Display/InputManager.swift | 17 +++++++++++------ Keyboard/Display/KeyboardActionManager.swift | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 296221b4..763f13d0 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -224,7 +224,7 @@ import UIKit /// 「現在入力中として表示されている文字列で確定する」というセマンティクスを持った操作である。 /// - parameters: /// - shouldModifyDisplayedText: DisplayedTextを操作して良いか否か。`textDidChange`などの場合は操作してはいけない。 - func enter(shouldModifyDisplayedText: Bool = true) -> [ActionType] { + func enter(shouldModifyDisplayedText: Bool = true, requireSetResult: Bool = true) -> [ActionType] { // selectedの場合、単に変換を止める if isSelected { self.stopComposition() @@ -234,15 +234,16 @@ import UIKit if liveConversionEnabled, let _candidate = liveConversionManager.lastUsedCandidate { candidate = _candidate } else { + let composingText = self.composingText.prefixToCursorPosition() candidate = Candidate( - text: self.composingText.convertTarget, + text: composingText.convertTarget, value: -18, - correspondingCount: self.composingText.input.count, + correspondingCount: composingText.input.count, lastMid: MIDData.一般.mid, data: [ DicdataElement( - word: self.composingText.convertTarget, - ruby: self.composingText.convertTarget.toKatakana(), + word: composingText.convertTarget, + ruby: composingText.convertTarget.toKatakana(), cid: CIDData.固有名詞.cid, mid: MIDData.一般.mid, value: -18 @@ -261,7 +262,11 @@ import UIKit } self.displayedTextManager.updateComposingText(composingText: self.composingText, completedPrefix: candidate.text, isSelected: self.isSelected) } - self.stopComposition() + if self.displayedTextManager.composingText.isEmpty { + self.stopComposition() + } else if requireSetResult { + self.setResult() + } return actions.map(\.action) } diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index a40341cb..4fe9ea64 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -178,7 +178,7 @@ import SwiftUtils case .enter: self.showResultView(variableStates: variableStates) self.shiftStateOff(variableStates: variableStates) - let actions = self.inputManager.enter() + let actions = self.inputManager.enter(requireSetResult: requireSetResult) self.registerActions(actions, variableStates: variableStates) case .changeCharacterType: From 8d515cc5be802b3fe49b530647a579be94d1b4cb Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 18 Sep 2023 19:35:59 +0900 Subject: [PATCH 036/124] feat: implement prediction candidate ui --- .../View/KeyboardBar/ResultBar.swift | 135 ++++++++++-------- .../View/KeyboardBar/ResultViewItemData.swift | 6 + Keyboard/Display/DisplayedTextManager.swift | 7 +- Keyboard/Display/InputManager.swift | 60 ++++++-- Keyboard/Display/KeyboardActionManager.swift | 32 ++++- Keyboard/Display/KeyboardViewController.swift | 2 + Keyboard/Display/PredictionManager.swift | 50 +++++++ azooKey.xcodeproj/project.pbxproj | 4 + 8 files changed, 221 insertions(+), 75 deletions(-) create mode 100644 Keyboard/Display/PredictionManager.swift diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index 6fe875d7..7605e714 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -22,6 +22,7 @@ private extension Equatable { } struct ResultBar: View { + @Namespace private var namespace @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action @EnvironmentObject private var variableStates: VariableStates @@ -42,12 +43,27 @@ struct ResultBar: View { self._isResultViewExpanded = isResultViewExpanded } + private var tabBarButton: some View { + KeyboardBarButton { + self.action.registerAction(.setTabBar(.toggle), variableStates: variableStates) + } + .matchedGeometryEffect(id: "KeyboardBarButton", in: namespace) + } + + private var resultData: [ResultData] { + if !variableStates.resultModelVariableSection.results.isEmpty { + variableStates.resultModelVariableSection.results + } else { + variableStates.resultModelVariableSection.predictionResults + } + } + var body: some View { - if variableStates.resultModelVariableSection.results.isEmpty { - CenterAlignedView { - if displayTabBarButton { - KeyboardBarButton { - self.action.registerAction(.setTabBar(.toggle), variableStates: variableStates) + Group { + if resultData.isEmpty { + CenterAlignedView { + if displayTabBarButton { + tabBarButton } if let undoButtonAction { Button { @@ -59,70 +75,77 @@ struct ResultBar: View { .buttonStyle(ResultButtonStyle(height: buttonHeight)) } } - } - .onAppear { - if variableStates.undoAction?.textChangedCount == variableStates.textChangedCount { - self.undoButtonAction = variableStates.undoAction - } else { - self.undoButtonAction = nil - } - } - .onChange(of: variableStates.undoAction.and(variableStates.textChangedCount)) {newValue in - withAnimation(.easeInOut) { - if newValue.first?.textChangedCount == newValue.second { - self.undoButtonAction = newValue.first + .onAppear { + if variableStates.undoAction?.textChangedCount == variableStates.textChangedCount { + self.undoButtonAction = variableStates.undoAction } else { self.undoButtonAction = nil } } - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color(.sRGB, white: 1, opacity: 0.001)) - .onLongPressGesture { - self.action.registerAction(.setTabBar(.toggle), variableStates: variableStates) - } - } else { - HStack { - ScrollView(.horizontal, showsIndicators: false) { - ScrollViewReader {scrollViewProxy in - LazyHStack(spacing: 10) { - ForEach(variableStates.resultModelVariableSection.results, id: \.id) {(data: ResultData) in - if data.candidate.inputable { - Button(data.candidate.text) { - KeyboardFeedback.click() - self.pressed(candidate: data.candidate) - } - .buttonStyle(ResultButtonStyle(height: buttonHeight)) - .contextMenu { - ResultContextMenuView(candidate: data.candidate, displayResetLearningButton: Extension.SettingProvider.canResetLearningForCandidate, index: data.id) + .onChange(of: variableStates.undoAction.and(variableStates.textChangedCount)) {newValue in + withAnimation(.easeIn(duration: 0.2)) { + if newValue.first?.textChangedCount == newValue.second { + self.undoButtonAction = newValue.first + } else { + self.undoButtonAction = nil + } + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color(.sRGB, white: 1, opacity: 0.001)) + .onLongPressGesture { + self.action.registerAction(.setTabBar(.toggle), variableStates: variableStates) + } + } else { + HStack { + if variableStates.resultModelVariableSection.results.isEmpty && displayTabBarButton { + tabBarButton + Spacer() + } + ScrollView(.horizontal, showsIndicators: false) { + ScrollViewReader {scrollViewProxy in + LazyHStack(spacing: 10) { + ForEach(resultData, id: \.id) {(data: ResultData) in + if data.candidate.inputable { + Button(data.candidate.text) { + KeyboardFeedback.click() + self.pressed(candidate: data.candidate) + } + .buttonStyle(ResultButtonStyle(height: buttonHeight)) + .contextMenu { + ResultContextMenuView(candidate: data.candidate, displayResetLearningButton: Extension.SettingProvider.canResetLearningForCandidate, index: data.id) + } + .id(data.id) + } else { + Text(data.candidate.text) + .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: Extension.SettingProvider.resultViewFontSize)) + .underline(true, color: .accentColor) } - .id(data.id) - } else { - Text(data.candidate.text) - .font(Design.fonts.resultViewFont(theme: theme, userSizePrefrerence: Extension.SettingProvider.resultViewFontSize)) - .underline(true, color: .accentColor) } + }.onChange(of: variableStates.resultModelVariableSection.updateResult) { _ in + scrollViewProxy.scrollTo(0, anchor: .trailing) } - }.onChange(of: variableStates.resultModelVariableSection.updateResult) { _ in - scrollViewProxy.scrollTo(0, anchor: .trailing) } + .padding(.horizontal, 5) } - .padding(.horizontal, 5) - } - // 候補を展開するボタン - Button(action: {self.expand()}) { - ZStack { - Color(white: 1, opacity: 0.001) - .frame(width: buttonWidth) - Image(systemName: "chevron.down") - .font(Design.fonts.iconImageFont(keyViewFontSizePreference: Extension.SettingProvider.keyViewFontSize, theme: theme)) - .frame(height: 18) + if variableStates.resultModelVariableSection.predictionResults.isEmpty { + // 候補を展開するボタン + Button(action: {self.expand()}) { + ZStack { + Color(white: 1, opacity: 0.001) + .frame(width: buttonWidth) + Image(systemName: "chevron.down") + .font(Design.fonts.iconImageFont(keyViewFontSizePreference: Extension.SettingProvider.keyViewFontSize, theme: theme)) + .frame(height: 18) + } + } + .buttonStyle(ResultButtonStyle(height: buttonHeight)) + .padding(.trailing, 10) } } - .buttonStyle(ResultButtonStyle(height: buttonHeight)) - .padding(.trailing, 10) } } + .animation(.easeIn(duration: 0.2), value: resultData.isEmpty) } private func pressed(candidate: any ResultViewItemData) { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift index 9a3aab98..05fb2528 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift @@ -18,16 +18,22 @@ public protocol ResultViewItemData { public struct ResultModelVariableSection { private(set) var results: [ResultData] = [] + private(set) var predictionResults: [ResultData] = [] private(set) var searchResults: [ResultData] = [] private(set) var updateResult: Bool = false public mutating func setResults(_ results: [any ResultViewItemData]) { self.results = results.indices.map {ResultData(id: $0, candidate: results[$0])} + self.predictionResults = [] self.updateResult.toggle() } public mutating func setSearchResults(_ results: [any ResultViewItemData]) { self.searchResults = results.indices.map {ResultData(id: $0, candidate: results[$0])} } + public mutating func setPredictionResults(_ results: [any ResultViewItemData]) { + self.predictionResults = results.indices.map {ResultData(id: $0, candidate: results[$0])} + self.updateResult.toggle() + } } struct ResultData: Identifiable { diff --git a/Keyboard/Display/DisplayedTextManager.swift b/Keyboard/Display/DisplayedTextManager.swift index ee7fac04..d12fb64d 100644 --- a/Keyboard/Display/DisplayedTextManager.swift +++ b/Keyboard/Display/DisplayedTextManager.swift @@ -31,11 +31,8 @@ import UIKit private var textChangedCount = 0 /// `textChangedCount`のgetter。 - func getTextChangedCountDelta() -> Int { - let result = self.textChangedCount - // リセットうする - self.textChangedCount = 0 - return result + func getTextChangedCount() -> Int { + return self.textChangedCount } /// marked textの有効化状態 diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 763f13d0..ac2d84ae 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -21,7 +21,8 @@ import UIKit // TODO: displayedTextManagerとliveConversionManagerを何らかの形で統合したい // ライブ変換を管理するクラス var liveConversionManager = LiveConversionManager() - + // (ゼロクエリの)予測変換を管理するクラス + var predictionManager = PredictionManager() // セレクトされているか否か、現在入力中の文字全体がセレクトされているかどうかである。 // TODO: isSelectedはdisplayedTextManagerが持っているべき var isSelected = false @@ -45,7 +46,7 @@ import UIKit private var rubyLog: OrderedDictionary = [:] // 変換結果の通知用関数 - private var updateResult: (([any ResultViewItemData]) -> Void)? + private var updateResult: (((inout ResultModelVariableSection) -> Void) -> Void)? private var liveConversionEnabled: Bool { liveConversionManager.enabled && !self.isSelected @@ -67,8 +68,8 @@ import UIKit return (left, center, right) } - func getTextChangedCountDelta() -> Int { - self.displayedTextManager.getTextChangedCountDelta() + func getTextChangedCount() -> Int { + self.displayedTextManager.getTextChangedCount() } func getComposingText() -> ComposingText { @@ -151,7 +152,7 @@ import UIKit self.displayedTextManager.setTextDocumentProxy(proxy) } - func setUpdateResult(_ updateResult: @escaping ([any ResultViewItemData]) -> Void) { + func setUpdateResult(_ updateResult: (((inout ResultModelVariableSection) -> Void) -> Void)?) { self.updateResult = updateResult } @@ -167,7 +168,9 @@ import UIKit func updateTextReplacementCandidates(left: String, center: String, right: String, target: [ConverterBehaviorSemantics.ReplacementTarget]) { let results = self.textReplacer.getReplacementCandidate(left: left, center: center, right: right, target: target) if let updateResult { - updateResult(results) + updateResult { + $0.setResults(results) + } } } @@ -176,6 +179,38 @@ import UIKit let results = self.textReplacer.getSearchResult(query: query, target: target) return results } + + func updatePredictionCandidates(candidate: Candidate) { + if let updateResult { + updateResult { + $0.setPredictionResults(predictionManager.update(candidate: candidate, textChangedCount: self.displayedTextManager.getTextChangedCount())) + } + } + } + + func updatePredictionCandidates(appending candidate: PredictionCandidate) { + // TODO: provide implementation + } + + func resetPredictionCandidates() { + if let updateResult { + updateResult { + $0.setPredictionResults([]) + } + } + } + + func resetPredictionCandidatesIfNecessary(textChangedCount: Int) { + if predictionManager.shouldResetPrediction(textChangedCount: textChangedCount) { + self.resetPredictionCandidates() + } + } + + /// `composingText`に入力されていた全体が変換された後に呼ばれる関数 + private func conversionCompleted(candidate: Candidate) { + // 予測変換を更新する + self.updatePredictionCandidates(candidate: candidate) + } /// 変換を選択した場合に呼ばれる func complete(candidate: Candidate) { @@ -189,6 +224,7 @@ import UIKit guard !self.composingText.isEmpty else { // ここで入力を停止する self.stopComposition() + self.conversionCompleted(candidate: candidate) return } self.isSelected = false @@ -210,7 +246,9 @@ import UIKit self.isSelected = false if let updateResult { - updateResult([]) + updateResult { + $0.setResults([]) + } } } @@ -230,6 +268,9 @@ import UIKit self.stopComposition() return [] } + if self.composingText.isEmpty { + return [] + } var candidate: Candidate if liveConversionEnabled, let _candidate = liveConversionManager.lastUsedCandidate { candidate = _candidate @@ -264,6 +305,7 @@ import UIKit } if self.displayedTextManager.composingText.isEmpty { self.stopComposition() + self.conversionCompleted(candidate: candidate) } else if requireSetResult { self.setResult() } @@ -835,7 +877,9 @@ import UIKit } if let updateResult { - updateResult(results.mainResults) + updateResult { + $0.setResults(results.mainResults) + } // 自動確定の実施 if liveConversionEnabled, let firstClause = self.liveConversionManager.candidateForCompleteFirstClause() { debug("InputManager.setResult: Complete first clause", firstClause) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 4fe9ea64..fd7f0791 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -41,8 +41,13 @@ import SwiftUtils func setDelegateViewController(_ controller: KeyboardViewController) { self.delegate = controller self.inputManager.setTextDocumentProxy(.mainProxy(controller.textDocumentProxy)) - self.inputManager.setUpdateResult { [weak controller] in - controller?.updateResultView($0) + } + + func setResultViewUpdateCallback(_ variableStates: VariableStates) { + self.inputManager.setUpdateResult { [weak variableStates] in + if let variableStates { + $0(&variableStates.resultModelVariableSection) + } } } @@ -56,10 +61,9 @@ import SwiftUtils /// 変換を確定した場合に呼ばれる。 /// - Parameters: - /// - text: String。確定された文字列。 - /// - count: Int。確定された文字数。例えば「検証」を確定した場合5。 + /// - candidate: 確定された候補。 + /// - variableStates: 状態。 override func notifyComplete(_ candidate: any ResultViewItemData, variableStates: VariableStates) { - let target = variableStates.tabManager.existentialTab().replacementTarget if let candidate = candidate as? Candidate { self.inputManager.complete(candidate: candidate) self.registerActions(candidate.actions.map(\.action), variableStates: variableStates) @@ -72,12 +76,20 @@ import SwiftUtils } } variableStates.lastTabCharacterPreferenceUpdate = .now + } else if let candidate = candidate as? PredictionCandidate { + self.inputManager.input(text: candidate.text, simpleInsert: true, inputStyle: .direct) + if !candidate.terminatePrediction { + self.inputManager.updatePredictionCandidates(appending: candidate) + } else { + self.inputManager.resetPredictionCandidates() + } } else { debug("notifyComplete: 確定できません") } // 左右の文字列 let (left, center, right) = self.inputManager.getSurroundingText() // MARK: Replacementの更新をする + let target = variableStates.tabManager.existentialTab().replacementTarget if !target.isEmpty { self.inputManager.updateTextReplacementCandidates(left: left, center: center, right: right, target: target) } @@ -271,7 +283,10 @@ import SwiftUtils // エンターキーの状態 variableStates.setEnterKeyState(self.inputManager.getEnterKeyState()) // 文字列の変更を適用 - variableStates.textChangedCount += self.inputManager.getTextChangedCountDelta() + variableStates.textChangedCount = self.inputManager.getTextChangedCount() + // 必要に応じて予測変換をリセット + self.inputManager.resetPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) + if let undoAction { variableStates.undoAction = .init(action: undoAction, textChangedCount: variableStates.textChangedCount) } @@ -540,6 +555,9 @@ import SwiftUtils debug("user operation id: 2", b_left, a_left) let offset = a_left.count - b_left.count self.inputManager.userMovedCursor(count: offset) + // カーソルが動いているのでtextChangedCountを増やす + variableStates.textChangedCount += 1 + self.inputManager.resetPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) return } @@ -560,6 +578,8 @@ import SwiftUtils defer { variableStates.textChangedCount += 1 + // 予測変換はテキストが変化したら解除する + self.inputManager.resetPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) } if b_left == "\n" && b_center == a_wholeText { diff --git a/Keyboard/Display/KeyboardViewController.swift b/Keyboard/Display/KeyboardViewController.swift index 88d7c330..5ce7ea85 100644 --- a/Keyboard/Display/KeyboardViewController.swift +++ b/Keyboard/Display/KeyboardViewController.swift @@ -107,6 +107,7 @@ final class KeyboardViewController: UIInputViewController { KeyboardViewController.keyboardViewHost = host KeyboardViewController.action.setDelegateViewController(self) + KeyboardViewController.action.setResultViewUpdateCallback(Self.variableStates) } private func getCurrentTheme() -> AzooKeyTheme { @@ -152,6 +153,7 @@ final class KeyboardViewController: UIInputViewController { } KeyboardViewController.action.setDelegateViewController(self) + KeyboardViewController.action.setResultViewUpdateCallback(Self.variableStates) SemiStaticStates.shared.setNeedsInputModeSwitchKey(self.needsInputModeSwitchKey) SemiStaticStates.shared.setHapticsAvailable() SemiStaticStates.shared.setHasFullAccess(self.hasFullAccess) diff --git a/Keyboard/Display/PredictionManager.swift b/Keyboard/Display/PredictionManager.swift new file mode 100644 index 00000000..3f0f958b --- /dev/null +++ b/Keyboard/Display/PredictionManager.swift @@ -0,0 +1,50 @@ +// +// PredictionManager.swift +// Keyboard +// +// Created by miwa on 2023/09/18. +// Copyright © 2023 miwa. All rights reserved. +// + +import KanaKanjiConverterModule +import KeyboardViews + +final class PredictionManager { + private struct State { + var candidate: Candidate + var textChangedCount: Int + } + + private var lastState: State? + + func update(candidate: Candidate, textChangedCount: Int) -> [PredictionCandidate] { + self.lastState = State(candidate: candidate, textChangedCount: textChangedCount) + return [ + // TODO: Provide implementation + ] + } + + func shouldResetPrediction(textChangedCount: Int) -> Bool { + if let lastState, lastState.textChangedCount != textChangedCount { + self.lastState = nil + return true + } + return false + } +} + +struct PredictionCandidate: ResultViewItemData { + var inputable: Bool { + true + } + + var text: String + + var terminatePrediction: Bool = false + + #if DEBUG + func getDebugInformation() -> String { + text + } + #endif +} diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index ca5a733b..90cdb8b9 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -169,6 +169,7 @@ 1AFB68422518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFB68412518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift */; }; 1AFB685328D56F1800B5C717 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1AC5876825D930D000BB060E /* Localizable.strings */; }; 1AFE773026077E0E0041D74D /* WalkthroughState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFE772F26077E0E0041D74D /* WalkthroughState.swift */; }; + 5598472E2AB84F5200B18C15 /* PredictionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5598472D2AB84F5200B18C15 /* PredictionManager.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -358,6 +359,7 @@ 1AFA57652584815A00477DC2 /* QwertyCustomKeysItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QwertyCustomKeysItemView.swift; sourceTree = ""; }; 1AFB68412518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSourceSoftwaresLicenseView.swift; sourceTree = ""; }; 1AFE772F26077E0E0041D74D /* WalkthroughState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalkthroughState.swift; sourceTree = ""; }; + 5598472D2AB84F5200B18C15 /* PredictionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PredictionManager.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -498,6 +500,7 @@ children = ( 1A1ECCA1295DF8DE001AD7E0 /* DisplayedTextManager.swift */, 1A1ECCA3295DF9D4001AD7E0 /* LiveConversionManager.swift */, + 5598472D2AB84F5200B18C15 /* PredictionManager.swift */, 1A1ECCA5295DFADF001AD7E0 /* InputManager.swift */, 1A3DC2062500D4FF002CAA93 /* KeyboardActionManager.swift */, 1A3DC1FB2500D488002CAA93 /* KeyboardViewController.swift */, @@ -1369,6 +1372,7 @@ buildActionMask = 2147483647; files = ( 1A1ECCA2295DF8DE001AD7E0 /* DisplayedTextManager.swift in Sources */, + 5598472E2AB84F5200B18C15 /* PredictionManager.swift in Sources */, 1A1ECCA6295DFADF001AD7E0 /* InputManager.swift in Sources */, 1A1ECCA4295DF9D4001AD7E0 /* LiveConversionManager.swift in Sources */, 1A3DC1FC2500D488002CAA93 /* KeyboardViewController.swift in Sources */, From 2eb77688f08141f5a493c3b196810aaaddd7b5e2 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 19 Sep 2023 23:54:46 +0900 Subject: [PATCH 037/124] update to use new api of prediction --- AzooKeyCore/Package.swift | 2 +- Keyboard/Display/InputManager.swift | 95 +++++++++++++----------- Keyboard/Display/PredictionManager.swift | 31 ++++++-- 3 files changed, 77 insertions(+), 51 deletions(-) diff --git a/AzooKeyCore/Package.swift b/AzooKeyCore/Package.swift index db36dd89..d5b40629 100644 --- a/AzooKeyCore/Package.swift +++ b/AzooKeyCore/Package.swift @@ -37,7 +37,7 @@ let package = Package( dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), - .package(url: "https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter", branch: "develop") + .package(url: "https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter", branch: "feature/prediction_candidate") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index ac2d84ae..e7192939 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -76,6 +76,48 @@ import UIKit self.composingText } + private func getConvertRequestOptions(inputStylePreference: InputStyle? = nil) -> ConvertRequestOptions { + let requireJapanesePrediction: Bool + let requireEnglishPrediction: Bool + switch (isSelected, inputStylePreference ?? .direct) { + case (true, _): + requireJapanesePrediction = false + requireEnglishPrediction = false + case (false, .direct): + requireJapanesePrediction = true + requireEnglishPrediction = true + case (false, .roman2kana): + requireJapanesePrediction = keyboardLanguage == .ja_JP + requireEnglishPrediction = keyboardLanguage == .en_US + } + @KeyboardSetting(.typographyLetter) var typographyLetterCandidate + @KeyboardSetting(.unicodeCandidate) var unicodeCandidate + @KeyboardSetting(.englishCandidate) var englishCandidateInRoman2KanaInput + @KeyboardSetting(.fullRomanCandidate) var fullWidthRomanCandidate + @KeyboardSetting(.halfKanaCandidate) var halfWidthKanaCandidate + @KeyboardSetting(.learningType) var learningType + + return ConvertRequestOptions( + N_best: 10, + requireJapanesePrediction: requireJapanesePrediction, + requireEnglishPrediction: requireEnglishPrediction, + keyboardLanguage: keyboardLanguage, + // KeyboardSettingsを注入 + typographyLetterCandidate: typographyLetterCandidate, + unicodeCandidate: unicodeCandidate, + englishCandidateInRoman2KanaInput: englishCandidateInRoman2KanaInput, + fullWidthRomanCandidate: fullWidthRomanCandidate, + halfWidthKanaCandidate: halfWidthKanaCandidate, + learningType: learningType, + maxMemoryCount: 65536, + shouldResetMemory: MemoryResetCondition.shouldReset(), + dictionaryResourceURL: Self.dictionaryResourceURL, + memoryDirectoryURL: Self.memoryDirectoryURL, + sharedContainerURL: Self.sharedContainerURL, + metadata: .init(appVersionString: SharedStore.currentAppVersion?.description ?? "Unknown") + ) + } + private func updateLog(candidate: Candidate) { for data in candidate.data { // 「感謝する: カンシャスル」→を「感謝: カンシャ」に置き換える @@ -181,15 +223,22 @@ import UIKit } func updatePredictionCandidates(candidate: Candidate) { + let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: candidate, options: getConvertRequestOptions()) if let updateResult { updateResult { - $0.setPredictionResults(predictionManager.update(candidate: candidate, textChangedCount: self.displayedTextManager.getTextChangedCount())) + $0.setPredictionResults(predictionManager.update(candidate: candidate, textChangedCount: self.displayedTextManager.getTextChangedCount(), predictions: results)) } } } func updatePredictionCandidates(appending candidate: PredictionCandidate) { - // TODO: provide implementation + if let updateResult, let lastUsedCandidate = predictionManager.getLastCandidate() { + let newCandidate = candidate.candidate.join(to: lastUsedCandidate) + let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: newCandidate, options: getConvertRequestOptions()) + updateResult { + $0.setPredictionResults(predictionManager.update(candidate: newCandidate, textChangedCount: self.displayedTextManager.getTextChangedCount(), predictions: results)) + } + } } func resetPredictionCandidates() { @@ -819,48 +868,8 @@ import UIKit func setResult() { let inputData = composingText.prefixToCursorPosition() debug("InputManager.setResult: value to be input", inputData) - - let requireJapanesePrediction: Bool - let requireEnglishPrediction: Bool - switch (isSelected, inputData.input.last?.inputStyle ?? .direct) { - case (true, _): - requireJapanesePrediction = false - requireEnglishPrediction = false - case (false, .direct): - requireJapanesePrediction = true - requireEnglishPrediction = true - case (false, .roman2kana): - requireJapanesePrediction = keyboardLanguage == .ja_JP - requireEnglishPrediction = keyboardLanguage == .en_US - } - @KeyboardSetting(.typographyLetter) var typographyLetterCandidate - @KeyboardSetting(.unicodeCandidate) var unicodeCandidate - @KeyboardSetting(.englishCandidate) var englishCandidateInRoman2KanaInput - @KeyboardSetting(.fullRomanCandidate) var fullWidthRomanCandidate - @KeyboardSetting(.halfKanaCandidate) var halfWidthKanaCandidate - @KeyboardSetting(.learningType) var learningType - - let options = ConvertRequestOptions( - N_best: 10, - requireJapanesePrediction: requireJapanesePrediction, - requireEnglishPrediction: requireEnglishPrediction, - keyboardLanguage: keyboardLanguage, - // KeyboardSettingsを注入 - typographyLetterCandidate: typographyLetterCandidate, - unicodeCandidate: unicodeCandidate, - englishCandidateInRoman2KanaInput: englishCandidateInRoman2KanaInput, - fullWidthRomanCandidate: fullWidthRomanCandidate, - halfWidthKanaCandidate: halfWidthKanaCandidate, - learningType: learningType, - maxMemoryCount: 65536, - shouldResetMemory: MemoryResetCondition.shouldReset(), - dictionaryResourceURL: Self.dictionaryResourceURL, - memoryDirectoryURL: Self.memoryDirectoryURL, - sharedContainerURL: Self.sharedContainerURL, - metadata: .init(appVersionString: SharedStore.currentAppVersion?.description ?? "Unknown") - ) + let options = self.getConvertRequestOptions(inputStylePreference: inputData.input.last?.inputStyle) debug("InputManager.setResult: options", options) - let results = self.kanaKanjiConverter.requestCandidates(inputData, options: options) // 表示を更新する diff --git a/Keyboard/Display/PredictionManager.swift b/Keyboard/Display/PredictionManager.swift index 3f0f958b..634ded65 100644 --- a/Keyboard/Display/PredictionManager.swift +++ b/Keyboard/Display/PredictionManager.swift @@ -17,13 +17,22 @@ final class PredictionManager { private var lastState: State? - func update(candidate: Candidate, textChangedCount: Int) -> [PredictionCandidate] { + func update(candidate: Candidate, textChangedCount: Int, predictions: [KanaKanjiConverterModule.PredictionCandidate]) -> [PredictionCandidate] { self.lastState = State(candidate: candidate, textChangedCount: textChangedCount) - return [ - // TODO: Provide implementation - ] + return predictions.map{.init(candidate: $0, terminatePrediction: shouldTerminate($0))} } + func shouldTerminate(_ candidate: KanaKanjiConverterModule.PredictionCandidate) -> Bool { + if ["。", "、", ".", ","].contains(candidate.text) { + return true + } + return false + } + + func getLastCandidate() -> Candidate? { + return lastState?.candidate + } + func shouldResetPrediction(textChangedCount: Int) -> Bool { if let lastState, lastState.textChangedCount != textChangedCount { self.lastState = nil @@ -34,13 +43,21 @@ final class PredictionManager { } struct PredictionCandidate: ResultViewItemData { + init(candidate: KanaKanjiConverterModule.PredictionCandidate, terminatePrediction: Bool = false) { + self.candidate = candidate + self.terminatePrediction = terminatePrediction + } + var candidate: KanaKanjiConverterModule.PredictionCandidate + var inputable: Bool { true } - var text: String - - var terminatePrediction: Bool = false + var text: String { + candidate.text + } + + var terminatePrediction: Bool #if DEBUG func getDebugInformation() -> String { From b56e6d9c673ecb81b20ee96234195ff008d975f9 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 22 Sep 2023 22:32:36 +0900 Subject: [PATCH 038/124] Fix strange animation --- .../KeyboardViews/View/KeyboardBar/ResultBar.swift | 14 ++++++++++---- .../View/KeyboardBar/ResultViewItemData.swift | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index 7605e714..340e905d 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -50,8 +50,12 @@ struct ResultBar: View { .matchedGeometryEffect(id: "KeyboardBarButton", in: namespace) } + private var isResultMode: Bool { + !variableStates.resultModelVariableSection.results.isEmpty + } + private var resultData: [ResultData] { - if !variableStates.resultModelVariableSection.results.isEmpty { + if isResultMode { variableStates.resultModelVariableSection.results } else { variableStates.resultModelVariableSection.predictionResults @@ -98,7 +102,7 @@ struct ResultBar: View { } } else { HStack { - if variableStates.resultModelVariableSection.results.isEmpty && displayTabBarButton { + if !isResultMode && displayTabBarButton { tabBarButton Spacer() } @@ -128,7 +132,7 @@ struct ResultBar: View { } .padding(.horizontal, 5) } - if variableStates.resultModelVariableSection.predictionResults.isEmpty { + if isResultMode { // 候補を展開するボタン Button(action: {self.expand()}) { ZStack { @@ -145,7 +149,8 @@ struct ResultBar: View { } } } - .animation(.easeIn(duration: 0.2), value: resultData.isEmpty) + .animation(.easeIn(duration: 0.2), value: variableStates.resultModelVariableSection.results.isEmpty) + .animation(.easeIn(duration: 0.2), value: variableStates.resultModelVariableSection.predictionResults.isEmpty) } private func pressed(candidate: any ResultViewItemData) { @@ -231,5 +236,6 @@ struct ResultButtonStyle: B theme.resultBackgroundColor.color ) .cornerRadius(5.0) + .animation(nil, value: configuration.isPressed) } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift index 05fb2528..2135a69c 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift @@ -28,10 +28,10 @@ public struct ResultModelVariableSection { self.updateResult.toggle() } public mutating func setSearchResults(_ results: [any ResultViewItemData]) { - self.searchResults = results.indices.map {ResultData(id: $0, candidate: results[$0])} + self.searchResults = results.enumerated().map {ResultData(id: $0.offset, candidate: $0.element)} } public mutating func setPredictionResults(_ results: [any ResultViewItemData]) { - self.predictionResults = results.indices.map {ResultData(id: $0, candidate: results[$0])} + self.predictionResults = results.enumerated().map {ResultData(id: $0.offset, candidate: $0.element)} self.updateResult.toggle() } } From e66d51e38fa89a01834018b64c50ce61c628799e Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 22 Sep 2023 23:10:54 +0900 Subject: [PATCH 039/124] Simplify code --- Keyboard/Display/InputManager.swift | 2 +- Keyboard/Display/KeyboardActionManager.swift | 2 +- Keyboard/Display/PredictionManager.swift | 32 ++++---------------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index e7192939..11405a59 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -233,7 +233,7 @@ import UIKit func updatePredictionCandidates(appending candidate: PredictionCandidate) { if let updateResult, let lastUsedCandidate = predictionManager.getLastCandidate() { - let newCandidate = candidate.candidate.join(to: lastUsedCandidate) + let newCandidate = candidate.join(to: lastUsedCandidate) let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: newCandidate, options: getConvertRequestOptions()) updateResult { $0.setPredictionResults(predictionManager.update(candidate: newCandidate, textChangedCount: self.displayedTextManager.getTextChangedCount(), predictions: results)) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index fd7f0791..e577c5b4 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -78,7 +78,7 @@ import SwiftUtils variableStates.lastTabCharacterPreferenceUpdate = .now } else if let candidate = candidate as? PredictionCandidate { self.inputManager.input(text: candidate.text, simpleInsert: true, inputStyle: .direct) - if !candidate.terminatePrediction { + if !candidate.isTerminal { self.inputManager.updatePredictionCandidates(appending: candidate) } else { self.inputManager.resetPredictionCandidates() diff --git a/Keyboard/Display/PredictionManager.swift b/Keyboard/Display/PredictionManager.swift index 634ded65..3162339f 100644 --- a/Keyboard/Display/PredictionManager.swift +++ b/Keyboard/Display/PredictionManager.swift @@ -19,14 +19,7 @@ final class PredictionManager { func update(candidate: Candidate, textChangedCount: Int, predictions: [KanaKanjiConverterModule.PredictionCandidate]) -> [PredictionCandidate] { self.lastState = State(candidate: candidate, textChangedCount: textChangedCount) - return predictions.map{.init(candidate: $0, terminatePrediction: shouldTerminate($0))} - } - - func shouldTerminate(_ candidate: KanaKanjiConverterModule.PredictionCandidate) -> Bool { - if ["。", "、", ".", ","].contains(candidate.text) { - return true - } - return false + return predictions } func getLastCandidate() -> Candidate? { @@ -42,26 +35,13 @@ final class PredictionManager { } } -struct PredictionCandidate: ResultViewItemData { - init(candidate: KanaKanjiConverterModule.PredictionCandidate, terminatePrediction: Bool = false) { - self.candidate = candidate - self.terminatePrediction = terminatePrediction - } - var candidate: KanaKanjiConverterModule.PredictionCandidate - - var inputable: Bool { +extension KanaKanjiConverterModule.PredictionCandidate: ResultViewItemData { + public var inputable: Bool { true } - - var text: String { - candidate.text - } - - var terminatePrediction: Bool - - #if DEBUG - func getDebugInformation() -> String { +#if DEBUG + public func getDebugInformation() -> String { text } - #endif +#endif } From aca13b74525f84452ef767027e0da99a0db28938 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 22 Sep 2023 23:37:10 +0900 Subject: [PATCH 040/124] Read more context --- Keyboard/Display/InputManager.swift | 19 ++++++++----- Keyboard/Display/PredictionManager.swift | 34 ++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 11405a59..cd1418fe 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -221,22 +221,29 @@ import UIKit let results = self.textReplacer.getSearchResult(query: query, target: target) return results } - + + /// 確定直後に呼ぶ func updatePredictionCandidates(candidate: Candidate) { let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: candidate, options: getConvertRequestOptions()) + predictionManager.updateAfterComplete(candidate: candidate, textChangedCount: self.displayedTextManager.getTextChangedCount()) if let updateResult { updateResult { - $0.setPredictionResults(predictionManager.update(candidate: candidate, textChangedCount: self.displayedTextManager.getTextChangedCount(), predictions: results)) + $0.setPredictionResults(results) } } } + /// 予測変換を選んだ後に呼ぶ func updatePredictionCandidates(appending candidate: PredictionCandidate) { - if let updateResult, let lastUsedCandidate = predictionManager.getLastCandidate() { - let newCandidate = candidate.join(to: lastUsedCandidate) - let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: newCandidate, options: getConvertRequestOptions()) + guard let lastUsedCandidate = predictionManager.getLastCandidate() else { + return + } + let newCandidate = candidate.join(to: lastUsedCandidate) + let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: newCandidate, options: getConvertRequestOptions()) + predictionManager.update(candidate: newCandidate, textChangedCount: self.displayedTextManager.getTextChangedCount()) + if let updateResult { updateResult { - $0.setPredictionResults(predictionManager.update(candidate: newCandidate, textChangedCount: self.displayedTextManager.getTextChangedCount(), predictions: results)) + $0.setPredictionResults(results) } } } diff --git a/Keyboard/Display/PredictionManager.swift b/Keyboard/Display/PredictionManager.swift index 3162339f..4d6b64b1 100644 --- a/Keyboard/Display/PredictionManager.swift +++ b/Keyboard/Display/PredictionManager.swift @@ -16,10 +16,40 @@ final class PredictionManager { } private var lastState: State? + + // 2つのCandidateをmergeする + private func mergeCandidates(_ left: Candidate, _ right: Candidate) -> Candidate { + // 厳密なmergeにはleft.lastRcidとright.lastLcidの連接コストの計算が必要だが、予測変換の文脈で厳密なValueの計算は不要なので行わない + var result = left + result.text += right.text + result.data += right.data + result.value += right.value + result.correspondingCount += right.correspondingCount + result.lastMid = right.lastMid == MIDData.EOS.mid ? left.lastMid : right.lastMid + return result + } + + /// 部分的に確定した後に更新を行う + func partialUpdate(candidate: Candidate) { + if let lastState { + self.lastState = .init(candidate: self.mergeCandidates(lastState.candidate, candidate), textChangedCount: lastState.textChangedCount) + } else { + self.lastState = .init(candidate: candidate, textChangedCount: -1) + } + } + + /// 確定直後にcandidateと合わせて更新する + func updateAfterComplete(candidate: Candidate, textChangedCount: Int) { + if let lastState, lastState.textChangedCount == -1 { + self.lastState = State(candidate: self.mergeCandidates(lastState.candidate, candidate), textChangedCount: textChangedCount) + } else { + self.lastState = State(candidate: candidate, textChangedCount: textChangedCount) + } + } - func update(candidate: Candidate, textChangedCount: Int, predictions: [KanaKanjiConverterModule.PredictionCandidate]) -> [PredictionCandidate] { + /// 確定後にcandidateと合わせて更新する + func update(candidate: Candidate, textChangedCount: Int) { self.lastState = State(candidate: candidate, textChangedCount: textChangedCount) - return predictions } func getLastCandidate() -> Candidate? { From 55595714d8517ff76bae1bc0180e4a097de82478 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 00:23:30 +0900 Subject: [PATCH 041/124] Enable learning of prediction --- Keyboard/Display/InputManager.swift | 3 ++- Keyboard/Display/KeyboardActionManager.swift | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index cd1418fe..91066063 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -234,10 +234,11 @@ import UIKit } /// 予測変換を選んだ後に呼ぶ - func updatePredictionCandidates(appending candidate: PredictionCandidate) { + func predictionCandidateSelected(candidate: PredictionCandidate) { guard let lastUsedCandidate = predictionManager.getLastCandidate() else { return } + self.kanaKanjiConverter.updateLearningData(lastUsedCandidate, with: candidate) let newCandidate = candidate.join(to: lastUsedCandidate) let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: newCandidate, options: getConvertRequestOptions()) predictionManager.update(candidate: newCandidate, textChangedCount: self.displayedTextManager.getTextChangedCount()) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index e577c5b4..b40290f2 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -79,7 +79,7 @@ import SwiftUtils } else if let candidate = candidate as? PredictionCandidate { self.inputManager.input(text: candidate.text, simpleInsert: true, inputStyle: .direct) if !candidate.isTerminal { - self.inputManager.updatePredictionCandidates(appending: candidate) + self.inputManager.predictionCandidateSelected(candidate: candidate) } else { self.inputManager.resetPredictionCandidates() } From 7fd3012e84a7de699e4090a015e480c8963f5903 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 01:50:57 +0900 Subject: [PATCH 042/124] lint --- Keyboard/Display/DisplayedTextManager.swift | 2 +- Keyboard/Display/InputManager.swift | 4 ++-- Keyboard/Display/KeyboardActionManager.swift | 2 +- Keyboard/Display/PredictionManager.swift | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Keyboard/Display/DisplayedTextManager.swift b/Keyboard/Display/DisplayedTextManager.swift index d12fb64d..8e8060e2 100644 --- a/Keyboard/Display/DisplayedTextManager.swift +++ b/Keyboard/Display/DisplayedTextManager.swift @@ -32,7 +32,7 @@ import UIKit /// `textChangedCount`のgetter。 func getTextChangedCount() -> Int { - return self.textChangedCount + self.textChangedCount } /// marked textの有効化状態 diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 91066063..2e53f2e9 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -117,7 +117,7 @@ import UIKit metadata: .init(appVersionString: SharedStore.currentAppVersion?.description ?? "Unknown") ) } - + private func updateLog(candidate: Candidate) { for data in candidate.data { // 「感謝する: カンシャスル」→を「感謝: カンシャ」に置き換える @@ -807,7 +807,7 @@ import UIKit // トークナイザ let tokenizer: CFStringTokenizer = CFStringTokenizerCreate( - kCFAllocatorDefault, + kCFAllocatorDefault, inputText as CFString, CFRangeMake(0, inputText.length), kCFStringTokenizerUnitWordBoundary, diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index b40290f2..acba3b8c 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -347,7 +347,7 @@ import SwiftUtils self.registerActions(action.start, variableStates: variableStates) } self.tasks.append((type: action, task: startTask)) - + let repeatTask = Task { try await Task.sleep(nanoseconds: 0_400_000_000) while !Task.isCancelled { diff --git a/Keyboard/Display/PredictionManager.swift b/Keyboard/Display/PredictionManager.swift index 4d6b64b1..37b9b8bc 100644 --- a/Keyboard/Display/PredictionManager.swift +++ b/Keyboard/Display/PredictionManager.swift @@ -16,7 +16,7 @@ final class PredictionManager { } private var lastState: State? - + // 2つのCandidateをmergeする private func mergeCandidates(_ left: Candidate, _ right: Candidate) -> Candidate { // 厳密なmergeにはleft.lastRcidとright.lastLcidの連接コストの計算が必要だが、予測変換の文脈で厳密なValueの計算は不要なので行わない @@ -28,7 +28,7 @@ final class PredictionManager { result.lastMid = right.lastMid == MIDData.EOS.mid ? left.lastMid : right.lastMid return result } - + /// 部分的に確定した後に更新を行う func partialUpdate(candidate: Candidate) { if let lastState { @@ -53,9 +53,9 @@ final class PredictionManager { } func getLastCandidate() -> Candidate? { - return lastState?.candidate + lastState?.candidate } - + func shouldResetPrediction(textChangedCount: Int) -> Bool { if let lastState, lastState.textChangedCount != textChangedCount { self.lastState = nil From 4881eb90fa568bb29243a922ac00ff6b7612f1af Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 14:34:17 +0900 Subject: [PATCH 043/124] Rename API --- Keyboard/Display/InputManager.swift | 16 ++++++++-------- Keyboard/Display/KeyboardActionManager.swift | 12 ++++++------ Keyboard/Display/PredictionManager.swift | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 2e53f2e9..3737ccd3 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -223,8 +223,8 @@ import UIKit } /// 確定直後に呼ぶ - func updatePredictionCandidates(candidate: Candidate) { - let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: candidate, options: getConvertRequestOptions()) + func updatePostCompositionPredictionCandidates(candidate: Candidate) { + let results = self.kanaKanjiConverter.requestPostCompositionPredictionCandidates(leftSideCandidate: candidate, options: getConvertRequestOptions()) predictionManager.updateAfterComplete(candidate: candidate, textChangedCount: self.displayedTextManager.getTextChangedCount()) if let updateResult { updateResult { @@ -234,13 +234,13 @@ import UIKit } /// 予測変換を選んだ後に呼ぶ - func predictionCandidateSelected(candidate: PredictionCandidate) { + func postCompositionPredictionCandidateSelected(candidate: PostCompositionPredictionCandidate) { guard let lastUsedCandidate = predictionManager.getLastCandidate() else { return } self.kanaKanjiConverter.updateLearningData(lastUsedCandidate, with: candidate) let newCandidate = candidate.join(to: lastUsedCandidate) - let results = self.kanaKanjiConverter.requestPredictionCandidates(leftSideCandidate: newCandidate, options: getConvertRequestOptions()) + let results = self.kanaKanjiConverter.requestPostCompositionPredictionCandidates(leftSideCandidate: newCandidate, options: getConvertRequestOptions()) predictionManager.update(candidate: newCandidate, textChangedCount: self.displayedTextManager.getTextChangedCount()) if let updateResult { updateResult { @@ -249,7 +249,7 @@ import UIKit } } - func resetPredictionCandidates() { + func resetPostCompositionPredictionCandidates() { if let updateResult { updateResult { $0.setPredictionResults([]) @@ -257,16 +257,16 @@ import UIKit } } - func resetPredictionCandidatesIfNecessary(textChangedCount: Int) { + func resetPostCompositionPredictionCandidatesIfNecessary(textChangedCount: Int) { if predictionManager.shouldResetPrediction(textChangedCount: textChangedCount) { - self.resetPredictionCandidates() + self.resetPostCompositionPredictionCandidates() } } /// `composingText`に入力されていた全体が変換された後に呼ばれる関数 private func conversionCompleted(candidate: Candidate) { // 予測変換を更新する - self.updatePredictionCandidates(candidate: candidate) + self.updatePostCompositionPredictionCandidates(candidate: candidate) } /// 変換を選択した場合に呼ばれる diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index acba3b8c..54d86342 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -76,12 +76,12 @@ import SwiftUtils } } variableStates.lastTabCharacterPreferenceUpdate = .now - } else if let candidate = candidate as? PredictionCandidate { + } else if let candidate = candidate as? PostCompositionPredictionCandidate { self.inputManager.input(text: candidate.text, simpleInsert: true, inputStyle: .direct) if !candidate.isTerminal { - self.inputManager.predictionCandidateSelected(candidate: candidate) + self.inputManager.postCompositionPredictionCandidateSelected(candidate: candidate) } else { - self.inputManager.resetPredictionCandidates() + self.inputManager.resetPostCompositionPredictionCandidates() } } else { debug("notifyComplete: 確定できません") @@ -285,7 +285,7 @@ import SwiftUtils // 文字列の変更を適用 variableStates.textChangedCount = self.inputManager.getTextChangedCount() // 必要に応じて予測変換をリセット - self.inputManager.resetPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) + self.inputManager.resetPostCompositionPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) if let undoAction { variableStates.undoAction = .init(action: undoAction, textChangedCount: variableStates.textChangedCount) @@ -557,7 +557,7 @@ import SwiftUtils self.inputManager.userMovedCursor(count: offset) // カーソルが動いているのでtextChangedCountを増やす variableStates.textChangedCount += 1 - self.inputManager.resetPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) + self.inputManager.resetPostCompositionPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) return } @@ -579,7 +579,7 @@ import SwiftUtils defer { variableStates.textChangedCount += 1 // 予測変換はテキストが変化したら解除する - self.inputManager.resetPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) + self.inputManager.resetPostCompositionPredictionCandidatesIfNecessary(textChangedCount: variableStates.textChangedCount) } if b_left == "\n" && b_center == a_wholeText { diff --git a/Keyboard/Display/PredictionManager.swift b/Keyboard/Display/PredictionManager.swift index 37b9b8bc..02ae07af 100644 --- a/Keyboard/Display/PredictionManager.swift +++ b/Keyboard/Display/PredictionManager.swift @@ -17,7 +17,7 @@ final class PredictionManager { private var lastState: State? - // 2つのCandidateをmergeする + // TODO: `KanaKanjiConverter.mergeCandidates`を呼んだほうが適切 private func mergeCandidates(_ left: Candidate, _ right: Candidate) -> Candidate { // 厳密なmergeにはleft.lastRcidとright.lastLcidの連接コストの計算が必要だが、予測変換の文脈で厳密なValueの計算は不要なので行わない var result = left @@ -65,7 +65,7 @@ final class PredictionManager { } } -extension KanaKanjiConverterModule.PredictionCandidate: ResultViewItemData { +extension PostCompositionPredictionCandidate: ResultViewItemData { public var inputable: Bool { true } From af61ce59b69362d689d42852b1ef5d9ad775e5cd Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 14:59:38 +0900 Subject: [PATCH 044/124] update document --- docs/advice_for_azooKey_based_development.md | 4 -- docs/overview.md | 43 ++++++++++++-------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/docs/advice_for_azooKey_based_development.md b/docs/advice_for_azooKey_based_development.md index fba90ac6..7725b56b 100644 --- a/docs/advice_for_azooKey_based_development.md +++ b/docs/advice_for_azooKey_based_development.md @@ -22,10 +22,6 @@ azooKeyは英語のなぞり入力(グライド入力)をサポートして 高精度なグライド入力の実現は今のところコストが高いため行えていません。将来的に対応したいですが、現状技術的に困難です。 -### 再変換 - -azooKeyは一般の場合の再変換をサポートしていません。つまり「再変換」から「さいへんかん」という文字列を得るためのモジュール(漢字かな変換モジュール)は実装されていません。 - ### シフト azooKeyのデフォルトのUIは英字のシフトに対応していませんが、`ApplicationSpecificKeyboardViewSettingProvider`を実装する際に`useShiftKey`を`true`にすることでデフォルトのローマ字キーボードでシフトキーを実装することができます。 diff --git a/docs/overview.md b/docs/overview.md index 6f39ff62..f559fb42 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -11,6 +11,10 @@ DictionaryDebugger: 辞書のデバッグツール Resources: MainAppとKeyboardで共有されるリソース ``` +## AzooKeyCore + +`AzooKeyCore`は全体で共有すべき実装を記述したSwift Packageです。詳しくは[README](../AzooKeyCore/README.md)を参照してください。 + ## MainApp MainAppはazooKeyの種々の設定を行うためのアプリです。 @@ -25,6 +29,10 @@ Keyboardはキーボード本体の実装です。 `KeyboardActionManager`は`InputManager`を用いて変換状態を管理します。`InputManager`は変換器である`KanaKanjiConverter`のAPIを呼び出したり、`LiveConversionManager`を通してライブ変換に関する処理を行ったり、`DisplayedTextManager`を通してディスプレイされるテキストの管理を行ったりします。 +### キーボードのUI + +キーボードのUIはAzooKeyCore/KeyboardViewsで実装しています。 + ### かな漢字変換モジュール かな漢字変換モジュールはazooKeyとは独立のパッケージ「AzooKeyKanaKanjiConverter」として切り出されています。以下を参照してください。 @@ -37,10 +45,6 @@ https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter https://github.com/ensan-hcl/CustardKit -## AzooKeyCore - -`AzooKeyCore`は全体で共有すべき実装を記述したSwift Packageです。詳しくは[README](../AzooKeyCore/README.md)を参照してください。 - ## Resources SharedはazooKey全体で共有されるリソースです。主に以下のものなどを含みます。 @@ -56,16 +60,21 @@ SharedはazooKey全体で共有されるリソースです。主に以下のも ## 用語 -| 英語 | 日本語 | 備考 | -| -------------- | -------------- | ---------------------------------------------------------- | -| Action | ユーザの操作 | | -| Candidate | 変換候補 | | -| Composing | 編集中 | 変換対象のテキストになっている、との意味。 | -| Custard | カスタード | **Cust**om Keybo**ard**の略。カスタムタブに関わる機能。 | -| Dicdata | 辞書データ | | -| Displayed | 表示されている | 内部状態ではなく、ユーザに見えている状態である、との意味。 | -| InputStyle | 入力方法 | ローマ字入力、ダイレクト入力など、入力方式を意味する。 | -| Learning | 学習 | 専ら学習機能を意味する。 | -| LiveConversion | ライブ変換 | | -| LOUDS | LOUDS | データ構造の名。 | - +| 英語 | 日本語 | 備考 | +| --------------------------- | ---------------- | ------------------------------------------------------------ | +| Action | ユーザの操作 | | +| Candidate | 変換候補 | | +| ChangeKeyboardKey | 地球儀キー | キーボードを変更するための地球儀キー。Appleの言葉ではInputModeSwitchKey。 | +| Composing | 編集中 | 変換対象のテキストになっている、との意味。 | +| Cursor | カーソル | 入力フィールド上に表示されるカーソル。コメントなどでは`|`の記号で表すことも多い。 | +| Cursor Bar | カーソルバー | 空白キーの長押しなどで表示されるカーソル移動用のバーUI。 | +| Custard | カスタード | **Cust**om Keybo**ard**の略。カスタムタブに関わる機能で用いている。 | +| Dicdata | 辞書データ | | +| Displayed | 表示されている | 内部状態ではなく、ユーザに見えている状態である、との意味。 | +| InputStyle | 入力方法 | ローマ字入力、ダイレクト入力など、入力方式を意味する。 | +| Learning | 学習 | 専ら学習機能を意味する。 | +| Live Conversion | ライブ変換 | | +| LOUDS | LOUDS | データ構造の名。 | +| Post Composition Prediction | 確定後の予測変換 | 候補を全て確定した後に表示される予測変換。 | +| Result Bar | リザルトバー | 変換候補を表示しているバーUI。 | +| Tab Bar | タブバー | azooKeyのアイコンのボタンを押すと表示されるバーUI。タブの移動などに用いる。 | From 39cb16865a2e4ca2f5748064291d7a06192e6892 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 15:16:47 +0900 Subject: [PATCH 045/124] lint --- .../AzooKeyUtils/AzooKeyKeyboardViewExtension.swift | 2 +- AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift | 2 +- .../View/FlickKeyboard/FlickKeyboardView.swift | 2 +- .../FlickKeyboard/SuggestView/FlickSuggestState.swift | 1 - .../FlickKeyboard/SuggestView/FlickSuggestView.swift | 3 +-- .../View/QwertyKeyboard/KeyView/QwertyKeyView.swift | 10 +++++----- .../QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift | 2 +- .../View/QwertyKeyboard/QwertyDataProvider.swift | 4 ++-- MainApp/Customize/ManageCustardView.swift | 4 ++-- MainApp/EnableAzooKeyView/EnableAzooKeyView.swift | 2 +- MainApp/Setting/BooleanSetting/BoolSettingView.swift | 2 +- 11 files changed, 16 insertions(+), 18 deletions(-) diff --git a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift index 0793ff54..7be8b828 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift @@ -93,7 +93,7 @@ public enum AzooKeyKeyboardViewExtension: ApplicationSpecificKeyboardViewExtensi public static var useBetaMoveCursorBar: Bool { UseBetaMoveCursorBar.value } - + public static var useShiftKey: Bool { false } diff --git a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift index 938c2d3e..6f41d42a 100644 --- a/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift +++ b/AzooKeyCore/Sources/KeyboardThemes/ThemeData.swift @@ -93,7 +93,7 @@ public struct ThemeShadowData: Codable, Equatable, Sendable where Col self.x = x self.y = y } - + public var color: ColorData public var radius: CGFloat public var x: CGFloat diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift index 2b9eac2b..44e88ad0 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift @@ -17,7 +17,7 @@ struct FlickKeyboardView: V private let models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)] init(keyModels: [[any FlickKeyModelProtocol]], interfaceSize: CGSize, keyboardOrientation: KeyboardOrientation) { self.tabDesign = TabDependentDesign(width: 5, height: 4, interfaceSize: interfaceSize, layout: .flick, orientation: keyboardOrientation) - + var models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)] = [:] for h in keyModels.indices { for v in keyModels[h].indices { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift index 4e226b1f..6bbf7e7a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift @@ -5,7 +5,6 @@ // Created by miwa on 2023/08/20. // - struct FlickSuggestState: Equatable, Hashable, Sendable { /// 横:縦:サジェストタイプ var items: [Int: [Int: FlickSuggestType]] = [:] diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index fd488c01..38505950 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -10,7 +10,6 @@ import CustardKit import Foundation import SwiftUI - struct FlickSuggestView: View { @EnvironmentObject private var variableStates: VariableStates @Environment(Extension.Theme.self) private var theme @@ -25,7 +24,7 @@ struct FlickSuggestView: Vi self.size = size self.suggestType = suggestType } - + private func getSuggestView(for model: FlickedKeyModel, isHidden: Bool, isPointed: Bool = false) -> some View { // 着せ替えが有効の場合、サジェストの背景色はwhiteにする。 var pointedColor: Color { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index 68fcfa9d..dca86da0 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -45,10 +45,10 @@ struct QwertyKeyDoublePressState { case secondPressStarted case secondPressCompleted } - + private var state: State = .inactive private(set) var updateDate: Date = Date() - + var secondPressCompleted: Bool { self.state == .secondPressCompleted } @@ -89,7 +89,7 @@ struct QwertyKeyDoublePressState { } self.updateDate = touchUpDate } - + mutating func reset() { self.state = .inactive self.updateDate = Date() @@ -104,8 +104,8 @@ struct QwertyKeyView: View @State private var doublePressState = QwertyKeyDoublePressState() @State private var suggest = false - @State private var longPressStartTask: Task<(), any Error>? = nil - + @State private var longPressStartTask: Task<(), any Error>? + @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action private let tabDesign: TabDependentDesign diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift index 52637ed5..9c53d8c2 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift @@ -36,7 +36,7 @@ struct QwertyShiftKeyModel: return [.setBoolState(VariableStates.BoolStates.isCapsLockedKey, .on)] } } - + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { if states.boolStates.isCapsLocked { return KeyLabel(.image("capslock.fill"), width: width, textColor: color) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift index 89c4ecd1..759d1028 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift @@ -537,7 +537,7 @@ struct QwertyDataProvider { QwertyKeyModel(labelType: .text("h"), pressActions: [.input("h")]), QwertyKeyModel(labelType: .text("j"), pressActions: [.input("j")]), QwertyKeyModel(labelType: .text("k"), pressActions: [.input("k")]), - QwertyKeyModel(labelType: .text("l"), pressActions: [.input("l")]), + QwertyKeyModel(labelType: .text("l"), pressActions: [.input("l")]) ] : [ QwertyKeyModel(labelType: .text("a"), pressActions: [.input("a")]), QwertyKeyModel(labelType: .text("s"), pressActions: [.input("s")]), @@ -548,7 +548,7 @@ struct QwertyDataProvider { QwertyKeyModel(labelType: .text("j"), pressActions: [.input("j")]), QwertyKeyModel(labelType: .text("k"), pressActions: [.input("k")]), QwertyKeyModel(labelType: .text("l"), pressActions: [.input("l")]), - QwertyAaKeyModel.shared, + QwertyAaKeyModel.shared ], [ Self.tabKeys(rowInfo: (7, 2, 0, 0)).languageKey, diff --git a/MainApp/Customize/ManageCustardView.swift b/MainApp/Customize/ManageCustardView.swift index 968b1b53..feb21452 100644 --- a/MainApp/Customize/ManageCustardView.swift +++ b/MainApp/Customize/ManageCustardView.swift @@ -146,7 +146,7 @@ struct ManageCustardView: View { @ObservedObject private var data = ImportedCustardData() @State private var urlString: String = "" @State private var showAlert = false - @State private var alertType: AlertType? = nil + @State private var alertType: AlertType? @Binding private var manager: CustardManager @State private var webCustards: WebCustardList = .init(last_update: "", custards: []) @State private var showDocumentPicker = false @@ -372,7 +372,7 @@ struct ManageCustardView: View { struct URLImportCustardView: View { @ObservedObject private var data = ImportedCustardData() @State private var showAlert = false - @State private var alertType: AlertType? = nil + @State private var alertType: AlertType? @Binding private var manager: CustardManager @Binding private var url: URL? @State private var addTabBar = true diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift index 8b001329..17468360 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift @@ -174,7 +174,7 @@ struct EnableAzooKeyView: View { } } } - + private func checkActiveKeyboardIsAzooKey() -> Bool { // キーボードが開いた時 // 参考:https://stackoverflow.com/questions/26153336/how-do-i-find-out-the-current-keyboard-used-on-ios8 diff --git a/MainApp/Setting/BooleanSetting/BoolSettingView.swift b/MainApp/Setting/BooleanSetting/BoolSettingView.swift index bfcb6e15..e1d42af4 100644 --- a/MainApp/Setting/BooleanSetting/BoolSettingView.swift +++ b/MainApp/Setting/BooleanSetting/BoolSettingView.swift @@ -14,7 +14,7 @@ struct BoolSettingView: View { @State private var showExplanation = false @State private var showRequireFullAccessAlert = false @State private var showOnEnabledMessageAlert = false - @State private var onEnabledAlertMessage: LocalizedStringKey? = nil + @State private var onEnabledAlertMessage: LocalizedStringKey? @State private var setting: SettingUpdater @MainActor init(_ key: SettingKey) { From 1cc5ec55c400e4fc14fb6fc4d9418425658f7287 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 15:29:34 +0900 Subject: [PATCH 046/124] -enable-upcoming-feature DisableOutwardActorInference --- AzooKeyCore/Package.swift | 1 + .../KeyboardViews/View/Components/ExpandedResultView.swift | 1 + .../Sources/KeyboardViews/View/Components/KeyLabel.swift | 1 + .../Sources/KeyboardViews/View/Components/LargeTextView.swift | 1 + .../Sources/KeyboardViews/View/Components/MessageView.swift | 1 + .../Sources/KeyboardViews/View/Components/ResizingRect.swift | 2 ++ .../KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift | 1 + .../View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift | 1 + .../View/FlickKeyboard/KeyView/FlickKeyView.swift | 1 + .../View/FlickKeyboard/SuggestView/FlickSuggestView.swift | 1 + .../KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift | 1 + .../KeyboardViews/View/KeyboardBar/KeyboardBarView.swift | 2 ++ .../KeyboardViews/View/KeyboardBar/MoveCursorBar.swift | 2 ++ .../Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift | 1 + AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift | 1 + .../View/QwertyKeyboard/KeyView/QwertyKeyView.swift | 1 + .../KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift | 1 + .../Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift | 1 + .../View/UpsideComponents/UpsideSearchView.swift | 1 + MainApp/ContentView.swift | 1 + MainApp/Customize/EditingTenkeyCustardView.swift | 1 + MainApp/Customize/ManageCustardView.swift | 2 ++ MainApp/EnableAzooKeyView/EnableAzooKeyView.swift | 1 + MainApp/General/KeyboardPreview.swift | 1 + MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift | 1 + MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift | 2 ++ .../QwertyCustomKeys/QwertyCustomKeysItemView.swift | 1 + MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift | 1 + .../KeyboardLayout/KeyboardLayoutSettingItemView.swift | 1 + MainApp/Setting/Template/TemplateListView.swift | 1 + MainApp/Theme/ThemeTab.swift | 1 + azooKey.xcodeproj/project.pbxproj | 4 ++-- 32 files changed, 38 insertions(+), 2 deletions(-) diff --git a/AzooKeyCore/Package.swift b/AzooKeyCore/Package.swift index d5b40629..6d496ec3 100644 --- a/AzooKeyCore/Package.swift +++ b/AzooKeyCore/Package.swift @@ -10,6 +10,7 @@ let swiftSettings: [SwiftSetting] = [ .enableUpcomingFeature("ForwardTrailingClosures"), .enableUpcomingFeature("ImplicitOpenExistentials"), .enableUpcomingFeature("StrictConcurrency"), + .enableUpcomingFeature("DisableOutwardActorInference"), .unsafeFlags(["-strict-concurrency=complete"]) ] let package = Package( diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift index 3df281cf..bb2a2004 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift @@ -9,6 +9,7 @@ import Foundation import SwiftUI +@MainActor struct ExpandedResultView: View { @EnvironmentObject private var variableStates: VariableStates @Binding private var isResultViewExpanded: Bool diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift index e048a5c1..156b5c32 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift @@ -18,6 +18,7 @@ public enum KeyLabelType { case selectable(String, String) } +@MainActor public struct KeyLabel: View { private let labelType: KeyLabelType private let width: CGFloat diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/LargeTextView.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/LargeTextView.swift index 2c69c2ea..08196c9f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/LargeTextView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/LargeTextView.swift @@ -10,6 +10,7 @@ import Foundation import SwiftUI import SwiftUIUtils +@MainActor struct LargeTextView: View { private let text: String @Binding private var isViewOpen: Bool diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift index 58aec81e..a7ebb13e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/MessageView.swift @@ -8,6 +8,7 @@ import SwiftUI +@MainActor struct MessageView: View { private let data: MessageData @Binding private var manager: MessageManager diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift index a73378b5..bf533379 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/ResizingRect.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI +@MainActor struct ResizingRect: View { typealias Position = (current: CGPoint, initial: CGPoint) @State private var top_left_edge: Position @@ -279,6 +280,7 @@ struct ResizingRect: View { } } +@MainActor struct ResizingBindingFrame: ViewModifier { private let initialSize: CGSize @Binding private var position: CGPoint diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index 9fdc9982..02f5c45f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -253,6 +253,7 @@ extension CustardInterfaceKey { } } +@MainActor struct CustomKeyboardView: View { private let custard: Custard private var tabDesign: TabDependentDesign { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift index 8f8cda55..a0f70421 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift @@ -10,6 +10,7 @@ import Foundation import SwiftUI import SwiftUIUtils +@MainActor struct SimpleKeyView: View { private let model: any SimpleKeyModelProtocol @EnvironmentObject private var variableStates: VariableStates diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift index eeee76d3..559828e3 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift @@ -26,6 +26,7 @@ enum KeyPressState { } } +@MainActor public struct FlickKeyView: View { private let model: any FlickKeyModelProtocol diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 38505950..8cb23cd4 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -10,6 +10,7 @@ import CustardKit import Foundation import SwiftUI +@MainActor struct FlickSuggestView: View { @EnvironmentObject private var variableStates: VariableStates @Environment(Extension.Theme.self) private var theme diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift index ced5b41f..91a63514 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift @@ -9,6 +9,7 @@ import SwiftUI import SwiftUIUtils +@MainActor struct EmojiTabResultBar: View { init() {} @Environment(Extension.Theme.self) private var theme diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift index bd6b4b21..788f3d8d 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift @@ -10,6 +10,7 @@ import Foundation import SwiftUI import SwiftUIUtils +@MainActor struct KeyboardBarView: View { @EnvironmentObject private var variableStates: VariableStates @Binding private var isResultViewExpanded: Bool @@ -37,6 +38,7 @@ struct KeyboardBarView: Vie } } +@MainActor struct KeyboardBarButton: View { enum LabelType { case azooKeyIcon diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift index 14ec6ee2..8ea44e5d 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift @@ -68,6 +68,7 @@ struct BetaMoveCursorBarState { } } +@MainActor struct MoveCursorBarBeta: View { init() {} @@ -283,6 +284,7 @@ private enum MoveCursorBarGestureState { case moving(CGPoint, Int) // 右だったら+1、左だったら-1 } +@MainActor struct MoveCursorBar: View { init() {} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index 340e905d..22584804 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -21,6 +21,7 @@ private extension Equatable { } } +@MainActor struct ResultBar: View { @Namespace private var namespace @Environment(Extension.Theme.self) private var theme diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift index 90d725c9..246d5d7f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift @@ -9,6 +9,7 @@ import Foundation import SwiftUI +@MainActor public struct KeyboardView: View { @State private var messageManager = MessageManager(necessaryMessages: Extension.MessageProvider.messages, userDefaults: Extension.MessageProvider.userDefaults) @State private var isResultViewExpanded = false diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index dca86da0..ae6400f0 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -96,6 +96,7 @@ struct QwertyKeyDoublePressState { } } +@MainActor struct QwertyKeyView: View { private let model: any QwertyKeyModelProtocol @EnvironmentObject private var variableStates: VariableStates diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift index 940c5d3b..be77d381 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift @@ -47,6 +47,7 @@ private final class ClipboardHistory: ObservableObject { } } +@MainActor struct ClipboardHistoryTab: View { @EnvironmentObject private var variableStates: VariableStates @StateObject private var target = ClipboardHistory() diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift index 14baa953..d0af3089 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift @@ -10,6 +10,7 @@ import KeyboardThemes import SwiftUI import SwiftUtils +@MainActor struct EmojiTab: View { @EnvironmentObject private var variableStates: VariableStates @Environment(Extension.Theme.self) private var theme diff --git a/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift b/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift index c7e0e7a6..4c359c16 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift @@ -9,6 +9,7 @@ import SwiftUI import enum KanaKanjiConverterModule.ConverterBehaviorSemantics +@MainActor struct UpsideSearchView: View { @Environment(\.userActionManager) private var action @Environment(Extension.Theme.self) private var theme diff --git a/MainApp/ContentView.swift b/MainApp/ContentView.swift index af20769e..956fd2fe 100644 --- a/MainApp/ContentView.swift +++ b/MainApp/ContentView.swift @@ -10,6 +10,7 @@ import AzooKeyUtils import KeyboardViews import SwiftUI +@MainActor struct ContentView: View { private enum TabSelection { case tips, theme, customize, settings diff --git a/MainApp/Customize/EditingTenkeyCustardView.swift b/MainApp/Customize/EditingTenkeyCustardView.swift index 46f2e80f..9cc65e9c 100644 --- a/MainApp/Customize/EditingTenkeyCustardView.swift +++ b/MainApp/Customize/EditingTenkeyCustardView.swift @@ -29,6 +29,7 @@ fileprivate extension Dictionary where Key == KeyPosition, Value == UserMadeTenK } } +@MainActor struct EditingTenkeyCustardView: CancelableEditor { private static let emptyKey: UserMadeTenKeyCustard.KeyData = .init(model: .custom(.empty), width: 1, height: 1) private static let emptyKeys: [KeyPosition: UserMadeTenKeyCustard.KeyData] = (0..<5).reduce(into: [:]) {dict, x in diff --git a/MainApp/Customize/ManageCustardView.swift b/MainApp/Customize/ManageCustardView.swift index feb21452..e23fb87d 100644 --- a/MainApp/Customize/ManageCustardView.swift +++ b/MainApp/Customize/ManageCustardView.swift @@ -142,6 +142,7 @@ struct WebCustardList: Codable { var custards: [Item] } +@MainActor struct ManageCustardView: View { @ObservedObject private var data = ImportedCustardData() @State private var urlString: String = "" @@ -369,6 +370,7 @@ struct ManageCustardView: View { } // FIXME: ファイルを保存もキャンセルもしない状態で2つ目のファイルを読み込むとエラーになる +@MainActor struct URLImportCustardView: View { @ObservedObject private var data = ImportedCustardData() @State private var showAlert = false diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift index 17468360..5455c0f0 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift @@ -18,6 +18,7 @@ private enum EnableAzooKeyViewStep { case setting } +@MainActor struct EnableAzooKeyView: View { @EnvironmentObject private var appStates: MainAppStates @State private var step: EnableAzooKeyViewStep = .menu diff --git a/MainApp/General/KeyboardPreview.swift b/MainApp/General/KeyboardPreview.swift index 2615e979..8b00bef4 100644 --- a/MainApp/General/KeyboardPreview.swift +++ b/MainApp/General/KeyboardPreview.swift @@ -21,6 +21,7 @@ private struct CandidateMock: ResultViewItemData { #endif } +@MainActor struct KeyboardPreview: View { private let theme: AzooKeyTheme diff --git a/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift b/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift index 44274c78..362fa58f 100644 --- a/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift +++ b/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift @@ -126,6 +126,7 @@ final class AdditionalDictManager: ObservableObject { } +@MainActor struct AdditionalDictManageViewMain: View { enum Style { case simple diff --git a/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift b/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift index 97f0d817..f42180d5 100644 --- a/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift +++ b/MainApp/Setting/AdditionalDict/AzooKeyUserDictionary.swift @@ -63,6 +63,7 @@ struct AzooKeyUserDictionaryView: View { } } +@MainActor private struct UserDictionaryDataListView: View { private let exceptionKey = "その他" @@ -142,6 +143,7 @@ private struct UserDictionaryDataListView: View { } } +@MainActor private struct UserDictionaryDataEditor: CancelableEditor { @ObservedObject private var item: EditableUserDictionaryData @ObservedObject private var variables: UserDictManagerVariables diff --git a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift index 35df07b8..3b65800c 100644 --- a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift +++ b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift @@ -101,6 +101,7 @@ private struct Selection: Hashable { var longpressEnabled = false } +@MainActor struct QwertyCustomKeysSettingView: View { @StateObject private var editState = EditState() @State private var setting = SettingUpdater() diff --git a/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift b/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift index 3f7a9212..bdc92ce5 100644 --- a/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift +++ b/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift @@ -73,6 +73,7 @@ struct FontSizeSettingView: View { } } +@MainActor private struct KeyView: View { @EnvironmentObject private var appStates: MainAppStates private let fontSize: CGFloat diff --git a/MainApp/Setting/KeyboardLayout/KeyboardLayoutSettingItemView.swift b/MainApp/Setting/KeyboardLayout/KeyboardLayoutSettingItemView.swift index b9f2baff..d57cfd28 100644 --- a/MainApp/Setting/KeyboardLayout/KeyboardLayoutSettingItemView.swift +++ b/MainApp/Setting/KeyboardLayout/KeyboardLayoutSettingItemView.swift @@ -25,6 +25,7 @@ extension LanguageLayout { } } +@MainActor struct LanguageLayoutSettingView: View { @EnvironmentObject private var appStates: MainAppStates @State private var selection: LanguageLayout = .flick diff --git a/MainApp/Setting/Template/TemplateListView.swift b/MainApp/Setting/Template/TemplateListView.swift index c6dc943f..7b3fe490 100644 --- a/MainApp/Setting/Template/TemplateListView.swift +++ b/MainApp/Setting/Template/TemplateListView.swift @@ -26,6 +26,7 @@ private final class NavigationModel: ObservableObject { } // Listが大元のtemplatesを持ち、各EditingViewにBindingで渡して編集させる。 +@MainActor struct TemplateListView: View { private static let dataFileName = "user_templates.json" @ObservedObject private var data = TemplateDataList() diff --git a/MainApp/Theme/ThemeTab.swift b/MainApp/Theme/ThemeTab.swift index b6c45f92..1db67ef7 100644 --- a/MainApp/Theme/ThemeTab.swift +++ b/MainApp/Theme/ThemeTab.swift @@ -12,6 +12,7 @@ import SwiftUI import SwiftUIUtils import SwiftUtils +@MainActor struct ThemeTabView: View { @Namespace private var namespace @EnvironmentObject private var appStates: MainAppStates diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index 90cdb8b9..f7372bd4 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -1634,7 +1634,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 2.2; - OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials"; + OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature DisableOutwardActorInference"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey; PRODUCT_NAME = azooKey; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1802,7 +1802,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 2.2; - OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials"; + OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature DisableOutwardActorInference"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey.keyboard; PRODUCT_NAME = Keyboard; PROVISIONING_PROFILE_SPECIFIER = ""; From e749a05a68836d3fe4a78b77cb116bfc90ead99e Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 15:31:18 +0900 Subject: [PATCH 047/124] -enable-upcoming-feature ImportObjcForwardDeclarations --- AzooKeyCore/Package.swift | 1 + azooKey.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/AzooKeyCore/Package.swift b/AzooKeyCore/Package.swift index 6d496ec3..84ebd32a 100644 --- a/AzooKeyCore/Package.swift +++ b/AzooKeyCore/Package.swift @@ -11,6 +11,7 @@ let swiftSettings: [SwiftSetting] = [ .enableUpcomingFeature("ImplicitOpenExistentials"), .enableUpcomingFeature("StrictConcurrency"), .enableUpcomingFeature("DisableOutwardActorInference"), + .enableUpcomingFeature("ImportObjcForwardDeclarations"), .unsafeFlags(["-strict-concurrency=complete"]) ] let package = Package( diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index f7372bd4..dc6ed723 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -1634,7 +1634,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 2.2; - OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature DisableOutwardActorInference"; + OTHER_SWIFT_FLAGS = "-enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature DisableOutwardActorInference -enable-upcoming-feature ImportObjcForwardDeclarations"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey; PRODUCT_NAME = azooKey; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1802,7 +1802,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 2.2; - OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature DisableOutwardActorInference"; + OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-function-bodies=300 -enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature ImportObjcForwardDeclarations -enable-upcoming-feature DisableOutwardActorInference"; PRODUCT_BUNDLE_IDENTIFIER = DevEn3.azooKey.keyboard; PRODUCT_NAME = Keyboard; PROVISIONING_PROFILE_SPECIFIER = ""; From 7d47525631f15cc08dcd23e02698f6816fcc6527 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 15:34:32 +0900 Subject: [PATCH 048/124] Update Swift Version --- .github/workflows/swift.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 9326c578..0681eb13 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -15,9 +15,9 @@ jobs: runs-on: macos-latest steps: - - uses: swift-actions/setup-swift@65540b95f51493d65f5e59e97dcef9629ddf11bf + - uses: swift-actions/setup-swift@150267bf6ba01f9d942a4bd55aa2f35ba586767d with: - swift-version: "5.8" + swift-version: "5.9" - uses: actions/checkout@v3 - name: Build # TODO: add KeyboardViews From 8c28c99e72645373312dd032c0c128d0ec422336 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 15:51:05 +0900 Subject: [PATCH 049/124] Update AzooKeyCore Swift version --- AzooKeyCore/Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AzooKeyCore/Package.swift b/AzooKeyCore/Package.swift index 84ebd32a..51bbb3f5 100644 --- a/AzooKeyCore/Package.swift +++ b/AzooKeyCore/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.8 +// swift-tools-version: 5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription From 140e54296a3532b6b648b42b5e420ac77a04e5f3 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 15:56:18 +0900 Subject: [PATCH 050/124] =?UTF-8?q?Swift5.9=E4=BB=A5=E9=99=8Dtype=20parame?= =?UTF-8?q?ter=E3=81=AEoverride=E3=81=AFwarning=E3=81=8C=E5=87=BA=E3=82=8B?= =?UTF-8?q?=E3=81=AE=E3=81=A7=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift | 6 +++--- .../View/FlickKeyboard/KeyView/FlickAaKeyModel.swift | 2 +- .../FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift | 2 +- .../View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift | 2 +- .../FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift | 2 +- .../View/FlickKeyboard/KeyView/FlickKeyModel.swift | 2 +- .../View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift | 2 +- .../View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift | 2 +- .../View/FlickKeyboard/KeyView/FlickTabKeyModel.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift | 2 +- .../KeyView/QwertyChangeKeyboardKeyModel.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift | 2 +- .../QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertyKeyModel.swift | 2 +- .../KeyView/QwertyLanguageSwitchKeyModel.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift | 2 +- .../Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift | 6 +++--- 19 files changed, 23 insertions(+), 23 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift index 3ade17fd..3c164299 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift @@ -82,7 +82,7 @@ struct SimpleKeyModel: Simp private let pressActions: [ActionType] let longPressActions: LongpressActionType - func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { KeyLabel(self.keyLabelType, width: width) } @@ -108,7 +108,7 @@ struct SimpleEnterKeyModel: let longPressActions: LongpressActionType = .none let unpressedKeyColorType: SimpleUnpressedKeyColorType = .enter - func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { let text = Design.language.getEnterKeyText(states.enterKeyState) return KeyLabel(.text(text), width: width) } @@ -134,7 +134,7 @@ struct SimpleChangeKeyboardKeyModel(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { if SemiStaticStates.shared.needsInputModeSwitchKey { return KeyLabel(.changeKeyboard, width: width) } else { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift index 94a7d7da..8ded3816 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift @@ -37,7 +37,7 @@ struct FlickAaKeyModel: Fli } } - func label(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { if states.boolStates.isCapsLocked { return KeyLabel(.image("capslock.fill"), width: width) } else { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift index 8c2a694e..255af3b7 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift @@ -43,7 +43,7 @@ struct FlickChangeKeyboardModel(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { switch SemiStaticStates.shared.needsInputModeSwitchKey { case true: return KeyLabel(.changeKeyboard, width: width) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift index 44082bc1..98b9a304 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift @@ -30,7 +30,7 @@ struct FlickEnterKeyModel: [:] } - func label(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { let text = Design.language.getEnterKeyText(states.enterKeyState) return KeyLabel(.text(text), width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift index 59ca0069..78f6e31a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift @@ -33,7 +33,7 @@ struct FlickKanaSymbolsKeyModel(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { KeyLabel(self.labelType, width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift index 3157b215..b5530cde 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift @@ -49,7 +49,7 @@ struct FlickKeyModel: Flick self.flickKeys } - func label(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { KeyLabel(self.labelType, width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift index 452611cf..ebb697d0 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift @@ -33,7 +33,7 @@ struct FlickKogakiKeyModel: [.changeCharacterType] } - func label(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { KeyLabel(self.labelType, width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift index e13e1e74..02847458 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift @@ -41,7 +41,7 @@ struct FlickSpaceKeyModel: [.input(" ")] } - func label(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { KeyLabel(.text("空白"), width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift index 0278175c..668d2fa1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift @@ -37,7 +37,7 @@ struct FlickTabKeyModel: Fl self.tab = tab } - func label(width: CGFloat, states: VariableStates) -> KeyLabel { + func label(width: CGFloat, states: VariableStates) -> KeyLabel { KeyLabel(self.data.labelType, width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift index cfbeab90..86efda10 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift @@ -28,7 +28,7 @@ struct QwertyAaKeyModel: Qw .init(start: [.setBoolState(VariableStates.BoolStates.isCapsLockedKey, .toggle)]) } - func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { if states.boolStates.isCapsLocked { return KeyLabel(.image("capslock.fill"), width: width, textColor: color) } else { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift index 673507e1..92139067 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift @@ -66,7 +66,7 @@ struct QwertyChangeKeyboardKeyModel(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { if SemiStaticStates.shared.needsInputModeSwitchKey { return KeyLabel(.changeKeyboard, width: width, textColor: color) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift index 50faca4e..98fe9dbd 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift @@ -32,7 +32,7 @@ struct QwertyEnterKeyModel: let longPressActions: LongpressActionType = .none - func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { let text = Design.language.getEnterKeyText(states.enterKeyState) return KeyLabel(.text(text), width: width, textSize: .small, textColor: color) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift index fecb568a..357c6ed9 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift @@ -34,7 +34,7 @@ struct QwertyFunctionalKeyModel(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { KeyLabel(self.labelType, width: width, textColor: color) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift index 683598ab..a7a0048f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift @@ -31,7 +31,7 @@ struct QwertyKeyModel: Qwer self.unpressedKeyColorType = keyColorType } - func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { if (states.boolStates.isCapsLocked || states.boolStates.isShifted), states.keyboardLanguage == .en_US, case let .text(text) = self.labelType { return KeyLabel(.text(text.uppercased()), width: width, textColor: color) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift index 447d64a6..9b2e89fa 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift @@ -53,7 +53,7 @@ struct QwertySwitchLanguageKeyModel(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { let current = currentTabLanguage(variableStates: states) if languages.0 == current { return KeyLabel(.selectable(languages.0.symbol, languages.1.symbol), width: width, textColor: color) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift index 9c53d8c2..49c1b595 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift @@ -37,7 +37,7 @@ struct QwertyShiftKeyModel: } } - func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { if states.boolStates.isCapsLocked { return KeyLabel(.image("capslock.fill"), width: width, textColor: color) } else if states.boolStates.isShifted { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift index e02b5140..8c97f4f7 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift @@ -19,7 +19,7 @@ struct QwertySpaceKeyModel: init() {} - func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { switch states.keyboardLanguage { case .el_GR: return KeyLabel(.text("διάστημα"), width: width, textSize: .small, textColor: color) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift index 48be6a4e..969114b9 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift @@ -39,7 +39,7 @@ struct QwertyTabKeyModel: Q self.keySizeType = .functional(normal: rowInfo.normal, functional: rowInfo.functional, enter: rowInfo.enter, space: rowInfo.space) } - func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { switch SemiStaticStates.shared.needsInputModeSwitchKey { case true: switch states.keyboardLanguage { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift index d0af3089..fae49311 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift @@ -368,7 +368,7 @@ struct EmojiTab: View { private struct ExpandKeyModel: SimpleKeyModelProtocol { private var currentLevel: EmojiTabExpandModePreference.Level private var action: () -> Void - func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { KeyLabel(.image(self.currentLevel.icon), width: width, textSize: .max) } @@ -393,7 +393,7 @@ private struct ExpandKeyModel: SimpleKeyModelProtocol { private var action: () -> Void private var systemImage: String - func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { + func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { KeyLabel(.image(systemImage), width: width, textSize: .max) } @@ -430,7 +430,7 @@ private struct EmojiKeyModel(width: CGFloat, states _: VariableStates, theme _: ThemeData) -> KeyLabel { + func label(width: CGFloat, states _: VariableStates, theme _: ThemeData) -> KeyLabel { KeyLabel(.text(emoji), width: width, textSize: .max) } From d05616496183ced1f8634f4f937ee821cc4fc042 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 16:03:16 +0900 Subject: [PATCH 051/124] fix --- .../QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift index 9b2e89fa..41550099 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift @@ -62,7 +62,7 @@ struct QwertySwitchLanguageKeyModel Date: Sat, 23 Sep 2023 16:39:13 +0900 Subject: [PATCH 052/124] Update iOS14 termination news to iOS 15 termination news --- ...ionNews.swift => iOS15TerminationNews.swift} | 11 +++++------ MainApp/Tips/TipsView.swift | 10 +++++----- MainApp/UpdateInformationView.swift | 17 +++++++++++++++++ Resources/en.lproj/Localizable.strings | 9 ++++----- azooKey.xcodeproj/project.pbxproj | 8 ++++---- 5 files changed, 35 insertions(+), 20 deletions(-) rename MainApp/Tips/Articles/{iOS14TerminationNews.swift => iOS15TerminationNews.swift} (62%) diff --git a/MainApp/Tips/Articles/iOS14TerminationNews.swift b/MainApp/Tips/Articles/iOS15TerminationNews.swift similarity index 62% rename from MainApp/Tips/Articles/iOS14TerminationNews.swift rename to MainApp/Tips/Articles/iOS15TerminationNews.swift index f24fbb2b..5f7c6c2c 100644 --- a/MainApp/Tips/Articles/iOS14TerminationNews.swift +++ b/MainApp/Tips/Articles/iOS15TerminationNews.swift @@ -1,5 +1,5 @@ // -// iOS14TerminationNews.swift +// iOS15TerminationNews.swift // MainApp // // Created by ensan on 2022/11/08. @@ -9,22 +9,21 @@ import SwiftUI // swiftlint:disable:next type_name -struct iOS14TerminationNewsView: View { +struct iOS15TerminationNewsView: View { internal init(_ readThisMessage: Binding) { self._readThisMessage = readThisMessage } @Binding private var readThisMessage: Bool var body: some View { - TipsContentView("iOS14のサポートを終了します") { + TipsContentView("iOS15のサポートを終了します") { TipsContentParagraph { - Text("バージョン1.10(公開時期未定)以降のazooKeyではiOS14のサポートを終了する予定です。") + Text("バージョン2.3(公開時期未定)以降のazooKeyではiOS15のサポートを終了する予定です。") } TipsContentParagraph { - Text("iOS15以降では引き続き最新バージョンのazooKeyをご利用いただけます。") + Text("iOS16以降では引き続き最新バージョンのazooKeyをご利用いただけます。") } TipsContentParagraph { - Text("iOS14に対応する端末は全てiOS15にも対応しています。") Text("ぜひiOSをアップデートしてazooKeyをご利用ください。") } } diff --git a/MainApp/Tips/TipsView.swift b/MainApp/Tips/TipsView.swift index 39f29b77..f234e213 100644 --- a/MainApp/Tips/TipsView.swift +++ b/MainApp/Tips/TipsView.swift @@ -11,7 +11,7 @@ import SwiftUI struct TipsTabView: View { @EnvironmentObject private var appStates: MainAppStates - @AppStorage("read_article_iOS14_service_termination") private var readArticle_iOS14_service_termination = false + @AppStorage("read_article_iOS15_service_termination") private var readArticle_iOS15_service_termination = false var body: some View { VStack { @@ -27,17 +27,17 @@ struct TipsTabView: View { } NavigationLink("入力方法を選ぶ", destination: SelctInputStyleTipsView()) } - if #unavailable(iOS 15) { +// if #unavailable(iOS 16) { Section(header: Text("お知らせ")) { HStack { - if !readArticle_iOS14_service_termination { + if !readArticle_iOS15_service_termination { Image(systemName: "exclamationmark.circle.fill") .foregroundStyle(.red) } - NavigationLink("iOS14のサポートを終了します", destination: iOS14TerminationNewsView($readArticle_iOS14_service_termination)) + NavigationLink("iOS15のサポートを終了します", destination: iOS15TerminationNewsView($readArticle_iOS15_service_termination)) } } - } +// } Section(header: Text("便利な使い方")) { NavigationLink("片手モードを使う", destination: OneHandedModeTipsView()) diff --git a/MainApp/UpdateInformationView.swift b/MainApp/UpdateInformationView.swift index 80d44c21..4187a10b 100644 --- a/MainApp/UpdateInformationView.swift +++ b/MainApp/UpdateInformationView.swift @@ -14,6 +14,23 @@ struct UpdateInformationView: View { Form { // version 2系 Group { + // version 2.2系 + Group { + VersionView("2.2", releaseDate: "2023年10月xx日") { + if #unavailable(iOS 16) { + ParagraphView("お知らせ。") { + "バージョン2.3以降でiOS15のサポートを終了します。iOS16以上で引き続きご利用いただけます。ご不便をおかけしますが、よろしくお願いいたします" + } + } + ParagraphView("予測変換を大幅に強化しました。") + ParagraphView("再変換を大幅に強化しました。") + ParagraphView("機能を改善しました。") { + "テキストを選択した際に表示していた「編集」機能を廃止しました" + "カーソルを動かした際、カーソルバーを表示するようにしました" + } + ParagraphView("その他辞書の改善を行いました。") + } + } // version 2.1系 Group { VersionView("2.1.2", releaseDate: "2023年07月27日") { diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 6c6fd6d9..7199cafa 100644 --- a/Resources/en.lproj/Localizable.strings +++ b/Resources/en.lproj/Localizable.strings @@ -380,11 +380,10 @@ "azooKeyユーザ辞書" = "azooKey's Text replacement"; "変換候補に単語を追加することができます。iOSの標準のユーザ辞書とは異なります。" = "You can add text replacements. It is different from thee device's text replacements."; -"iOS14のサポートを終了します" = "Support for iOS14 is ending"; -"バージョン1.10(公開時期未定)以降のazooKeyではiOS14のサポートを終了する予定です。" = "It is planned that azooKey after version 1.10 does not support iOS14."; -"iOS15以降では引き続き最新バージョンのazooKeyをご利用いただけます。" = "In iOS15 and later, you can still use latest version of azooKey."; -"iOS14に対応する端末は全てiOS15にも対応しています。" = "All devices supporting iOS14 support iOS15 too."; -"ぜひiOSをアップデートしてazooKeyをご利用ください。" = "Please update iOS and continue to use azooKey."; +"iOS15のサポートを終了します" = "Support for iOS15 is ending"; +"バージョン2.3(公開時期未定)以降のazooKeyではiOS15のサポートを終了する予定です。" = "Support for iOS 15 will be discontinued in azooKey version 2.3 (release date TBD) and beyond."; +"iOS16以降では引き続き最新バージョンのazooKeyをご利用いただけます。" = "You can continue using the latest version of azooKey on iOS 16 and later."; +"ぜひiOSをアップデートしてazooKeyをご利用ください。" = "Please update iOS and continue using azooKey."; "追加する" = "Add"; "詳細設定" = "Details"; diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index dc6ed723..7057d58c 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -44,7 +44,7 @@ 1A1ECCA2295DF8DE001AD7E0 /* DisplayedTextManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A1ECCA1295DF8DE001AD7E0 /* DisplayedTextManager.swift */; }; 1A1ECCA4295DF9D4001AD7E0 /* LiveConversionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A1ECCA3295DF9D4001AD7E0 /* LiveConversionManager.swift */; }; 1A1ECCA6295DFADF001AD7E0 /* InputManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A1ECCA5295DFADF001AD7E0 /* InputManager.swift */; }; - 1A273F97291A6B8B001E1B02 /* iOS14TerminationNews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A273F96291A6B8B001E1B02 /* iOS14TerminationNews.swift */; }; + 1A273F97291A6B8B001E1B02 /* iOS15TerminationNews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A273F96291A6B8B001E1B02 /* iOS15TerminationNews.swift */; }; 1A2B2B5F299480B40048332A /* UseMarkedTextTipsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2B2B5E299480B40048332A /* UseMarkedTextTipsView.swift */; }; 1A2B2B612994846B0048332A /* KeyboardBehaviorIssueAfterInstallTipsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2B2B602994846B0048332A /* KeyboardBehaviorIssueAfterInstallTipsView.swift */; }; 1A2C293926273E9900DFE465 /* DraggableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2C293826273E9900DFE465 /* DraggableView.swift */; }; @@ -250,7 +250,7 @@ 1A1ECCA1295DF8DE001AD7E0 /* DisplayedTextManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayedTextManager.swift; sourceTree = ""; }; 1A1ECCA3295DF9D4001AD7E0 /* LiveConversionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveConversionManager.swift; sourceTree = ""; }; 1A1ECCA5295DFADF001AD7E0 /* InputManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputManager.swift; sourceTree = ""; }; - 1A273F96291A6B8B001E1B02 /* iOS14TerminationNews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOS14TerminationNews.swift; sourceTree = ""; }; + 1A273F96291A6B8B001E1B02 /* iOS15TerminationNews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOS15TerminationNews.swift; sourceTree = ""; }; 1A2B2B5E299480B40048332A /* UseMarkedTextTipsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UseMarkedTextTipsView.swift; sourceTree = ""; }; 1A2B2B602994846B0048332A /* KeyboardBehaviorIssueAfterInstallTipsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardBehaviorIssueAfterInstallTipsView.swift; sourceTree = ""; }; 1A2C293826273E9900DFE465 /* DraggableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableView.swift; sourceTree = ""; }; @@ -859,7 +859,7 @@ isa = PBXGroup; children = ( 1A3A16032528BFF900A5BA4F /* SelctInputStyle.swift */, - 1A273F96291A6B8B001E1B02 /* iOS14TerminationNews.swift */, + 1A273F96291A6B8B001E1B02 /* iOS15TerminationNews.swift */, 1AF6A54625FCF1240037D5ED /* OneHandedModeTips.swift */, 1AF28CDF253C9FFC0012CF94 /* CursorMoveTips.swift */, 1A9218DD2550FB9C005F45C4 /* SmoothDeleteTipsView.swift */, @@ -1314,7 +1314,7 @@ 1AFA575A2583051500477DC2 /* CapslockTips.swift in Sources */, 1A73F20729C01B5700833C11 /* checkKeyboardActivation.swift in Sources */, 1A4057F7255843850073C6F7 /* LearningTypeSettingItemView.swift in Sources */, - 1A273F97291A6B8B001E1B02 /* iOS14TerminationNews.swift in Sources */, + 1A273F97291A6B8B001E1B02 /* iOS15TerminationNews.swift in Sources */, 1AFA57662584815B00477DC2 /* QwertyCustomKeysItemView.swift in Sources */, 1AFB68422518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift in Sources */, 1A5C7EAC25F36A6E00A7CBA8 /* PreferredLanguageSettingView.swift in Sources */, From b09def67d32fc2fc34d0ddd0132dcc2d5ed802d8 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 16:42:48 +0900 Subject: [PATCH 053/124] remvoe comment-out --- MainApp/Tips/TipsView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MainApp/Tips/TipsView.swift b/MainApp/Tips/TipsView.swift index f234e213..6b4402c3 100644 --- a/MainApp/Tips/TipsView.swift +++ b/MainApp/Tips/TipsView.swift @@ -27,7 +27,7 @@ struct TipsTabView: View { } NavigationLink("入力方法を選ぶ", destination: SelctInputStyleTipsView()) } -// if #unavailable(iOS 16) { + if #unavailable(iOS 16) { Section(header: Text("お知らせ")) { HStack { if !readArticle_iOS15_service_termination { @@ -37,7 +37,7 @@ struct TipsTabView: View { NavigationLink("iOS15のサポートを終了します", destination: iOS15TerminationNewsView($readArticle_iOS15_service_termination)) } } -// } + } Section(header: Text("便利な使い方")) { NavigationLink("片手モードを使う", destination: OneHandedModeTipsView()) From ea95f59445471fb609f5bea218b42add75a43c40 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 22:56:48 +0900 Subject: [PATCH 054/124] Add contact import feature --- AzooKeyCore/Package.swift | 2 +- .../KeyboardSetting/BoolKeyboardSetting.swift | 15 +++ Keyboard/Display/KeyboardViewController.swift | 68 +++++++++-- MainApp/Info.plist | 2 + .../ContactAuthManager.swift | 27 +++++ .../ContactImportSettingView.swift | 114 ++++++++++++++++++ MainApp/Setting/SettingTab.swift | 1 + .../Tips/Articles/FullAccessTipsView.swift | 1 + azooKey.xcodeproj/project.pbxproj | 16 +++ 9 files changed, 238 insertions(+), 8 deletions(-) create mode 100644 MainApp/Setting/ContactImportSetting/ContactAuthManager.swift create mode 100644 MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift diff --git a/AzooKeyCore/Package.swift b/AzooKeyCore/Package.swift index 51bbb3f5..870f6fec 100644 --- a/AzooKeyCore/Package.swift +++ b/AzooKeyCore/Package.swift @@ -39,7 +39,7 @@ let package = Package( dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), - .package(url: "https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter", branch: "feature/prediction_candidate") + .package(url: "https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter", branch: "develop") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift index af687299..f3e49d95 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift @@ -215,6 +215,21 @@ public extension KeyboardSettingKey where Self == EnablePasteButton { static var enablePasteButton: Self { .init() } } +// TODO: Localize +/// 「連絡先」アプリの名前情報を読み込む設定 +/// - note: この機能はフルアクセスがないと実現できない +public struct EnableContactImport: BoolKeyboardSettingKey { + public static let title: LocalizedStringKey = "変換に連絡先データを利用" + public static let explanation: LocalizedStringKey = "「連絡先」アプリに登録された氏名のデータを変換に利用します" + public static let defaultValue = false + public static let key: String = "enable_contact_import" + public static let requireFullAccess: Bool = true +} + +public extension KeyboardSettingKey where Self == EnableContactImport { + static var enableContactImport: Self { .init() } +} + /// クリップボード履歴マネージャを有効化する設定 /// - note: この機能はフルアクセスがないと実現できない public struct EnableClipboardHistoryManagerTab: BoolKeyboardSettingKey { diff --git a/Keyboard/Display/KeyboardViewController.swift b/Keyboard/Display/KeyboardViewController.swift index 5ce7ea85..61ecffed 100644 --- a/Keyboard/Display/KeyboardViewController.swift +++ b/Keyboard/Display/KeyboardViewController.swift @@ -7,6 +7,7 @@ // import AzooKeyUtils +import Contacts import KanaKanjiConverterModule import KeyboardViews import SwiftUI @@ -158,15 +159,68 @@ final class KeyboardViewController: UIInputViewController { SemiStaticStates.shared.setHapticsAvailable() SemiStaticStates.shared.setHasFullAccess(self.hasFullAccess) - @KeyboardSetting(.useOSUserDict) var useOSUserDict - if useOSUserDict { - Task { + Task { + @KeyboardSetting(.useOSUserDict) var useOSUserDict + var dict: [DicdataElement] = [] + if useOSUserDict { let lexicon = await self.requestSupplementaryLexicon() - let dict = lexicon.entries.map {entry in DicdataElement(word: entry.documentText, ruby: entry.userInput.toKatakana(), cid: CIDData.固有名詞.cid, mid: MIDData.一般.mid, value: -6)} - KeyboardViewController.action.sendToDicdataStore(.importOSUserDict(dict)) + dict = lexicon.entries.map {entry in DicdataElement(word: entry.documentText, ruby: entry.userInput.toKatakana(), cid: CIDData.固有名詞.cid, mid: MIDData.一般.mid, value: -6)} } - } else { - KeyboardViewController.action.sendToDicdataStore(.importOSUserDict([])) + @KeyboardSetting(.enableContactImport) var enableContactImport + if enableContactImport && self.hasFullAccess && CNContactStore.authorizationStatus(for: .contacts) == .authorized { + let contactStore: CNContactStore = CNContactStore() + let keys = [ + CNContactFamilyNameKey, + CNContactPhoneticFamilyNameKey, + CNContactMiddleNameKey, + CNContactPhoneticMiddleNameKey, + CNContactGivenNameKey, + CNContactPhoneticGivenNameKey, + CNContactOrganizationNameKey, + CNContactPhoneticOrganizationNameKey + ] as [NSString] + + struct NamePair: Hashable { + var name: String + var phoneticName: String + var isValid: Bool { + !name.isEmpty && !phoneticName.isEmpty + } + } + + var familyNames: Set = [] + var middleNames: Set = [] + var givenNames: Set = [] + var orgNames: Set = [] + var fullNames: Set = [] + + try contactStore.enumerateContacts(with: CNContactFetchRequest(keysToFetch: keys)) { contact, _ in + familyNames.update(with: NamePair(name: contact.familyName, phoneticName: contact.phoneticFamilyName)) + middleNames.update(with: NamePair(name: contact.middleName, phoneticName: contact.phoneticMiddleName)) + givenNames.update(with: NamePair(name: contact.givenName, phoneticName: contact.phoneticGivenName)) + orgNames.update(with: NamePair(name: contact.organizationName, phoneticName: contact.phoneticOrganizationName)) + fullNames.update(with: NamePair( + name: contact.familyName + contact.middleName + contact.givenName, + phoneticName: contact.phoneticFamilyName + contact.phoneticMiddleName + contact.phoneticGivenName + )) + } + for item in familyNames where item.isValid { + dict.append(DicdataElement(word: item.name, ruby: item.phoneticName, cid: CIDData.人名姓.cid, mid: MIDData.人名姓.mid, value: -6)) + } + for item in middleNames where item.isValid { + dict.append(DicdataElement(word: item.name, ruby: item.phoneticName, cid: CIDData.人名一般.cid, mid: MIDData.一般.mid, value: -6)) + } + for item in givenNames where item.isValid { + dict.append(DicdataElement(word: item.name, ruby: item.phoneticName, cid: CIDData.人名名.cid, mid: MIDData.人名名.mid, value: -6)) + } + for item in fullNames where item.isValid { + dict.append(DicdataElement(word: item.name, ruby: item.phoneticName, cid: CIDData.人名一般.cid, mid: MIDData.一般.mid, value: -10)) + } + for item in orgNames where item.isValid { + dict.append(DicdataElement(word: item.name, ruby: item.phoneticName, cid: CIDData.固有名詞組織.cid, mid: MIDData.組織.mid, value: -7)) + } + } + KeyboardViewController.action.sendToDicdataStore(.importOSUserDict(dict)) } } diff --git a/MainApp/Info.plist b/MainApp/Info.plist index 0570316f..f3ab887b 100644 --- a/MainApp/Info.plist +++ b/MainApp/Info.plist @@ -2,6 +2,8 @@ + NSContactsUsageDescription + 連絡先に登録された名前に基づいて変換するため CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName diff --git a/MainApp/Setting/ContactImportSetting/ContactAuthManager.swift b/MainApp/Setting/ContactImportSetting/ContactAuthManager.swift new file mode 100644 index 00000000..d383e23f --- /dev/null +++ b/MainApp/Setting/ContactImportSetting/ContactAuthManager.swift @@ -0,0 +1,27 @@ +// +// ContactAuthManager.swift +// azooKey +// +// Created by miwa on 2023/09/23. +// Copyright © 2023 DevEn3. All rights reserved. +// + +import Contacts +import Foundation + +struct ContactAuthManager { + let contactStore: CNContactStore = CNContactStore() + var authState: CNAuthorizationStatus { + CNContactStore.authorizationStatus(for: .contacts) + } + + func requestAuthForContact(callback: @escaping ((granted: Bool, error: (any Error)?)) -> Void) { + // notDeterminedの場合のみ利用可能 + // deniedの場合は明示的に設定アプリを開いてもらう必要がある + if CNContactStore.authorizationStatus(for: .contacts) == .notDetermined { + contactStore.requestAccess(for: .contacts) { (granted, error) in + callback((granted, error)) + } + } + } +} diff --git a/MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift b/MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift new file mode 100644 index 00000000..a362f544 --- /dev/null +++ b/MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift @@ -0,0 +1,114 @@ +// +// ContactImportSettingView.swift +// azooKey +// +// Created by miwa on 2023/09/23. +// Copyright © 2023 DevEn3. All rights reserved. +// + +import AzooKeyUtils +import KeyboardViews +import SwiftUI + +struct ContactImportSettingView: View { + @State private var manager = ContactAuthManager() + @State private var showExplanation = false + @State private var showRequireFullAccessAlert = false + @State private var setting: SettingUpdater + @State private var showAuthErrorMessage = false + + @MainActor init() { + self._setting = .init(initialValue: .init()) + } + + @MainActor private var disabled: Bool { + !SemiStaticStates.shared.hasFullAccess + } + + @MainActor private var enabledButDenied: Bool { + setting.value && manager.authState != .authorized + } + + @MainActor @ViewBuilder private var control: some View { + Toggle(isOn: $setting.value) { + HStack { + Text(EnableContactImport.title) + Button { + self.showExplanation = true + } label: { + Image(systemName: "questionmark.circle") + } + Image(systemName: "f.circle.fill") + .foregroundStyle(.purple) + if self.enabledButDenied { + Image(systemName: "exclamationmark.circle.fill") + .foregroundStyle(.red) + } + } + } + } + + var body: some View { + Group { + if disabled { + control + .disabled(true) + .onTapGesture { + showRequireFullAccessAlert = true + } + } else if enabledButDenied { + control + .disabled(true) + .onTapGesture { + showAuthErrorMessage = true + } + } else { + control + } + } + .onChange(of: setting.value) { enabled in + if enabled && manager.authState == .notDetermined { + manager.requestAuthForContact { (granted, _) in + if !granted { + self.showAuthErrorMessage = true + } + } + } else if enabled && manager.authState == .denied { + self.showAuthErrorMessage = true + } + } + .onAppear { + setting.reload() + } + .alert("設定を 有効化できません", isPresented: $showAuthErrorMessage) { + Button("「設定」アプリを開く") { + if let url = URL(string: UIApplication.openSettingsURLString) { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } + } + Button("キャンセル", role: .cancel) { + self.setting.value = false + } + } message: { + Text("「連絡先」へのアクセスを許可する必要があります") + } + .alert(EnableContactImport.explanation, isPresented: $showExplanation) { + Button("OK") { + self.showExplanation = false + } + } + .alert(EnableContactImport.explanation, isPresented: $showRequireFullAccessAlert) { + Button("キャンセル", role: .cancel) { + showRequireFullAccessAlert = false + } + if let url = URL(string: UIApplication.openSettingsURLString) { + Button("「設定」アプリを開く") { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + showRequireFullAccessAlert = false + } + } + } message: { + Text("この機能にはフルアクセスが必要です。この機能を使いたい場合は、「設定」>「キーボード」でフルアクセスを有効にしてください。") + } + } +} diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index 6f5a30ef..6911decb 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -86,6 +86,7 @@ struct SettingTabView: View { BoolSettingView(.typographyLetter) BoolSettingView(.unicodeCandidate) MarkedTextSettingView(.markedTextSetting) + ContactImportSettingView() NavigationLink("絵文字と顔文字", destination: AdditionalDictManageView()) } diff --git a/MainApp/Tips/Articles/FullAccessTipsView.swift b/MainApp/Tips/Articles/FullAccessTipsView.swift index 5a254122..ddfa1443 100644 --- a/MainApp/Tips/Articles/FullAccessTipsView.swift +++ b/MainApp/Tips/Articles/FullAccessTipsView.swift @@ -38,6 +38,7 @@ struct FullAccessTipsView: View { BoolSettingView(.enablePasteButton) } BoolSettingView(.enableClipboardHistoryManagerTab) + ContactImportSettingView() TipsContentParagraph { Text("フルアクセスをオンにすると、変換候補を長押しすることでキーボード上で誤変換を報告できるようになります。") diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index 7057d58c..af46be44 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -169,6 +169,8 @@ 1AFB68422518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFB68412518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift */; }; 1AFB685328D56F1800B5C717 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1AC5876825D930D000BB060E /* Localizable.strings */; }; 1AFE773026077E0E0041D74D /* WalkthroughState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFE772F26077E0E0041D74D /* WalkthroughState.swift */; }; + 557D9DFB2ABEE7970028F3A0 /* ContactAuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557D9DFA2ABEE7970028F3A0 /* ContactAuthManager.swift */; }; + 557D9DFD2ABEF6560028F3A0 /* ContactImportSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557D9DFC2ABEF6560028F3A0 /* ContactImportSettingView.swift */; }; 5598472E2AB84F5200B18C15 /* PredictionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5598472D2AB84F5200B18C15 /* PredictionManager.swift */; }; /* End PBXBuildFile section */ @@ -359,6 +361,8 @@ 1AFA57652584815A00477DC2 /* QwertyCustomKeysItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QwertyCustomKeysItemView.swift; sourceTree = ""; }; 1AFB68412518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSourceSoftwaresLicenseView.swift; sourceTree = ""; }; 1AFE772F26077E0E0041D74D /* WalkthroughState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalkthroughState.swift; sourceTree = ""; }; + 557D9DFA2ABEE7970028F3A0 /* ContactAuthManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactAuthManager.swift; sourceTree = ""; }; + 557D9DFC2ABEF6560028F3A0 /* ContactImportSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImportSettingView.swift; sourceTree = ""; }; 5598472D2AB84F5200B18C15 /* PredictionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PredictionManager.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -764,6 +768,7 @@ isa = PBXGroup; children = ( 1AC0315C25120A17004CA505 /* SettingTab.swift */, + 557D9DF92ABEE78D0028F3A0 /* ContactImportSetting */, 1A8E454528E138F300133D3B /* MarkedTextSetting */, 1A347FE628D22F8E007D7852 /* LiveConversionSetting */, 1AAC102529B25CF90020BDE9 /* KeyboardHeightSetting */, @@ -923,6 +928,15 @@ path = Theme; sourceTree = ""; }; + 557D9DF92ABEE78D0028F3A0 /* ContactImportSetting */ = { + isa = PBXGroup; + children = ( + 557D9DFA2ABEE7970028F3A0 /* ContactAuthManager.swift */, + 557D9DFC2ABEF6560028F3A0 /* ContactImportSettingView.swift */, + ); + path = ContactImportSetting; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1283,6 +1297,7 @@ 1A3022AF2631663200E4495C /* OnEnterBackground.swift in Sources */, 1A8E454728E1390100133D3B /* MarkedTextSettingView.swift in Sources */, 1AB8C3CE25E2509300D39BC5 /* CustomizeTabView.swift in Sources */, + 557D9DFB2ABEE7970028F3A0 /* ContactAuthManager.swift in Sources */, 1A3A07D8259C5FF500AE1C53 /* KeyboardLayoutTypeDetailsView.swift in Sources */, 1A9B0A6E2565797E004203BB /* ContactView.swift in Sources */, 1A5B1CE026D1E495007D4E1C /* MainApp.swift in Sources */, @@ -1333,6 +1348,7 @@ 1A855C7829EA8A6400DD3702 /* ShareWordView.swift in Sources */, 1AF616B4256D409E001A0B32 /* MemoryResetSetting.swift in Sources */, 1AE1913625D4A3370044EE4B /* ThemeShareView.swift in Sources */, + 557D9DFD2ABEF6560028F3A0 /* ContactImportSettingView.swift in Sources */, 1AFA57602584810800477DC2 /* Focus.swift in Sources */, 1A18424325DD6857003985AB /* FontPicker.swift in Sources */, 1A9B0A2D25635090004203BB /* EmojiKaomojiView.swift in Sources */, From 87443d89f873ea4df26bb7d80746f67c765fc812 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 23:24:00 +0900 Subject: [PATCH 055/124] Localize Info.plist --- MainApp/Info.plist | 2 +- .../ContactImportSettingView.swift | 11 ++-- Resources/InfoPlist.xcstrings | 53 +++++++++++++++++++ Resources/en.lproj/Localizable.strings | 46 ---------------- azooKey.xcodeproj/project.pbxproj | 4 ++ 5 files changed, 66 insertions(+), 50 deletions(-) create mode 100644 Resources/InfoPlist.xcstrings diff --git a/MainApp/Info.plist b/MainApp/Info.plist index f3ab887b..4fbb1641 100644 --- a/MainApp/Info.plist +++ b/MainApp/Info.plist @@ -3,7 +3,7 @@ NSContactsUsageDescription - 連絡先に登録された名前に基づいて変換するため + Use contacts to better conversion using name data CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName diff --git a/MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift b/MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift index a362f544..ff98c712 100644 --- a/MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift +++ b/MainApp/Setting/ContactImportSetting/ContactImportSettingView.swift @@ -16,6 +16,7 @@ struct ContactImportSettingView: View { @State private var showRequireFullAccessAlert = false @State private var setting: SettingUpdater @State private var showAuthErrorMessage = false + @State private var authorized: Bool = false @MainActor init() { self._setting = .init(initialValue: .init()) @@ -26,7 +27,7 @@ struct ContactImportSettingView: View { } @MainActor private var enabledButDenied: Bool { - setting.value && manager.authState != .authorized + !disabled && setting.value && !self.authorized } @MainActor @ViewBuilder private var control: some View { @@ -71,6 +72,9 @@ struct ContactImportSettingView: View { manager.requestAuthForContact { (granted, _) in if !granted { self.showAuthErrorMessage = true + self.authorized = false + } else { + self.authorized = true } } } else if enabled && manager.authState == .denied { @@ -78,9 +82,10 @@ struct ContactImportSettingView: View { } } .onAppear { - setting.reload() + self.authorized = manager.authState == .authorized + self.setting.reload() } - .alert("設定を 有効化できません", isPresented: $showAuthErrorMessage) { + .alert("設定を有効化できません", isPresented: $showAuthErrorMessage) { Button("「設定」アプリを開く") { if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url, options: [:], completionHandler: nil) diff --git a/Resources/InfoPlist.xcstrings b/Resources/InfoPlist.xcstrings new file mode 100644 index 00000000..d83ac8d7 --- /dev/null +++ b/Resources/InfoPlist.xcstrings @@ -0,0 +1,53 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "CFBundleDisplayName" : { + "comment" : "Bundle display name", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "azooKey" + } + } + } + }, + "CFBundleName" : { + "comment" : "Bundle name", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "azooKey" + } + } + } + }, + "custom keyboard file" : { + + }, + "json custom keyboard file" : { + + }, + "NSContactsUsageDescription" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using name data in 'Contacts' app, azooKey can perform more accurate conversion." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "「連絡先」の氏名の情報を利用してより精度の高い変換を行うことができます。" + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 7199cafa..ab57c52c 100644 --- a/Resources/en.lproj/Localizable.strings +++ b/Resources/en.lproj/Localizable.strings @@ -619,49 +619,3 @@ "入力中のテキストを保護 (試験版)" = "Protect composing text (experimental)"; "入力中のテキストを保護し、Webアプリなどでの入力において挙動を安定させます。\n試験的機能のため、仕様の変更、不具合などが発生する可能性があります。" = "By protecting composing text, azooKey will behave more stably in some web apps. \nSince this is an experimental feature, this feature may be discontinued without notice."; - -/* -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -"" = ""; -*/ diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index af46be44..d739d9d5 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -171,6 +171,7 @@ 1AFE773026077E0E0041D74D /* WalkthroughState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFE772F26077E0E0041D74D /* WalkthroughState.swift */; }; 557D9DFB2ABEE7970028F3A0 /* ContactAuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557D9DFA2ABEE7970028F3A0 /* ContactAuthManager.swift */; }; 557D9DFD2ABEF6560028F3A0 /* ContactImportSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557D9DFC2ABEF6560028F3A0 /* ContactImportSettingView.swift */; }; + 557D9DFF2ABF2B9D0028F3A0 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557D9DFE2ABF2B9D0028F3A0 /* InfoPlist.xcstrings */; }; 5598472E2AB84F5200B18C15 /* PredictionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5598472D2AB84F5200B18C15 /* PredictionManager.swift */; }; /* End PBXBuildFile section */ @@ -363,6 +364,7 @@ 1AFE772F26077E0E0041D74D /* WalkthroughState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalkthroughState.swift; sourceTree = ""; }; 557D9DFA2ABEE7970028F3A0 /* ContactAuthManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactAuthManager.swift; sourceTree = ""; }; 557D9DFC2ABEF6560028F3A0 /* ContactImportSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImportSettingView.swift; sourceTree = ""; }; + 557D9DFE2ABF2B9D0028F3A0 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = ""; }; 5598472D2AB84F5200B18C15 /* PredictionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PredictionManager.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -713,6 +715,7 @@ isa = PBXGroup; children = ( 1AC03158251103EF004CA505 /* Designs.xcassets */, + 557D9DFE2ABF2B9D0028F3A0 /* InfoPlist.xcstrings */, 1AC5876825D930D000BB060E /* Localizable.strings */, 1AE191FB25D7E3B40044EE4B /* AzooKeyIcon-Regular.otf */, 1A1A62F029C8BCA400EF7B26 /* Data */, @@ -1140,6 +1143,7 @@ 1A1A62F929C8BCD400EF7B26 /* emoji_all_E15.0.txt.gen in Resources */, 1A3DC1D22500D44E002CAA93 /* LaunchScreen.storyboard in Resources */, 1A1A630829C9C91A00EF7B26 /* emoji_dict_E14.0.txt.gen in Resources */, + 557D9DFF2ABF2B9D0028F3A0 /* InfoPlist.xcstrings in Resources */, 1AC5876525D930D000BB060E /* Localizable.strings in Resources */, 1AE191FC25D7E3B40044EE4B /* AzooKeyIcon-Regular.otf in Resources */, 1A1A62FB29C8BCD400EF7B26 /* emoji_all_E13.1.txt.gen in Resources */, From e6054ddcdba3a79d02068efa5da4165718fbbe4b Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 23:27:23 +0900 Subject: [PATCH 056/124] Add new setting --- docs/settings.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/settings.md b/docs/settings.md index be91cac2..c8bd6582 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -44,4 +44,10 @@ TBW フルアクセスがオンであり、かつフリック入力で左下に「地球儀キー」ではなく「カーソルバーキー」がある場合、カーソルバーキーの上フリックにペーストボタンを追加できます。 -なお、ペースト自体はアクションであるため、カスタムキーやカスタムタブのアクションとして設定することができます。 \ No newline at end of file +なお、ペースト自体はアクションであるため、カスタムキーやカスタムタブのアクションとして設定することができます。 + +## 変換に連絡先データを利用 + +「連絡先」アプリの氏名のデータを変換に利用します。知り合いの名前が打ちやすくなります。 + +なお、この機能にはフルアクセスと「連絡先」アプリへのアクセスの許可が必要です。 \ No newline at end of file From 5a107ac0ecfd437ae61f03c0f7c95b7bc38caf91 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 23 Sep 2023 23:28:48 +0900 Subject: [PATCH 057/124] Add new feature description --- MainApp/UpdateInformationView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MainApp/UpdateInformationView.swift b/MainApp/UpdateInformationView.swift index 4187a10b..ad460c12 100644 --- a/MainApp/UpdateInformationView.swift +++ b/MainApp/UpdateInformationView.swift @@ -25,6 +25,7 @@ struct UpdateInformationView: View { ParagraphView("予測変換を大幅に強化しました。") ParagraphView("再変換を大幅に強化しました。") ParagraphView("機能を改善しました。") { + "「連絡先」に登録されている氏名を読み込んで変換に利用できるようになりました" "テキストを選択した際に表示していた「編集」機能を廃止しました" "カーソルを動かした際、カーソルバーを表示するようにしました" } From ca38d163c0578327d61c31df54e51b0917fabc7c Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 00:56:49 +0900 Subject: [PATCH 058/124] Migrate new xcstrings --- .../KeyboardSetting/BoolKeyboardSetting.swift | 1 - .../Customize/CodableActionDataEditor.swift | 1 - MainApp/General/FallbackLink.swift | 6 + MainApp/General/HeaderLogoView.swift | 6 +- MainApp/General/Pickers/FontPicker.swift | 2 +- MainApp/Info.plist | 8 +- .../AdditionalDictManageView.swift | 4 +- .../FlickCustomKeySettingView.swift | 10 +- .../FontSizeSettingItemView.swift | 2 +- .../OpenSourceSoftwaresLicenseView.swift | 54 +- MainApp/Setting/SettingTab.swift | 2 +- .../Template/TemplateEditingView.swift | 16 +- Resources/InfoPlist.xcstrings | 30 +- Resources/Localizable.xcstrings | 9685 +++++++++++++++++ Resources/en.lproj/Localizable.strings | 621 -- Resources/ja.lproj/Localizable.strings | 7 - azooKey.xcodeproj/project.pbxproj | 32 +- 17 files changed, 9778 insertions(+), 709 deletions(-) create mode 100644 Resources/Localizable.xcstrings delete mode 100644 Resources/en.lproj/Localizable.strings delete mode 100644 Resources/ja.lproj/Localizable.strings diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift index f3e49d95..5e2dc970 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift @@ -215,7 +215,6 @@ public extension KeyboardSettingKey where Self == EnablePasteButton { static var enablePasteButton: Self { .init() } } -// TODO: Localize /// 「連絡先」アプリの名前情報を読み込む設定 /// - note: この機能はフルアクセスがないと実現できない public struct EnableContactImport: BoolKeyboardSettingKey { diff --git a/MainApp/Customize/CodableActionDataEditor.swift b/MainApp/Customize/CodableActionDataEditor.swift index 560bd779..11015948 100644 --- a/MainApp/Customize/CodableActionDataEditor.swift +++ b/MainApp/Customize/CodableActionDataEditor.swift @@ -40,7 +40,6 @@ extension CodableActionData { case .dismissKeyboard: return "キーボードを閉じる" case .enableResizingMode: return "片手モードをオンにする" case let .launchApplication(value): - // TODO: Localize switch value.scheme { case .azooKey: return "azooKey本体アプリを開く" diff --git a/MainApp/General/FallbackLink.swift b/MainApp/General/FallbackLink.swift index e58b511d..9b624292 100644 --- a/MainApp/General/FallbackLink.swift +++ b/MainApp/General/FallbackLink.swift @@ -36,6 +36,12 @@ struct FallbackLink: View { self.icon = icon } + init(verbatim title: String, destination: String, icon: Icon = .link) { + self.title = LocalizedStringKey("\(title)") + self.url = URL(string: destination)! + self.icon = icon + } + var body: some View { Button { // 外部ブラウザでURLを開く diff --git a/MainApp/General/HeaderLogoView.swift b/MainApp/General/HeaderLogoView.swift index 1d1ba7e1..0fa2d0c6 100644 --- a/MainApp/General/HeaderLogoView.swift +++ b/MainApp/General/HeaderLogoView.swift @@ -20,15 +20,15 @@ struct HeaderLogoView: View { Group { switch colorScheme { case .light: - Text("A") + Text(verbatim: "A") .font(Design.fonts.azooKeyIconFont(iconSize * 0.75)) .accessibilityLabel("azooKeyのロゴ") case .dark: - Text("B") + Text(verbatim: "B") .font(Design.fonts.azooKeyIconFont(iconSize * 0.75)) .accessibilityLabel("azooKeyのロゴ") @unknown default: - Text("azooKey") + Text(verbatim: "azooKey") .font(Font(UIFont.systemFont(ofSize: iconSize))) } } diff --git a/MainApp/General/Pickers/FontPicker.swift b/MainApp/General/Pickers/FontPicker.swift index e2fc809f..ed17dbef 100644 --- a/MainApp/General/Pickers/FontPicker.swift +++ b/MainApp/General/Pickers/FontPicker.swift @@ -69,7 +69,7 @@ struct FontPickView: View { Button("フォントを選択") { isFontPickerPresented = true } - Text("テキスト Text").font(selectedFont) + Text(verbatim: "テキスト Text").font(selectedFont) } .sheet(isPresented: $isFontPickerPresented, content: { FontPicker( diff --git a/MainApp/Info.plist b/MainApp/Info.plist index 4fbb1641..fdeb3dd1 100644 --- a/MainApp/Info.plist +++ b/MainApp/Info.plist @@ -2,8 +2,6 @@ - NSContactsUsageDescription - Use contacts to better conversion using name data CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -65,16 +63,18 @@ LSRequiresIPhoneOS + NSContactsUsageDescription + Use contacts to better conversion using name data UIAppFonts AzooKeyIcon-Regular.otf UIApplicationSceneManifest - UISceneConfigurations - UIApplicationSupportsMultipleScenes + UISceneConfigurations + UILaunchStoryboardName LaunchScreen diff --git a/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift b/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift index 362fa58f..385079af 100644 --- a/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift +++ b/MainApp/Setting/AdditionalDict/AdditionalDictManageView.swift @@ -143,11 +143,11 @@ struct AdditionalDictManageViewMain: View { Section(header: Text("利用するもの")) { Toggle(isOn: $viewModel.systemDict[.emoji]) { Text("絵文字") - Text("🥺🌎♨️") + Text(verbatim: "🥺🌎♨️") } Toggle(isOn: $viewModel.systemDict[.kaomoji]) { Text("顔文字") - Text("(◍•ᴗ•◍)") + Text(verbatim: "(◍•ᴗ•◍)") } } if self.style == .all { diff --git a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift index a37ee7d6..98bd28f9 100644 --- a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift +++ b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift @@ -75,11 +75,11 @@ struct FlickCustomKeysSettingSelectView: View { var body: some View { VStack { Picker(selection: $selection, label: Text("カスタムするキー")) { - Text("小゙゚").tag(CustomizableFlickKey.kogana) - Text("、。?!").tag(CustomizableFlickKey.kanaSymbols) - Text("あいう").tag(CustomizableFlickKey.hiraTab) - Text("abc").tag(CustomizableFlickKey.abcTab) - Text("☆123").tag(CustomizableFlickKey.symbolsTab) + Text(verbatim: "小゙゚").tag(CustomizableFlickKey.kogana) + Text(verbatim: "、。?!").tag(CustomizableFlickKey.kanaSymbols) + Text(verbatim: "あいう").tag(CustomizableFlickKey.hiraTab) + Text(verbatim: "abc").tag(CustomizableFlickKey.abcTab) + Text(verbatim: "☆123").tag(CustomizableFlickKey.symbolsTab) } .pickerStyle(.segmented) .padding() diff --git a/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift b/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift index bdc92ce5..07636170 100644 --- a/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift +++ b/MainApp/Setting/FontSizeSetting/FontSizeSettingItemView.swift @@ -98,6 +98,6 @@ private struct KeyView: View { RoundedRectangle(cornerRadius: 5) .stroke() .frame(width: size.width, height: size.height) - .overlay(Text("あ").font(.system(size: fontSize))) + .overlay(Text(verbatim: "あ").font(.system(size: fontSize))) } } diff --git a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift index c469b9b1..599beced 100644 --- a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift +++ b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift @@ -98,94 +98,94 @@ struct OpenSourceSoftwaresLicenseView: View { } Group { Section { - Text("SudachiDict").font(.title).padding() + Text(verbatim: "SudachiDict").font(.title).padding() Text("本アプリケーションは基礎的な語彙の基盤としてSudachiDictを使用しています。") FallbackLink("License", destination: "https://github.com/WorksApplications/SudachiDict/blob/develop/LICENSE-2.0.txt") - FallbackLink("SudachiDict", destination: "https://github.com/WorksApplications/SudachiDict") + FallbackLink(verbatim: "SudachiDict", destination: "https://github.com/WorksApplications/SudachiDict") } Section { - Text("IPAdic").font(.title).padding() + Text(verbatim: "IPAdic").font(.title).padding() Text("本アプリケーションは基礎的な語彙の基盤としてIPAdicを使用しています。") Text(license_ipadic) } Section { - Text("MeCab").font(.title).padding() + Text(verbatim: "MeCab").font(.title).padding() Text("本アプリケーションは形態素解析器としてMeCabを使用しています。") - FallbackLink("MeCab: Yet Another Part-of-Speech and Morphological Analyzer", destination: "https://taku910.github.io/mecab/") + FallbackLink(verbatim: "MeCab: Yet Another Part-of-Speech and Morphological Analyzer", destination: "https://taku910.github.io/mecab/") Text(license_mecab) } Section { - Text("mecab-ipadic-NEologd").font(.title).padding() + Text(verbatim: "mecab-ipadic-NEologd").font(.title).padding() Text("本アプリケーションは固有名詞などの解析のためmecab-ipadic-NEologdを使用しています。") FallbackLink("License", destination: "https://github.com/neologd/mecab-ipadic-neologd/blob/master/COPYING") - FallbackLink("mecab-ipadic-NEologd : Neologism dictionary for MeCab", destination: "https://github.com/neologd/mecab-ipadic-neologd") + FallbackLink(verbatim: "mecab-ipadic-NEologd : Neologism dictionary for MeCab", destination: "https://github.com/neologd/mecab-ipadic-neologd") } Section { - Text("Mozc").font(.title).padding() + Text(verbatim: "Mozc").font(.title).padding() Text("本アプリケーションはMozcの一部のデータを利用しています。") - FallbackLink("BSD 3-Clause \"New\" or \"Revised\" License", destination: "https://github.com/google/mozc/blob/master/LICENSE") - FallbackLink("Mozc", destination: "https://github.com/google/mozc") - Text("Copyright 2010-2022, Google Inc.") + FallbackLink(verbatim: "BSD 3-Clause \"New\" or \"Revised\" License", destination: "https://github.com/google/mozc/blob/master/LICENSE") + FallbackLink(verbatim: "Mozc", destination: "https://github.com/google/mozc") + Text(verbatim: "Copyright 2010-2022, Google Inc.") } Section { - Text("japanese-word2vec-model-builder").font(.title).padding() + Text(verbatim: "japanese-word2vec-model-builder").font(.title).padding() Text("本アプリケーションは変換精度の向上のためjapanese-word2vec-model-builderを使用しています。") FallbackLink("License", destination: "https://github.com/shiroyagicorp/japanese-word2vec-model-builder/blob/master/LICENSE") - FallbackLink("Japanese Word2Vec Model Builder", destination: "https://github.com/shiroyagicorp/japanese-word2vec-model-builder") + FallbackLink(verbatim: "Japanese Word2Vec Model Builder", destination: "https://github.com/shiroyagicorp/japanese-word2vec-model-builder") } Group { Section { - Text("Emoji-IME-Dictionary").font(.title).padding() + Text(verbatim: "Emoji-IME-Dictionary").font(.title).padding() Text("本アプリケーションは絵文字への変換候補を表示するためにEmoji-IME-Dictionaryのデータを使用しています。") FallbackLink("License", destination: "https://github.com/peaceiris/emoji-ime-dictionary/blob/main/LICENSE") - FallbackLink("Emoji-IME-Dictionary", destination: "https://github.com/peaceiris/emoji-ime-dictionary") + FallbackLink(verbatim: "Emoji-IME-Dictionary", destination: "https://github.com/peaceiris/emoji-ime-dictionary") } Section { - Text("Kaomojitoka to Google IME Dictionary").font(.title).padding() + Text(verbatim: "Kaomojitoka to Google IME Dictionary").font(.title).padding() Text("本アプリケーションは顔文字への変換候補を表示するためにKaomojitoka to Google IME Dictionaryのデータを使用しています。") FallbackLink("License", destination: "https://github.com/nikukyugamer/kaomojitoka-to-google-ime-dictionary/blob/master/LICENSE") FallbackLink( - "Kaomojitoka to Google IME Dictionary", + verbatim: "Kaomojitoka to Google IME Dictionary", destination: "https://github.com/nikukyugamer/kaomojitoka-to-google-ime-dictionary" ) } Section { - Text("Kaomojic").font(.title).padding() + Text(verbatim: "Kaomojic").font(.title).padding() Text("本アプリケーションは顔文字への変換候補を表示するためにKaomojicのデータを使用しています。") FallbackLink("License", destination: "https://github.com/mika-f/kaomojic/blob/develop/LICENSE") - FallbackLink("Kaomojic", destination: "https://github.com/mika-f/kaomojic") + FallbackLink(verbatim: "Kaomojic", destination: "https://github.com/mika-f/kaomojic") } } Section { - Text("CustardKit").font(.title).padding() + Text(verbatim: "CustardKit").font(.title).padding() Text("本アプリケーションで利用可能なカスタムタブのデータ構造の記述をCustardKitとしてオープンソースで公開し、アプリ内でも使用しています。") FallbackLink("License", destination: "https://github.com/ensan-hcl/CustardKit/blob/main/LICENSE") FallbackLink( - "CustardKit", + verbatim: "CustardKit", destination: "https://github.com/ensan-hcl/CustardKit" ) } Group { Section { - Text("Swift Algorithms").font(.title).padding() + Text(verbatim: "Swift Algorithms").font(.title).padding() Text("本アプリケーションはSwift Algorithmsを使用しています。") - FallbackLink("Apache License 2.0", destination: "https://github.com/apple/swift-algorithms/blob/main/LICENSE.txt") + FallbackLink(verbatim: "Apache License 2.0", destination: "https://github.com/apple/swift-algorithms/blob/main/LICENSE.txt") FallbackLink( - "Swift Algorithms", + verbatim: "Swift Algorithms", destination: "https://github.com/apple/swift-algorithms" ) } Section { - Text("Swift Collections").font(.title).padding() + Text(verbatim: "Swift Collections").font(.title).padding() Text("本アプリケーションはSwift Collectionsを使用しています。") - FallbackLink("Apache License 2.0", destination: "https://github.com/apple/swift-collections/blob/main/LICENSE.txt") + FallbackLink(verbatim: "Apache License 2.0", destination: "https://github.com/apple/swift-collections/blob/main/LICENSE.txt") FallbackLink( - "Swift Collections", + verbatim: "Swift Collections", destination: "https://github.com/apple/swift-collections" ) } diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index 6911decb..04f802f8 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -127,7 +127,7 @@ struct SettingTabView: View { HStack { Text("URL Scheme") Spacer() - Text("azooKey://").font(.system(.body, design: .monospaced)) + Text(verbatim: "azooKey://").font(.system(.body, design: .monospaced)) } HStack { Text("バージョン") diff --git a/MainApp/Setting/Template/TemplateEditingView.swift b/MainApp/Setting/Template/TemplateEditingView.swift index e9f6c974..9a423a57 100644 --- a/MainApp/Setting/Template/TemplateEditingView.swift +++ b/MainApp/Setting/Template/TemplateEditingView.swift @@ -180,13 +180,15 @@ struct RandomTemplateLiteralSettingView: View { self.template.literal = self.literal } - private func warning(_ type: Error) -> some View { - let warningSymbol = Image(systemName: "exclamationmark.triangle") - switch type { - case .nan: - return Text("\(warningSymbol)値が無効です。有効な数値を入力してください") - case .stringIsNil: - return Text("\(warningSymbol)文字列が入っていません。最低一つは必要です") + @ViewBuilder private func warning(_ type: Error) -> some View { + HStack { + Image(systemName: "exclamationmark.triangle") + switch type { + case .nan: + Text("値が無効です。有効な数値を入力してください") + case .stringIsNil: + Text("文字列が入っていません。最低一つは必要です") + } } } diff --git a/Resources/InfoPlist.xcstrings b/Resources/InfoPlist.xcstrings index d83ac8d7..47caa10f 100644 --- a/Resources/InfoPlist.xcstrings +++ b/Resources/InfoPlist.xcstrings @@ -1,13 +1,12 @@ { - "sourceLanguage" : "en", + "sourceLanguage" : "ja", "strings" : { "CFBundleDisplayName" : { "comment" : "Bundle display name", - "extractionState" : "extracted_with_value", "localizations" : { - "en" : { + "ja" : { "stringUnit" : { - "state" : "new", + "state" : "translated", "value" : "azooKey" } } @@ -15,21 +14,34 @@ }, "CFBundleName" : { "comment" : "Bundle name", - "extractionState" : "extracted_with_value", "localizations" : { - "en" : { + "ja" : { "stringUnit" : { - "state" : "new", + "state" : "translated", "value" : "azooKey" } } } }, "custom keyboard file" : { - + "localizations" : { + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } }, "json custom keyboard file" : { - + "localizations" : { + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } }, "NSContactsUsageDescription" : { "extractionState" : "manual", diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings new file mode 100644 index 00000000..2cc8faac --- /dev/null +++ b/Resources/Localizable.xcstrings @@ -0,0 +1,9685 @@ +{ + "sourceLanguage" : "ja", + "strings" : { + "" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "・%@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "・%@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "・カスタム書式に「yyyy/MM/dd hh:mm」と入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Input custom format as 'yyyy/MM/dd hh:mm'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "・名前を「タイムスタンプ」に設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set 'Name' as 'TimeStamp'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "・書式で「カスタム」を選択" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select 'カスタム' for 'Format'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "{{%@}}というテンプレートが見つかりません。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Template {{%@}} is not found" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "{{%@}}を新規作成" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create {{%@}}" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "{{%@}}を編集できます" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can edit {{%@}}" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "{{タイムスタンプ}}" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "{{TimeStamp}}" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "{{テンプレート名}}" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "{{TemplateName}}" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「%@(%@)」と言える" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can say \"%1$@(%2$@)\"" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「%@(%@)」の読み込みに成功しました" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Successfuly imported '%1$@'(%2$@)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「%@」を入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Input '%@'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「%@」を繰り返し入力" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Input '%@' repeatedly" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「2020ねん→令和2年」「れいわ2ねん→2020年」のように西暦と和暦を相互に変換して候補に表示します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Convert Gregorian year and Japanese year mutually and display candidates like 「2020ねん→令和2年」「れいわ2ねん→2020年」." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「u3042→あ」のように、入力されたunicode番号に対応する文字に変換します。接頭辞にはu, u+, U, U+が使えます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Convert Unicode order to letter and display candidates like 「u3042→あ」" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「yyyy/MM/dd hh:mm」というのは日付の書式の書き方で、「yyyy」が4桁の年、「MM」が2桁の月、「dd」は2桁の日付を指しています。「hh」と「mm」も同様に時間と分です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "'yyyy/MM/dd hh:mm' is the format of dates. 'yyyy' represents the current year in 4 digits, 'MM' represents the current month in 2 digits, 'dd' represents the current date in 2 digits. 'hh' and 'mm' represent the current hour and minute." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「いんてれsちんg」→「interesting」のように、ローマ字日本語入力中も英語への変換候補を表示します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display English word candidates during qwerty Japanese inputting like 「いんてれsちんg」→「interesting」." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「キーボード」を押して" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Push 'Keyboard'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「クリップボードの履歴」や「ペーストボタン」の機能を利用している際、頻繁に「ペーストの許可」を求めるダイアログが出ることがあります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When using features like 'clipboard history' or 'paste button,' you may see frequent dialogues requesting permission to paste." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「ペーストを許可」のダイアログについて" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "About the 'Allow Paste' Dialog" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「ほかのAppからペースト」について" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "About 'Paste from other apps'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「入力中のテキストを保護」の設定をオンにすることで解決する場合があります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn on the setting to 'Protect composing text' may resolve the issue." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「小゙゚」キーと「、。?!」キーで入力する文字をカスタマイズすることができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can register at most three letters on both keys 「小゙゚」 and 「、。?!」." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「片手」をタップします。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap '片手'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「空白」を長押しすると、カーソルバーが現れます。ホームボタンのない端末のフリック入力では左下の%@を押して表示することも可能です。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap and hold \"空白\" key, the cursor bar appears. If your device doesn't have the home button, you can push %@ and then the button appears." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「設定」アプリを開く" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open 'Settings' app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "「連絡先」アプリに登録された氏名のデータを変換に利用します" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use names in 'Contacts.app' in conversion to enable more accurate conversion." + } + } + } + }, + "「連絡先」へのアクセスを許可する必要があります" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You need to grant access to \"contacts\"" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + } + } + }, + "%@ %@に指を置いて左右になぞることでカーソルが滑らかに移動します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "By putting your finger on the %1$@ %2$@ and tracing it, the cursor moves smoothly as you move your finger." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@キーボードの種類 (現在: %@)" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ keyboard layout (current: %2$@)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@というテンプレートが見つかりません。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Template '%@' cannot be found" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@など" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@, etc" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@の隣までカーソルを移動" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move cursor next to %@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@の隣まで削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete until %@ is found" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@をタップするとリセットされます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To reset, tap %@." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@をタップすると完了します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To finish resizing, tap %@." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@を押して完了したあとは通常のキーボードと同様に使えます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "After tap %@ and resizing has finished, you can use the keyboard in the same way as the normal mode." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@を押すと再度編集できます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To resize the keyboard, tap %@." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@を押すと通常の両手モードに戻ります。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To escape one-handed mode, tap %@." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@を編集できます" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ can be edited" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@を長押しでペースト" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Longpress %@ to paste" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@文字ずつカーソルを移動" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move cursor for %@ characters repeatedly" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@文字ずつ削除" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete %@ character repeatedly" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@文字分カーソルを移動" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move cursor for %@ characters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@文字削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete %@ character" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@画像を選び直す" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@Change image" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@画像を選ぶ" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@Select image" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%@配信" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@配信" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "%を新規作成" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create new template %@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "⚫︎%@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "⚫︎%@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "1文字ずつ移動したい場合は%@の%@部分または%@部分をタップすることでそれぞれの方向に1文字ずつ移動します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When you'd like to move by one character, tap the %1$@ %2$@ or %3$@ and the cursor moves each direction for one character." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "Acknowledgements" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Acknowledgements" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyが使えます!" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can use azooKey now!" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyが開かれました!" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You enabled azooKey!" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyでは「テンプレート」という機能を使うことで、時刻や乱数などを用いた高度な変換を定義することが可能です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using the 'Template' feature, you can define special conversions relating to dates and random values." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyではキーボード上で文字を拡大して表示することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On azooKey, you can zoom letters and check them." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyではこの他にも、「ズレ」を設定することで昨日や明日の日付を表示したり、乱数を用いるテンプレートを設定したりすることができます。お試しください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "In azooKey, you can also set yesterday or tomorrow's date using 'delta' and templates that use random values. Let's try!" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyでは一部キーのカスタマイズが可能です。「設定」タブから変更できます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "With azooKey, you can customize some of the keys. You can change keys on the Settings tab." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyでは片手モードを利用可能です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "In azooKey, you can use one-handed mode." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyとアプリの相性の問題で、入力がうまくいかないケースがあります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "There are some cases where input fails in certain application, because they are incompatible." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyのソースコードを閲覧する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Review the implementation of azooKey" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyのロゴ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "logo of azooKey" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyの設定タブよりキーの文字サイズを設定することが可能です。そちらもお試しください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On the Settings tab in azooKey, you can set key font size. Please try it." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyは、キーボードの振動フィードバックや、キーボードからのペーストを実現するために、フルアクセスの許可が必要です。フルアクセスを許可していただくことで、これらの機能が使用できます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "azooKey requires full access permission in order to enable features such as keyboard haptics and pasting from the keyboard. By granting full access, these features can be utilized." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyはオープンソースソフトウェアであり、GitHubでソースコードを公開しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "azooKey is open source software and its source code is available on GitHub." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyはクリップボードの履歴を保存するため、定期的にクリップボードをチェックします。また、ペーストする際にもクリップボードの情報を利用します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "azooKey periodically checks the clipboard to save its history, and also uses its information when pasting." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyは安全なキーボードアプリであり、ユーザの明示的な同意なく、個人情報を外部に送信したり、保存したりすることはありません。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "azooKey is a safe keyboard app and does not transmit or store personal information without the explicit consent of the user." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyユーザ辞書" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "azooKey's Text replacement" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyをインストールした直後、特定のアプリでキーボードが開かないことがあります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Immediately after installing azooKey, the keyboard may not open in certain applications." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyをオンにして" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn on azooKey" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyをお楽しみください!" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enjoy azooKey!" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyを使う前に、iPhoneのキーボードのリストにazooKeyを追加する必要があります" : { + "comment" : "Localizable.strings\n azooKey\n\n Created by ensan on 2021/02/14.\n Copyright © 2021 ensan. All rights reserved.", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Before using azooKey, you need to add azooKey into the list of device keyboards" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyを使ってくれてありがとう!" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Thank you for using azooKey!" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKeyを拡張する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Extend azooKey" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "azooKey本体アプリを開く" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open azooKey.app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "Caps lock" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Caps lock" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "Caps lockのモードの切り替え" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toggle caps lock" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "Configuring open access for a custom keyboard | Apple Developer Documentation (英語)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configuring open access for a custom keyboard | Apple Developer Documentation" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "iCloudから読み込む" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Import from iCloud" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "iOS15のサポートを終了します" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Support for iOS15 is ending" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "iOS16以降では引き続き最新バージョンのazooKeyをご利用いただけます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can continue using the latest version of azooKey on iOS 16 and later." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "License" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "License" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "macOSなどに搭載されている、入力中の文字列を自動的に変換する「ライブ変換」が利用できます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can use 'Live Conversion' with which hiragana characters you input are immediately converted into kanji text. This feature is often used in macOS, and now this feature is available on iOS!" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "OK" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "OSのユーザ辞書の利用" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use device text replacement" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "OS標準のユーザ辞書を利用します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use device text replacement and display the candidates." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "unicode変換" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unicode letters conversion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "URL Scheme" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL Scheme" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "URLから読み込む" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Import from URL" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "URLが間違っている可能性があります" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wrong URL" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "URLをコピーします。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Copy URL" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "URLを入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "URLを取得中" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Getting URL" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ver %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "ver %@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "View azooKey on GitHub" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "View azooKey on GitHub" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "Web検索" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Google search" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "アイコンの名前" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name of icon" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "アイテム" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Items" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "アイテムを追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add new item" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "アクション" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actions" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "アクションを編集する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit press action" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "アクションを追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add new action" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "あずきのマークを押すと表示されます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tab bar will appear when you press azooKey's icon on the keyboard." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "あなたがよく使う仕事の挨拶やゲームの定型文、お気に入りの顔文字など、好きなものを並べたカスタムタブを作ることができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can create custom tabs where you can list your commonly used work greetings, game phrases, favorite emojis, and more." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "アプリを開く" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "インストール直後、特定のアプリでキーボードが開かない" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keyboard does not open in certain applications immediately after installation" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "オープンソースソフトウェア" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open source softwares (Japanese)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "おすすめ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Suggestion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "オプション" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Options" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "オプションの設定方法" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "How to specify options" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "お問い合わせ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contact" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "お問い合わせ内容を選んでください。ブラウザでGoogle Formが開きます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please select the type of inquiry. Google Form will open in your browser." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "お知らせ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "News" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カーソルバー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cursor bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カーソルバーの切り替え" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toggle show or not show cursor bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カーソルバーの表示" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show cursor bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カーソルバーを消すには、入力/削除を行うか、再び空白を長押ししてください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To hide the bar, you can simply input or delete letters, or tap and hold \"空白\" key again." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カーソルを移動する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move cursor easily" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カーソルを自由に移動する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move cursor easily" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カーソル移動" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Moving cursor" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタム" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムキーの設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit custom keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムするキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Key to be customized" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom tabs" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブがまだありません" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom tabs have yet created" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブの情報" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Information of custom tab" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブの管理" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage custom tabs" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブの読み込み" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Load custom tabs" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブはファイルとして共有可能です。パソコンで作ったファイルや他の人の作ったファイルを読み込んで利用できます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom tabs can be shared as files. You can load and use files created on your computer or files created by others." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブファイルの作り方" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "How to make custom tab files." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブをファイルとして外部で作成し、azooKeyに読み込むことができます。より高機能なタブの作成が可能です。詳しくは以下をご覧ください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can create custom tabs as files outside of this app and import them. You can create more high-functional tabs. For detail please check below." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブを作る" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Make custom tab" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブを使うにはタブバーを利用します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can use Tab Bar to move custom tabs." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタムタブ機能" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom Tabs feature" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "カスタム書式" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Custom format" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "から" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "starts" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーに表示される文字を設定します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set the label." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーのサイズ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Size of this key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの文字の大きさを指定できます。文字が大きすぎる場合表示が崩れることがあります。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can set the font size of keys. If the size is too large, the appearance can get collapsed." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの文字の色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of key labels" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの種類" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Type of this key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの編集" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of this key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの色を設定します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set the color of this key." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの表示サイズ" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Font size of key labels" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの見た目は「ラベル」で設定できます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can set labels for the appearance." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーの音" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable keyboard sounds" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの入力方式" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select input style" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの地球儀ボタンを長押しし、azooKeyを選択してください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap and hold the globe button on the keyboard, and select azooKey" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの種類" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keyboard Layout" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの種類 (現在: %@)" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keyboard layout (current: %@)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの種類をお選びください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select input style" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの種類を設定する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select input style" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの高さ" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keyboard height" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードの高さを調整できます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can edit keyboard height." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードを使えるようにする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Make keyboard able to use" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードを有効化する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable Keyboard" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードを閉じる" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dismiss keyboard" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーボードを開く" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open keyboard" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーをカスタマイズする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Customize keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーをドラッグして移動してください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Drag the key to move it." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーを押したときの動作をより詳しく設定します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set actions when you press this key in detail." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーを押した際に端末を振動させます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable haptics feedback when you press keys." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーを押した際に音を鳴らします♪" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Make sounds when you press keys♪" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーを押して入力される文字を設定します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set letters inputted when you press this key." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーを押して移動するタブを設定します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set the destination tab when you press this key." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーを追加する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add a new key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キーを長押ししたときの動作をより詳しく設定します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set actions when you longpress this key in detail." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "キャンセル" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancel" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ギリシャ語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Greek" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "クモの絵文字を非表示" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forbid spider emojis" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "クリア" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clear" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "クリップボードの履歴" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Clipboard histories" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "クリップボードの履歴を保存" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keep clipboard histories" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ゴキブリの絵文字を非表示" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forbid cockroach emojis" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ここでは「2020/01/23 01:23」という形式のタイムスタンプを作ってみます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Here we make '2020/01/23 01:23' style time stamp." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このアクションはiOSのメジャーアップデートで利用できなくなる可能性があります" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This action could be invalid in future iOS versions" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このアプリでは編集できないアクションです" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "An action which cannot be edited in this app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このアプリで作成" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Made in this app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このアプリについて" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "About azooKey" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このアプリを再び開いてください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open this app again" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このキーにはタブ移動以外のアクションが設定されています。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This key doesn't have a moving tab action." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このキーにはタブ移動以外のアクションが設定されています。現在のアクションを消去して移動するタブを設定するには「タブを設定する」を押してください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This key has an action other than tab navigation assigned to it. To clear the current action and set it to navigate tabs, press 'Set destination tab'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このキーには入力以外のアクションが設定されています。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This key doesn't have input action." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このキーには入力以外のアクションが設定されています。現在のアクションを消去して入力する文字を設定するには「入力を設定する」を押してください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This key has a non-input action assigned to it. To clear the current action and set it to input a character, press 'Set inputted letters'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このキーに長押しキーを追加する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add a new alternative key which appears when longpressed" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このキーは編集できません" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This key cannot be edited" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "このキーを並び替える" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rearrange this key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この列を削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete this column" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この単語をazooKeyの本体辞書に追加することを申請します。\n個人情報を含む単語は申請しないでください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This word is requested to be added to the main dictionary of azooKey. \nPlease do not submit words that contain personal information." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この単語をシェアする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share this word" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この操作は取り消せません。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This operation cannot be canceled." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この書式を使って他にもカスタマイズが可能です。「hh」ではなく「HH」を使うことで24時間表記にすることができます。また「M」一文字を使った場合は「01」月ではなく「1」月と表示されます。「ss」で秒を、「EEE」で曜日を、「a」で午前/午後を表示することもできます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using this format, you can define other styles. Using 'HH' instead of 'hh', you can get 24-hour notation. Using only 'M', it displays '1月', not '01月'. 'ss' represents the current second, 'EEE' represents the current day, 'a' represents AM or PM." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この機能にはフルアクセスが必要です。この機能を使いたい場合は、「設定」>「キーボード」でフルアクセスを有効にしてください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This feature requires full access. To use this feature, please enable full access at 'Settings' > 'Keyboard'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この行を削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete this row" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "この設定をしないとキーボードが使えません" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Without this operation you cannot use azooKey" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "コピーした文字列の履歴を保存し、専用のタブから入力できるようにします。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keeping histories of copied text, and make it possible to input them from clipboard history tab." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "コピーする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Copy" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "これはazooKeyの問題ではなく、OS側のデータの更新が遅れている可能性があります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This may not be an azooKey issue, but a delay in updating the data on the OS side." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "これまでの学習を反映しない" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ignore memories" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "サイズの調整モードがオンになります。左右の白い部分をドラッグし、好みのサイズに調整してください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Resizing mode becomes enabled. Drag the white part at the sides and adjust the keyboard to your suitable size." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "サウンド" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sounds" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "サウンドと振動" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Keyboard Feedbacks" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "サブのラベル" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sub label" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "サンプル" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sample" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "シェアする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "システムアイコン" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "System icon" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "しない" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Disabled" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ショートカットを実行" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Run shortcut" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ショートカットを実行する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Run shortcut" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "スクロール式のカスタムタブを作る" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Make scroll style custom tabs" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "スクロール方向" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Scroll direction" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ズレ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delta" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ぜひiOSをアップデートしてazooKeyをご利用ください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please update iOS and continue using azooKey." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "そのまま入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Direct input style" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "その他の質問・連絡など" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Other inquiries or contacts" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "その他の質問・連絡などはメールでお寄せください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "For other inquiries or contacts, please send us an email." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ダークモードで使用" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use in dark mode" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タイムスタンプを使う" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use timestamp" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タイムスタンプを設定する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use timestamp" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ダイレクト" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Direct" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabs" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブの名前" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tab Name" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブの移動" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move to tab" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーに「コピー履歴」ボタンを追加しました。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "'コピー履歴' button is added into tab bar." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーに追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add to tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーに追加する" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add to tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーに追加済み" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Already in tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーの切り替え" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toggle show or not show tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーの編集" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーの表示" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーボタン" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tab bar button" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーを編集" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit tab bar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブバーを編集し、タブの並び替え、削除、追加を行ったり、文字の入力やカーソルの移動など様々な機能を追加することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can edit the tab bar. You can rearrange, delete, append tabs and also add features like inputting, moving the cursor, and so on." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブを設定する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set destination tab" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブを選択" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select destination tab" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "タブ名" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tab Name" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "データが取得できませんでした" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Failed to get data from URL" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "データの更新処理中です" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data update in progress" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "テキスト" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Text" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "デフォルトに戻す" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "テンプレート" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Templates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "テンプレートの管理" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Manage templates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "テンプレートを編集" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit template" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "テンプレートを編集する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit template" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "テンプレートを選ぶ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select template" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "テンプレート名" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name of template" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "どちらの入力方式でも%@は大文字固定になっていることを意味します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "In both input styles, the mark %@ means that currently the keyboard is caps locked." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "とても反応しにくい" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Very insensitive" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "とても反応しやすい" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Very sensitive" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "どれだけ指を動かしたらフリックと判定するか調整できます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can adjust how much you move your finger to determine a flick." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "なお、「クリップボードの履歴」を有効にしていない場合、クリップボードの中身を定期的に取得することはありません。また、取得したクリップボードのテキストはアプリ内でのみ利用されます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Note that if you have not enabled 'clipboard history,' azooKey will not periodically access the clipboard. Also, the text obtained from the clipboard is only used within the app." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "なお、azooKeyはオープンソースであり、誰もが実装を確認することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Additionally, azooKey is an open-source keyboard app, allowing anyone to review the implementation." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "なお、アプリケーション側でカスタムキーボードの利用を禁止する設定がなされている場合もあります。再起動で治らない場合はそちらもご確認ください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "In another case, the application may be set to prohibit the use of the custom keyboard. If this is not fixed by restarting the application, please check there as well." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "なし" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "None" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "バージョン" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Version" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "バージョン2.3(公開時期未定)以降のazooKeyではiOS15のサポートを終了する予定です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Support for iOS 15 will be discontinued in azooKey version 2.3 (release date TBD) and beyond." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "バグの報告や機能のリクエストをしたい" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Report bugs or request new features" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ファイルを処理中" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Processing file" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ファイルを取得中" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Getting file" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フィードバックを募集します" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Feedback wanted" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フォントはiOSで標準的に利用される「ヒラギノ明朝」を用いています。明朝体の字形は手書きする際の規範的な字形と必ずしも一致しません。ご了承ください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The font is 'Hiragino Mincho' which is commonly used in iOS. Please note that the glyphs of Mincho style are not always consistent with normative glyphs in handwriting." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フォントを選択" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select font" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "プライバシーポリシー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Policy (Japanese)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ブラウザを開けませんでした" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Browser could not launched" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリックのキーボードでは削除%@キーを左にフリックすると、文頭まで削除することができます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you are using flick input style, by flicking delete key %@ left, you can delete to the beginning of the sentence." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリックの感度" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Flicking sensitivity" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリック入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Flick" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリック入力では、ひらがなタブの「小゙゚」キーと「、。?!」キーのフリックに最大3方向まで好きな文字を登録することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using flick input style, you can register at most three letters on the key 「小゙゚」 and 「、。?!」." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリック入力では「a/A」キーを上にフリックします。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using flick style, to flick \"a/A\" key, you can turn on caps lock." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリック入力では左上の「☆123」・ローマ字入力では左下の「123」「#+=」キーを長押ししても表示されます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using flick input style, you can also show it by longpressing ☆123 key at the left top edge of the keyboard. Using qwerty input style, you can show it by longpressing #+= key or 123 key at the left bottom edge of the keyboard." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリック式のカスタムタブを作る" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Make tenkey style custom tabs" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フリック式のカスタムタブを作成することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can make tenkey style custom tabs." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フルアクセスが必要な機能を使う" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use features requiring full access" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フルアクセスについて" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "About full access" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フルアクセスをオフにする(設定アプリが開きます)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn off full access (opens the Settings app)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フルアクセスをオンにする(設定アプリが開きます)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn on full access (opens the Settings app)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フルアクセスをオンにすると、変換候補を長押しすることでキーボード上で誤変換を報告できるようになります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When you turn on full access, you can report mis-conversions on the keyboard by long-pressing conversion candidates." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フルアクセスを有効化する際、以下のような警告が表示されますが、すべてのキーボードアプリで共通して表示されている警告です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The following warning appears when enabling full access, but it is a warning that is common to all keyboard apps." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "フルアクセスを許可しなくても、キーボードは完全に動作します。上記の機能を使わない場合は、オンにしないことを強くおすすめします。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The keyboard will function fully even without granting full access. It is strongly recommended not to turn on full access if you do not need to use the above features." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "プレビュー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Preview" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ペースト" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Paste" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ペーストする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Paste copied text" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ペーストボタン" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable paste button" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "まず「テンプレートの管理」から新しいテンプレートを作成します。画面右上の%@を押して、テンプレートを追加しましょう。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To begin with, let's make a new template on 'Manage templates'. Push the button %@ and add a new template." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "まずタブバーを表示します。変換候補欄を長押しするか記号タブキーを長押しすると表示されます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "First, display the tab bar. You can display the tab bar by longpressing empty candidates space or longpressing symbols tab key." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "また、フルアクセスをオンにしたあとでも、いつでもフルアクセスをオフにすることができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Furthermore, even after turning on full access, it is possible to turn it off at any time." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "まで" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "ends" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "メインとサブ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Main and sub" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "メインのラベル" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Main label" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "もっと便利にする" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "More useful" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ユーザ辞書" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Text replacement" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ユーザ辞書で作成したテンプレートを使う際は、%@という形式で記述します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When you use the template in the text replacement, input as '%@'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ゆっくり" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Slow" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "より強力な学習を有効化 (試験版)" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable more strong learning (experimental)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "より長い期間学習が保持されます。\n試験的機能のため、予告なく提供を終了する可能性があります。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Histories can be remembered much longer. \nSince this is an experimental feature, this feature may be discontinued without notice." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ライトモードで使用" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use in light mode" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ライブ変換" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Live Conversion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ライブ変換の設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings for Live Conversion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ライブ変換を使用しますか?" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable live conversion?" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ラベル" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Labels" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ラベルの種類" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Type of label" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ラベルを設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set labels" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ランダム" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Random" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "リセット" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "リセットする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ローマ字かな入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Roman to kana input style" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ローマ字入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Qwerty" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ローマ字入力では、数字タブの一部キーに好きな文字と長押ししたときの候補を登録することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using qwerty input style, you can register favorite letter on some of the keys in the number tab and on some of the variations which you can select by longpressing." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "ローマ字入力では「Aa」キーを長押しします。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Using roman style, tap and hold \"Aa\" key, you can turn on caps lock." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "一度端末を再起動していただくとデータが更新され、キーボードが使えるようになることがあります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Once you restart your device, the data will be updated and you may be able to use the keyboard." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "一度端末を再起動していただくと設定が反映されます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please reboot your device, and the setting can work." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "一行ずつ登録したい文字や単語を入力してください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "List up letters and sentences you want to use in this custom tab in line-separated format" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "一覧" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "List" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "上から順に実行されます" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actions are executed in order" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "上に行を追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insert a row above" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "上書き" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Overwrap" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "下にスクロールして「追加する」を押して" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Scroll down and push 'add'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "下に行を追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insert a row below" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "不具合報告" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Report a problem" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "不快な絵文字を表示しない" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Block unpleasant Emojis" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "人・動物・会社などの名前である" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "It is the name of persons, pets, and groups." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "今回は「タイムスタンプ」というテンプレートなので、%@と入力します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "We created 'Timestamp' template, so input %@." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "以上で設定が完了です。あとは実際に使ってみましょう。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All the settings are now done. Let's use it." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "以下は、フルアクセスをオンにすることで利用できる設定項目です。フルアクセスを必要とする機能は、すべてデフォルトで無効になっているため、フルアクセスを許可しただけでキーボードの振る舞いが変わることはありません。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The following are the settings that can be used when full access is turned on. As all functions requiring full access are disabled by default, simply granting full access will not change the behavior of the keyboard." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "以下は、フルアクセスをオンにすることで利用できる設定項目です。フルアクセスを必要とする設定は、すべてデフォルトで無効になっているため、フルアクセスを許可しただけでキーボードの振る舞いが変わることはありません。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Below are the settings that can be accessed by enabling Full Access. Settings requiring Full Access are all disabled by default, so simply granting Full Access will not change the keyboard's behavior." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "作る" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Make" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "作成したカスタムタブに移動するためにタブバーがあります。タブがいくつあっても簡単に移動できます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "There is a tab bar to navigate to the custom tabs you've created. You can easily switch between tabs no matter how many there are." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "使い方" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usage" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "便利な使い方" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Useful tips" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "保存" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "値が無効です。有効な数値を入力してください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The value is invalid. Please specify valid number" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "値の種類" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Type of value" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Input" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力される文字" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Inputted letters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力される文字とは異なっていても構いません。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Not necessarily equal to input letter." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力する文字" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Letters to input" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力の確定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Complete" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力を設定する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set inputted letters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力中のテキストを保護 (試験版)" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Protect composing text (experimental)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力中のテキストを保護し、Webアプリなどでの入力において挙動を安定させます。\n試験的機能のため、仕様の変更、不具合などが発生する可能性があります。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "By protecting composing text, azooKey will behave more stably in some web apps. \nSince this is an experimental feature, this feature may be discontinued without notice." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力中の文字列を自動的に変換します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hiragana characters you input are immediately converted into kanji text, without manual operation" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力方式" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Input style" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "入力方法を選ぶ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select input style" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "全角英数字(abc123)への変換候補を表示します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display full-width numbers and roman letters candidates like 'abc123'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "全角英数字変換" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Full-width numbers and roman letters candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "共有する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "最初の設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "First settings" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "最大限大きなサイズで文字が表示されます。右にスクロールすると途切れている文字を確認することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The letter is zoomed as large as possible. Scroll right to check cut-off letters." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "最後に表示していたタブ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Last used tab" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "分" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Minutes" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "利用するもの" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You use" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "利用規約" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Terms of use (Japanese)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Remove" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "削除キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "削除する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Remove" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "削除する文字数" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Count to delete" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "削除と順番" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete & Rearrange" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "動作なし" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No actions" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "動作の編集" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit actions" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "半角カタカナへの変換を候補に表示します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display half-width カタカナ(katakana) candidates." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "半角カナ変換" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Half-width kana candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "単語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Word" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "単語が空です" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Word is empty" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "参考情報" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "References" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "反応しにくい" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insensitive" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "反応しやすい" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sensitive" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "句読点キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese punctuation key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "右に列を追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insert a column to right" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "右端の値" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rightmost value" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "名前" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "名前が重複しています" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This name is already used" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "名前を入力してください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Please input name" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "和暦" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "困ったときは" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When in trouble" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "地球儀キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Globe key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "基本" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Basic" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "報告の際には、「アプリのバージョン」「変換候補と読みと順位」「ローマ字入力かフリック入力か」「学習のあり/なし」の情報がサーバに送信されます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When reporting, information such as the app version, conversion candidate, reading, ranking, input method (roman character input or flick input), and whether or not learning is enabled will be sent to the server." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "場所・建物などの名前である" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "It is the name of places and buildings" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換なし" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "None" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換に連絡先データを利用" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use contacts data for conversion" + } + } + } + }, + "変換候補" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補に単語を追加することができます。iOSの標準のユーザ辞書とは異なります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can add text replacements. It is different from thee device's text replacements." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補の文字の大きさを指定できます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can set the font size of candidates." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補の文字の色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補の背景色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Background color of candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補の表示サイズ" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Font size of candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補の追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Request to add a candidate for conversion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補の追加申請" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Request to add a candidate for conversion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換候補欄が空のときにタブバーボタンを表示します" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display tab bar button when there is no candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "変換精度向上のため、報告をいただけると大変助かります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reporting would be greatly appreciated as it helps improve conversion accuracy." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "大きな文字で表示する" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zoom in" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "大文字/小文字、拗音/濁音/半濁音の切り替え" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Change uppercase ⇆ lowercase" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "大文字に固定する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Caps Lock" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "大文字のみ入力するモード(Caps Lock)を利用できます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can use caps lock in azooKey." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "好きな文字や文章を並べたオリジナルのタブを作成することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can make your original tab includes letters and sentences you need to input daily." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "始める" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Start" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "学習する(デフォルト)" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use memorizing (default)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "学習のリセット" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset memories" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "学習の使用" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use memorizing" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "学習履歴をリセットします。よろしいですか?" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset memories. Is this alright?" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "学習機能" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Memories" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "完了" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Done" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "小数" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Decimals" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "小書き・濁点化キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese Voiced kana key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "少し速い" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fast" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "左に列を追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Insert a column to left" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "左下のカーソル移動キーの上フリックにペーストボタンを追加します" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add a paste button to the upper flick of the lower left cursor bar key." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "左端の値" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Leftmost value" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "手順を見る" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Check steps" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "押されているキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of selected keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "押した時の動作" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actions when select" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "押している間のアクション" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actions repeated during longpress" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "押し始めのアクション" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Actions done when longpress starts" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "拡張" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Extensions" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "指定しない" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Don't use" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "指定なし" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Not specified" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "振動フィードバック" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable keyboard haptics" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "操作性" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usability" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "改行キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Return key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "数字(ローマ字入力)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Numbers (qwerty style)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "数字タブの青枠部分に好きな記号や文字を割り当てられます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can register your favorite letters on blue framed keys." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "整数" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Integers" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Letters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字の入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Input letters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字の削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete letters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字の太さ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Font weight" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字を拡大するには、まず拡大したい文字を入力した上で変換候補を長押しします。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To zoom letters, you need to input the letters you want to zoom, and tap candidate and hold." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字を拡大表示する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zooming difficult letters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字を置換" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Replace characters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字列" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Words" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文字列が入っていません。最低一つは必要です" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "At least one string must be specified" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文頭まで一気に消す" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete to beginning of the sentence" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文頭まで削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete to beginning of the sentence" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "文頭まで削除する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete to beginning of the sentence" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "新しいカーソルバーを使う (試験版)" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use new cursor bar (experimental)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "新しいカーソルバーを有効化します。\n試験的機能のため、予告なく提供を終了する可能性があります。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable new cursor bar. \nSince this is an experimental feature, this feature may be discontinued without notice." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "新たな学習を停止" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stop memorizing" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Days" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語・英語に対応したカスタムタブを読み込んだ場合、これを選ぶことも可能です" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you have imported custom tabs that support Japanese or English, you can choose them as a default keyboard." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語(フリック入力)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese (flick style)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語(ローマ字入力)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese (qwerty style)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語(設定に合わせる)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese (follow your setting)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語タブキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Japanese tab key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語と英語それぞれで「ローマ字入力」または「フリック入力」を選ぶことが可能です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can select Qwerty and Flick input styles for each of Japanese and English." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "日本語入力中の英単語変換" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Conversion to English words during Japanese input" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "時刻" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "時間" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hours" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "普通" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Normal" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "暦の種類" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Calendar" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "更新" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Update" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "更新履歴" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Update histories (Japanese)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "書き出す" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Export" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "書式" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Format" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "書式の設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Format" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "書式はyyyyMMddhhmmssフォーマットで記述します。詳しい記法はインターネット等で確認できます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Formats can be specified by yyyyMMddhhmmss style. You can check details on the Internet." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "書式を入力" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Specify format" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションで利用可能なカスタムタブのデータ構造の記述をCustardKitとしてオープンソースで公開し、アプリ内でも使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "We have open-sourced the data structure description of available custom tabs in this application as CustardKit and also use it within the app." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションはMozcの一部のデータを利用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application utilizes some data from Mozc." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションはSwift Algorithmsを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses Swift Algorithms." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションはSwift Collectionsを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses Swift Collections." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは固有名詞などの解析のためmecab-ipadic-NEologdを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses mecab-ipadic-NEologd for the analysis of proper nouns and other specific terms." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは基礎的な語彙の基盤としてIPAdicを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses IPAdic as the foundation for basic vocabulary." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは基礎的な語彙の基盤としてSudachiDictを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses SudachiDict as the foundation for basic vocabulary." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは変換精度の向上のためjapanese-word2vec-model-builderを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses the japanese-word2vec-model-builder for improving conversion accuracy." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは多くのオープンソースソフトウェアを用いて作成されています。この場を借りて感謝申し上げます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application has been created using many open-source software components. We would like to take this opportunity to express our gratitude." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは形態素解析器としてMeCabを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses MeCab as its morphological analyzer." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは絵文字への変換候補を表示するためにEmoji-IME-Dictionaryのデータを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses data from \"Emoji-IME-Dictionary\" to display emoji conversion suggestions." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは顔文字への変換候補を表示するためにKaomojicのデータを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses data from \"Kaomojic\" to display emoticon conversion suggestions." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "本アプリケーションは顔文字への変換候補を表示するためにKaomojitoka to Google IME Dictionaryのデータを使用しています。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This application uses data from \"Kaomojitoka to Google IME Dictionary\" to display emoticon conversion suggestions." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "枠線の太さ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Border width" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "枠線の色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of border" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "横" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Horizontal" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "横方向キー数" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Row key count" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "機能の改善・追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Request a feature or improvement" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "次にユーザ辞書でテンプレートを使います。「追加する」から新規に単語を登録し、編集画面が開きます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Next, let's use this template in the text replacement. Tap 'Add' and new text replacement editing view opens." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "正しくない形式のファイルです" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Incorrectly formatted file" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "注意" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warning" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "準備は完了です!" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Preparation completed!" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "漢字を拡大表示する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zooming difficult letters" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "片手モードで解除ボタンを表示しない" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Do not display release button in one-handed mode" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "片手モードの際に表示される解除ボタンを非表示にします。片手モードの調整はタブバーのボタンから行えます。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hide the reset button displayed in one-handed mode. One-handed mode adjustment can be done from the tab bar button." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "片手モードをオン" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable one-handed mode" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "片手モードをオンにする" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable one-handed mode" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "片手モードを使う" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use one-handed mode" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "片手モードを利用する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use one-handed mode" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "特別なキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of special keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "特定のアプリケーションで入力がおかしくなる" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Input fails in certain applications" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "特殊キーの背景色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Background color of special keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "現在" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Current" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "現在のアクションを消去して入力する文字を設定するには「入力を設定する」を押してください" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To delete current actions and set inputted letters, please push 'set destination tab.'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "現在のアクションを消去して移動するタブを設定するには「タブを設定する」を押してください" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To delete current actions and set destination tab, please push 'set destination tab.'" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "現在は携帯電話式の入力については対応していません。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Currently, azooKey doesn't support the Japanese flip phone input style." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "由来" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Origin" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "申請する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Request adding word" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "申請中です" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Requesting" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "画像をトリミング" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trim image" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "画像を削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Remove image" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "登録したい文字や単語を順番に書いていくだけでスクロール式のカスタムタブを作成することができます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can make scroll style custom tabs only by listing up the words and sentences." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "目立たないキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of unimportant keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "着せ替え" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Themes" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "着せ替えが完成しました🎉" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your theme is completed 🎉" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "着せ替えを作成" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Make your theme" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "着せ替えを編集" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit theme" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "確定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Complete" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "秒" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seconds" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "移動" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "移動・追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move/Add" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "移動する文字数" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Count of movement" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "移動先:%@" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Destination: %@" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "移動先のタブ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tab to move" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "空白キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Space key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "端末の文字サイズの設定を変更しても、キーボードに表示される文字の大きさが変わらないことがあります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sometimes the setting of your device's font size doesn't affect the keyboard." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "端末の文字サイズ設定が反映されない" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Setting of device's font size doesn't work" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "第1言語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "First language" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "第2言語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Second language" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "絵文字" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Emoji" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "絵文字と顔文字" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Emojis and Kaomojis" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "絵文字と顔文字は別々にオン・オフを選択可能です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can decide whether you use emoji and whether you use kaomoji." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "絵文字と顔文字を設定しましょう" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Let's use emoji and kaomoji" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "絵文字の一覧を表示したい場合、標準の絵文字キーボードをご利用ください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you want to get the list of emoji, please use the device's emojis keyboard." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "絵文字や顔文字の変換候補を表示したい" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show Emoji and Kaomoji candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "編集が終わったら完了ボタンを押してください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "When you finish editing, push the 'Done' button." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "編集したいキーを選択してください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select the key to which you want to register." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "編集したい方向を選択してください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select the key to which you want to register." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "編集する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "編集画面で次のように設定します。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On the editing view, set as follows:" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "縦" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vertical" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "縦方向キー数" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Column key count" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "背景" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Background" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "背景の色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Background color" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "自動" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auto" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "自動的にタブバーに追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add to tab bar automatically" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "自動確定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Auto Prefix Completion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "自動確定の速さ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Speed of Auto Prefix Completion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "自動確定を使うと長い文章を打っているときに候補の選択がしやすくなります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "With auto-prefix-completion, selecting candidate is more easy when you are inputting long text." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "英字入力をした際、「𝕥𝕪𝕡𝕠𝕘𝕣𝕒𝕡𝕙𝕪」のような装飾字体を候補に表示します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display decorated font candidates like '𝕥𝕪𝕡𝕠𝕘𝕣𝕒𝕡𝕙𝕪' during English inputting." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "英語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "English" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "英語(フリック入力)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "English (flick style)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "英語(ローマ字入力)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "English (qwerty style)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "英語(設定に合わせる)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "English (follow your setting)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "英語タブキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "English tab key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "表示" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "表示する値(カンマ区切り)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The values to display (comma-separated)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "装飾英字変換" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Decorated letters candidates" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "西暦" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gregorian" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "西暦⇄和暦変換" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gregorian - Japanese calendar conversion" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "解除するにはもう一度キーを押してください。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "To unlock, push the key again." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "言語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Language" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "記号(ローマ字入力)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Symbols (qwerty style)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "記号タブキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Symbols tab key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "記号と数字(フリック入力)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Symbols and numbers (flick style)" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "設定アプリで「ほかのAppからペースト」を「許可」にすることで、ダイアログが出なくなります。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "By allowing 'Paste from other apps' in Settings, you can avoid these dialogs." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "設定アプリを開く" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Settings app" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "設定する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "設定は「設定タブ」でいつでも変えられます" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You can change settings on Settings tab anytime" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "設定を有効化できません" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This setting cannot be enabled" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "詳しい設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Details" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "詳細な設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "High-level settings" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "詳細設定" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Details" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "誤って削除してしまった場合は端末を振るか、入力欄を三本指でスワイプすることで取り消し操作を行うことが可能です。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If you mistakenly deleted letters, you could shake your device or swipe the input field with three fingers, and you can undo it." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読み" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ruby" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読みが空です" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ruby is empty" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読みと単語" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ruby and word" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読みに使用できない文字が含まれます。ひらがな、英字、数字を指定してください" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Contains unusable characters. Please use hiragana, roman letters, and numbers." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読み込みに失敗したカスタムタブ「%@」を書き出す" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Export custom tab '%@' that failed to load" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読み込み中" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Loading" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読み込み失敗" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Load failed" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読み込む" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Import" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読み込んだタブ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Imported tabs" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "読み込んだデータ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Imported data" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "識別子" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Identifier" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "識別子%@を持つカスタムタブが既に登録されています。上書きしますか?" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You have been already using a custom tab that has identifier %@. Do you overwrap it?" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "負の値を指定すると右側の文字を削除します" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Negative number means delete forward" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "負の値を指定すると左にカーソルが動きます" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Negative number means moving backward" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "追加" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "追加したテンプレートを選ぶと編集画面が開きます。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select the template you added, and the editing view opens." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "追加する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "通常キーの背景色" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Background color of normal keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "通常のキー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Color of normal keys" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "速い" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Very fast" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "選ぶ" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "長押し" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Longpress" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "長押しアクション" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Longpress action" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "長押しアクションを編集する" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit longpress action" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "長押しした時の候補" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Selectable variations when you longpress this key" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "長押し後表示される画面で「大きな文字で表示する」をタップします。" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap the button 'Zoom in'." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "閉じる" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "青枠部分" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Blue framed part" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "顔文字" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kaomoji" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "高度" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advanced" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + "黄色枠部分" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Yellow framed part" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings deleted file mode 100644 index ab57c52c..00000000 --- a/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,621 +0,0 @@ -/* - Localizable.strings - azooKey - - Created by ensan on 2021/02/14. - Copyright © 2021 ensan. All rights reserved. -*/ -"azooKeyを使う前に、iPhoneのキーボードのリストにazooKeyを追加する必要があります" = "Before using azooKey, you need to add azooKey into the list of device keyboards"; -"手順を見る" = "Check steps"; -"追加する" = "Adding"; -"下にスクロールして「追加する」を押して" = "Scroll down and push 'add'"; -"「キーボード」を押して" = "Push 'Keyboard'"; -"azooKeyをオンにして" = "Turn on azooKey"; -"このアプリを再び開いてください" = "Open this app again"; -"この設定をしないとキーボードが使えません" = "Without this operation you cannot use azooKey"; -"最初の設定" = "First settings"; -"キーボードの種類をお選びください" = "Select input style"; -"ライブ変換を使用しますか?" = "Enable live conversion?"; -"絵文字と顔文字を設定しましょう" = "Let's use emoji and kaomoji"; -"設定は「設定タブ」でいつでも変えられます" = "You can change settings on Settings tab anytime"; -"azooKeyが使えます!" = "You can use azooKey now!"; -"準備は完了です!" = "Preparation completed!"; -"キーボードの地球儀ボタンを長押しし、azooKeyを選択してください" = "Tap and hold the globe button on the keyboard, and select azooKey"; -"キーボードを開く" = "Open keyboard"; -"azooKeyが開かれました!" = "You enabled azooKey!"; -"azooKeyをお楽しみください!" = "Enjoy azooKey!"; -"始める" = "Start"; - -"使い方" = "Usage"; -"拡張" = "Extensions"; -"着せ替え" = "Themes"; -"設定" = "Settings"; - -"作る" = "Make"; -"選ぶ" = "Select"; -"着せ替えを作成" = "Make your theme"; -"着せ替えを編集" = "Edit theme"; - -"ライトモードで使用" = "Use in light mode"; -"ダークモードで使用" = "Use in dark mode"; - - -"キャンセル" = "Cancel"; -"完了" = "Done"; - -"背景" = "Background"; -"文字" = "Letters"; -"変換候補" = "Candidates"; -"キー" = "Keys"; - - -"%@画像を選ぶ" = "%@Select image"; -"%@画像を選び直す" = "%@Change image"; -"画像を削除" = "Remove image"; -"背景の色" = "Background color"; - -"画像をトリミング" = "Trim image"; - -"文字の太さ" = "Font weight"; - -"変換候補の文字の色" = "Color of candidates"; -"変換候補の背景色" = "Background color of candidates"; - -"キーの文字の色" = "Color of key labels"; -"通常キーの背景色" = "Background color of normal keys"; -"特殊キーの背景色" = "Background color of special keys"; -"枠線の色" = "Border color"; -"枠線の太さ" = "Border width"; - -"リセットする" = "Reset"; - -"編集する" = "Edit"; -"削除する" = "Remove"; - -"着せ替えが完成しました🎉" = "Your theme is completed 🎉"; -"シェアする" = "Share"; -"閉じる" = "Close"; - -"キーボードを使えるようにする" = "Make keyboard able to use"; -"キーボードを有効化する" = "Enable Keyboard"; -"便利な使い方" = "Useful tips"; -"困ったときは" = "When in trouble"; - -"入力方法を選ぶ" = "Select input style"; -"キーボードの入力方式" = "Select input style"; -"キーボードの種類を設定する" = "Select input style"; -"キーボードの種類 (現在: %@)" = "Keyboard layout (current: %@)"; -"%@キーボードの種類 (現在: %@)" = "%1$@ keyboard layout (current: %2$@)"; -"日本語・英語に対応したカスタムタブを読み込んだ場合、これを選ぶことも可能です" = "If you have imported custom tabs that support Japanese or English, you can choose them as a default keyboard."; - -"片手モードを使う" = "Use one-handed mode"; -"片手モードを利用する" = "Use one-handed mode"; -"azooKeyでは片手モードを利用可能です。" = "In azooKey, you can use one-handed mode."; -"まずタブバーを表示します。変換候補欄を長押しするか記号タブキーを長押しすると表示されます。" = "First, display the tab bar. You can display the tab bar by longpressing empty candidates space or longpressing symbols tab key."; -"「片手」をタップします。" = "Tap '片手'."; -"サイズの調整モードがオンになります。左右の白い部分をドラッグし、好みのサイズに調整してください。" = "Resizing mode becomes enabled. Drag the white part at the sides and adjust the keyboard to your suitable size."; -"%@をタップすると完了します。" = "To finish resizing, tap %@."; -"%@をタップするとリセットされます。" = "To reset, tap %@."; -"%@を押して完了したあとは通常のキーボードと同様に使えます。" = "After tap %@ and resizing has finished, you can use the keyboard in the same way as the normal mode."; -"%@を押すと再度編集できます。" = "To resize the keyboard, tap %@."; -"%@を押すと通常の両手モードに戻ります。" = "To escape one-handed mode, tap %@."; - -"カーソルを自由に移動する" = "Move cursor easily"; -"カーソルを移動する" = "Move cursor easily"; -"「空白」を長押しすると、カーソルバーが現れます。ホームボタンのない端末のフリック入力では左下の%@を押して表示することも可能です。" = "Tap and hold \"空白\" key, the cursor bar appears. If your device doesn't have the home button, you can push %@ and then the button appears."; -"黄色枠部分" = "Yellow framed part"; -"青枠部分" = "Blue framed part"; -"%@ %@に指を置いて左右になぞることでカーソルが滑らかに移動します。" = "By putting your finger on the %1$@ %2$@ and tracing it, the cursor moves smoothly as you move your finger."; -"1文字ずつ移動したい場合は%@の%@部分または%@部分をタップすることでそれぞれの方向に1文字ずつ移動します。" = "When you'd like to move by one character, tap the %1$@ %2$@ or %3$@ and the cursor moves each direction for one character."; -"カーソルバーを消すには、入力/削除を行うか、再び空白を長押ししてください。" = "To hide the bar, you can simply input or delete letters, or tap and hold \"空白\" key again."; - -"文頭まで一気に消す" = "Delete to beginning of the sentence"; -"文頭まで削除する" = "Delete to beginning of the sentence"; -"フリックのキーボードでは削除%@キーを左にフリックすると、文頭まで削除することができます。" = "If you are using flick input style, by flicking delete key %@ left, you can delete to the beginning of the sentence."; -"誤って削除してしまった場合は端末を振るか、入力欄を三本指でスワイプすることで取り消し操作を行うことが可能です。" = "If you mistakenly deleted letters, you could shake your device or swipe the input field with three fingers, and you can undo it."; - -"漢字を拡大表示する" = "Zooming difficult letters"; -"文字を拡大表示する" = "Zooming difficult letters"; -"azooKeyではキーボード上で文字を拡大して表示することができます。" = "On azooKey, you can zoom letters and check them."; -"文字を拡大するには、まず拡大したい文字を入力した上で変換候補を長押しします。" = "To zoom letters, you need to input the letters you want to zoom, and tap candidate and hold."; -"大きな文字で表示する" = "Zoom in"; -"長押し後表示される画面で「大きな文字で表示する」をタップします。" = "Tap the button 'Zoom in'."; -"最大限大きなサイズで文字が表示されます。右にスクロールすると途切れている文字を確認することができます。" = "The letter is zoomed as large as possible. Scroll right to check cut-off letters."; -"フォントはiOSで標準的に利用される「ヒラギノ明朝」を用いています。明朝体の字形は手書きする際の規範的な字形と必ずしも一致しません。ご了承ください。" = "The font is 'Hiragino Mincho' which is commonly used in iOS. Please note that the glyphs of Mincho style are not always consistent with normative glyphs in handwriting."; - -"大文字に固定する" = "Caps Lock"; - -"大文字のみ入力するモード(Caps Lock)を利用できます。" = "You can use caps lock in azooKey."; -"フリック入力では「a/A」キーを上にフリックします。" = "Using flick style, to flick \"a/A\" key, you can turn on caps lock."; -"ローマ字入力では「Aa」キーを長押しします。" = "Using roman style, tap and hold \"Aa\" key, you can turn on caps lock."; -"どちらの入力方式でも%@は大文字固定になっていることを意味します。" = "In both input styles, the mark %@ means that currently the keyboard is caps locked."; -"解除するにはもう一度キーを押してください。" = "To unlock, push the key again."; - -"タイムスタンプを使う" = "Use timestamp"; -"タイムスタンプを設定する" = "Use timestamp"; -"azooKeyでは「テンプレート」という機能を使うことで、時刻や乱数などを用いた高度な変換を定義することが可能です。" = "Using the 'Template' feature, you can define special conversions relating to dates and random values."; -"ここでは「2020/01/23 01:23」という形式のタイムスタンプを作ってみます。" = "Here we make '2020/01/23 01:23' style time stamp."; -"まず「テンプレートの管理」から新しいテンプレートを作成します。画面右上の%@を押して、テンプレートを追加しましょう。" = "To begin with, let's make a new template on 'Manage templates'. Push the button %@ and add a new template."; -"追加したテンプレートを選ぶと編集画面が開きます。" = "Select the template you added, and the editing view opens."; -"編集画面で次のように設定します。" = "On the editing view, set as follows:"; -"・名前を「タイムスタンプ」に設定" = "Set 'Name' as 'TimeStamp'."; -"・書式で「カスタム」を選択" = "Select 'カスタム' for 'Format'."; -"・カスタム書式に「yyyy/MM/dd hh:mm」と入力" = "Input custom format as 'yyyy/MM/dd hh:mm'."; -"編集が終わったら完了ボタンを押してください。" = "When you finish editing, push the 'Done' button."; -"次にユーザ辞書でテンプレートを使います。「追加する」から新規に単語を登録し、編集画面が開きます。" = "Next, let's use this template in the text replacement. Tap 'Add' and new text replacement editing view opens."; -"ユーザ辞書で作成したテンプレートを使う際は、%@という形式で記述します。" = "When you use the template in the text replacement, input as '%@'."; -"今回は「タイムスタンプ」というテンプレートなので、%@と入力します。" = "We created 'Timestamp' template, so input %@."; -"以上で設定が完了です。あとは実際に使ってみましょう。" = "All the settings are now done. Let's use it."; -"「yyyy/MM/dd hh:mm」というのは日付の書式の書き方で、「yyyy」が4桁の年、「MM」が2桁の月、「dd」は2桁の日付を指しています。「hh」と「mm」も同様に時間と分です。" = "'yyyy/MM/dd hh:mm' is the format of dates. 'yyyy' represents the current year in 4 digits, 'MM' represents the current month in 2 digits, 'dd' represents the current date in 2 digits. 'hh' and 'mm' represent the current hour and minute."; -"この書式を使って他にもカスタマイズが可能です。「hh」ではなく「HH」を使うことで24時間表記にすることができます。また「M」一文字を使った場合は「01」月ではなく「1」月と表示されます。「ss」で秒を、「EEE」で曜日を、「a」で午前/午後を表示することもできます。" = "Using this format, you can define other styles. Using 'HH' instead of 'hh', you can get 24-hour notation. Using only 'M', it displays '1月', not '01月'. 'ss' represents the current second, 'EEE' represents the current day, 'a' represents AM or PM."; -"azooKeyではこの他にも、「ズレ」を設定することで昨日や明日の日付を表示したり、乱数を用いるテンプレートを設定したりすることができます。お試しください。" = "In azooKey, you can also set yesterday or tomorrow's date using 'delta' and templates that use random values. Let's try!"; -"{{テンプレート名}}" = "{{TemplateName}}"; -"{{タイムスタンプ}}" = "{{TimeStamp}}"; -"キーをカスタマイズする" = "Customize keys"; - - -"端末の文字サイズ設定が反映されない" = "Setting of device's font size doesn't work"; -"端末の文字サイズの設定を変更しても、キーボードに表示される文字の大きさが変わらないことがあります。" = "Sometimes the setting of your device's font size doesn't affect the keyboard."; -"一度端末を再起動していただくと設定が反映されます。" = "Please reboot your device, and the setting can work."; -"azooKeyの設定タブよりキーの文字サイズを設定することが可能です。そちらもお試しください。" = "On the Settings tab in azooKey, you can set key font size. Please try it."; - -"絵文字や顔文字の変換候補を表示したい" = "Show Emoji and Kaomoji candidates"; -"バグの報告や機能のリクエストをしたい" = "Report bugs or request new features"; -"お問い合わせ" = "Contact"; - -"特定のアプリケーションで入力がおかしくなる" = "Input fails in certain applications"; -"azooKeyとアプリの相性の問題で、入力がうまくいかないケースがあります。" = "There are some cases where input fails in certain application, because they are incompatible."; -"「入力中のテキストを保護」の設定をオンにすることで解決する場合があります。" = "Turn on the setting to 'Protect composing text' may resolve the issue."; - -"インストール直後、特定のアプリでキーボードが開かない" = "Keyboard does not open in certain applications immediately after installation"; -"azooKeyをインストールした直後、特定のアプリでキーボードが開かないことがあります。" = "Immediately after installing azooKey, the keyboard may not open in certain applications."; -"これはazooKeyの問題ではなく、OS側のデータの更新が遅れている可能性があります。" = "This may not be an azooKey issue, but a delay in updating the data on the OS side."; -"一度端末を再起動していただくとデータが更新され、キーボードが使えるようになることがあります。" = "Once you restart your device, the data will be updated and you may be able to use the keyboard."; -"なお、アプリケーション側でカスタムキーボードの利用を禁止する設定がなされている場合もあります。再起動で治らない場合はそちらもご確認ください。" = "In another case, the application may be set to prohibit the use of the custom keyboard. If this is not fixed by restarting the application, please check there as well."; - -"日本語と英語それぞれで「ローマ字入力」または「フリック入力」を選ぶことが可能です。" = "You can select Qwerty and Flick input styles for each of Japanese and English."; -"現在は携帯電話式の入力については対応していません。" = "Currently, azooKey doesn't support the Japanese flip phone input style."; - -"フルアクセスが必要な機能を使う" = "Use features requiring full access"; -"フルアクセスについて" = "About full access"; -"azooKeyは、キーボードの振動フィードバックや、キーボードからのペーストを実現するために、フルアクセスの許可が必要です。フルアクセスを許可していただくことで、これらの機能が使用できます。" = "azooKey requires full access permission in order to enable features such as keyboard haptics and pasting from the keyboard. By granting full access, these features can be utilized."; -"以下は、フルアクセスをオンにすることで利用できる設定項目です。フルアクセスを必要とする機能は、すべてデフォルトで無効になっているため、フルアクセスを許可しただけでキーボードの振る舞いが変わることはありません。" = "The following are the settings that can be used when full access is turned on. As all functions requiring full access are disabled by default, simply granting full access will not change the behavior of the keyboard."; -"また、フルアクセスをオンにしたあとでも、いつでもフルアクセスをオフにすることができます。" = "Furthermore, even after turning on full access, it is possible to turn it off at any time."; - -"フルアクセスをオンにすると、変換候補を長押しすることでキーボード上で誤変換を報告できるようになります。" = "When you turn on full access, you can report mis-conversions on the keyboard by long-pressing conversion candidates."; -"報告の際には、「アプリのバージョン」「変換候補と読みと順位」「ローマ字入力かフリック入力か」「学習のあり/なし」の情報がサーバに送信されます。" = "When reporting, information such as the app version, conversion candidate, reading, ranking, input method (roman character input or flick input), and whether or not learning is enabled will be sent to the server."; -"変換精度向上のため、報告をいただけると大変助かります。" = "Reporting would be greatly appreciated as it helps improve conversion accuracy."; - -"フルアクセスを許可しなくても、キーボードは完全に動作します。上記の機能を使わない場合は、オンにしないことを強くおすすめします。" = "The keyboard will function fully even without granting full access. It is strongly recommended not to turn on full access if you do not need to use the above features."; -"なお、azooKeyはオープンソースであり、誰もが実装を確認することができます。" = "Additionally, azooKey is an open-source keyboard app, allowing anyone to review the implementation."; -"フルアクセスを有効化する際、以下のような警告が表示されますが、すべてのキーボードアプリで共通して表示されている警告です。" = "The following warning appears when enabling full access, but it is a warning that is common to all keyboard apps."; -"azooKeyは安全なキーボードアプリであり、ユーザの明示的な同意なく、個人情報を外部に送信したり、保存したりすることはありません。" = "azooKey is a safe keyboard app and does not transmit or store personal information without the explicit consent of the user."; -"フルアクセスをオフにする(設定アプリが開きます)" = "Turn off full access (opens the Settings app)"; -"フルアクセスをオンにする(設定アプリが開きます)" = "Turn on full access (opens the Settings app)"; -"参考情報" = "References"; -"azooKeyのソースコードを閲覧する" = "Review the implementation of azooKey"; -"Configuring open access for a custom keyboard | Apple Developer Documentation (英語)" = "Configuring open access for a custom keyboard | Apple Developer Documentation"; - -"「ほかのAppからペースト」について" = "About 'Paste from other apps'"; -"「クリップボードの履歴」や「ペーストボタン」の機能を利用している際、頻繁に「ペーストの許可」を求めるダイアログが出ることがあります。" = "When using features like 'clipboard history' or 'paste button,' you may see frequent dialogues requesting permission to paste."; -"azooKeyはクリップボードの履歴を保存するため、定期的にクリップボードをチェックします。また、ペーストする際にもクリップボードの情報を利用します。" = "azooKey periodically checks the clipboard to save its history, and also uses its information when pasting."; -"設定アプリで「ほかのAppからペースト」を「許可」にすることで、ダイアログが出なくなります。" = "By allowing 'Paste from other apps' in Settings, you can avoid these dialogs."; -"設定アプリを開く" = "Open Settings app"; -"なお、「クリップボードの履歴」を有効にしていない場合、クリップボードの中身を定期的に取得することはありません。また、取得したクリップボードのテキストはアプリ内でのみ利用されます。" = "Note that if you have not enabled 'clipboard history,' azooKey will not periodically access the clipboard. Also, the text obtained from the clipboard is only used within the app."; - -"日本語" = "Japanese"; -"英語" = "English"; -"ギリシャ語" = "Greek"; -"なし" = "None"; -"現在" = "Current"; -"キーボードの種類" = "Keyboard Layout"; -"フリック入力" = "Flick"; -"ローマ字入力" = "Qwerty"; - -"そのまま入力" = "Direct input style"; -"ローマ字かな入力" = "Roman Kana input style"; - -"azooKeyでは一部キーのカスタマイズが可能です。「設定」タブから変更できます。" = "With azooKey, you can customize some of the keys. You can change keys on the Settings tab."; -"フリック入力では、ひらがなタブの「小゙゚」キーと「、。?!」キーのフリックに最大3方向まで好きな文字を登録することができます。" = "Using flick input style, you can register at most three letters on the key 「小゙゚」 and 「、。?!」."; -"ローマ字入力では、数字タブの一部キーに好きな文字と長押ししたときの候補を登録することができます。" = "Using qwerty input style, you can register favorite letter on some of the keys in the number tab and on some of the variations which you can select by longpressing."; - -"お問い合わせ内容を選んでください。ブラウザでGoogle Formが開きます。" = "Please select the type of inquiry. Google Form will open in your browser."; -"不具合報告" = "Report a problem"; -"機能の改善・追加" = "Request a feature or improvement"; -"変換候補の追加" = "Request to add a candidate for conversion"; -"変換候補の追加申請" = "Request to add a candidate for conversion"; -"その他の質問・連絡など" = "Other inquiries or contacts"; -"その他の質問・連絡などはメールでお寄せください" = "For other inquiries or contacts, please send us an email."; -"この単語をazooKeyの本体辞書に追加することを申請します。\n個人情報を含む単語は申請しないでください。" = "This word is requested to be added to the main dictionary of azooKey. \nPlease do not submit words that contain personal information."; -"申請中です" = "Requesting"; -"申請する" = "Request adding word"; -"この単語をシェアする" = "Share this word"; - -"おすすめ" = "Suggestion"; - -"%@を長押しでペースト" = "Longpress %@ to paste"; - -"カスタムキー" = "Custom keys"; -"カスタムキーの設定" = "Edit custom keys"; -"設定する" = "Set"; -"「小゙゚」キーと「、。?!」キーで入力する文字をカスタマイズすることができます。" = "You can register at most three letters on both keys 「小゙゚」 and 「、。?!」."; -"数字タブの青枠部分に好きな記号や文字を割り当てられます。" = "You can register your favorite letters on blue framed keys."; - -"編集したい方向を選択してください。" = "Select the key to which you want to register."; -"編集したいキーを選択してください。" = "Select the key to which you want to register."; -"リセット" = "Reset"; -"入力" = "Input"; -"ラベル" = "Labels"; -"ラベルの種類" = "Type of label"; -"テキスト" = "Text"; -"システムアイコン" = "System icon"; -"メインとサブ" = "Main and sub"; -"アイコンの名前" = "Name of icon"; -"メインのラベル" = "Main label"; -"サブのラベル" = "Sub label"; -"キーに表示される文字を設定します。" = "Set the label."; -"入力される文字とは異なっていても構いません。" = "Not necessarily equal to input letter."; -"キーを押して入力される文字を設定します。" = "Set letters inputted when you press this key."; -"キーを押して移動するタブを設定します。" = "Set the destination tab when you press this key."; -"キーを押したときの動作をより詳しく設定します。" = "Set actions when you press this key in detail."; -"キーを長押ししたときの動作をより詳しく設定します。" = "Set actions when you longpress this key in detail."; -"入力される文字" = "Inputted letters"; -"キーの見た目は「ラベル」で設定できます。" = "You can set labels for the appearance."; -"キーを追加する" = "Add a new key"; -"デフォルトに戻す" = "Reset"; -"このキーには入力以外のアクションが設定されています。" = "This key doesn't have input action."; -"現在のアクションを消去して入力する文字を設定するには「入力を設定する」を押してください" = "To delete current actions and set inputted letters, please push 'set destination tab.'"; -"このキーにはタブ移動以外のアクションが設定されています。" = "This key doesn't have a moving tab action."; -"現在のアクションを消去して移動するタブを設定するには「タブを設定する」を押してください" = "To delete current actions and set destination tab, please push 'set destination tab.'"; -"タブを設定する" = "Set destination tab"; -"入力を設定する" = "Set inputted letters"; -"アクションを編集する" = "Edit press action"; -"長押しアクションを編集する" = "Edit longpress action"; -"長押し" = "Longpress"; -"長押しアクション" = "Longpress action"; - -"キーの色" = "Color of this key"; -"キーの色を設定します。" = "Set the color of this key."; -"通常のキー" = "Color of normal keys"; -"特別なキー" = "Color of special keys"; -"押されているキー" = "Color of selected keys"; -"目立たないキー" = "Color of unimportant keys"; - -"キーのサイズ" = "Size of this key"; -"キーの種類" = "Type of this key"; -"カスタム" = "Custom"; -"改行キー" = "Return key"; -"削除キー" = "Delete key"; -"空白キー" = "Space key"; -"地球儀キー" = "Globe key"; -"小書き・濁点化キー" = "Japanese Voiced kana key"; -"句読点キー" = "Japanese punctuation key"; -"日本語タブキー" = "Japanese tab key"; -"英語タブキー" = "English tab key"; -"記号タブキー" = "Symbols tab key"; - -"共有する" = "Share"; - -"長押しした時の候補" = "Selectable variations when you longpress this key"; -"削除" = "Remove"; -"クリア" = "Clear"; -"移動" = "Move"; -"追加" = "Add"; - -"この機能にはフルアクセスが必要です。この機能を使いたい場合は、「設定」>「キーボード」でフルアクセスを有効にしてください。" = "This feature requires full access. To use this feature, please enable full access at 'Settings' > 'Keyboard'."; -"「設定」アプリを開く" = "Open 'Settings' app"; - -"第1言語" = "First language"; -"第2言語" = "Second language"; -"指定しない" = "Don't use"; - -"サウンドと振動" = "Keyboard Feedbacks"; -"サウンド" = "Sounds"; -"キーの音" = "Enable keyboard sounds"; -"キーを押した際に音を鳴らします♪" = "Make sounds when you press keys♪"; - -"振動フィードバック" = "Enable keyboard haptics"; -"キーを押した際に端末を振動させます。" = "Enable haptics feedback when you press keys."; - -"表示" = "Display"; -"キーの表示サイズ" = "Font size of key labels"; -"キーの文字の大きさを指定できます。文字が大きすぎる場合表示が崩れることがあります。" = "You can set the font size of keys. If the size is too large, the appearance can get collapsed."; -"変換候補の表示サイズ" = "Font size of candidates"; -"変換候補の文字の大きさを指定できます。" = "You can set the font size of candidates."; -"サンプル" = "Sample"; -"自動" = "Auto"; - -"カーソルバー" = "Cursor bar"; -"フィードバックを募集します" = "Feedback wanted"; - -"ペースト" = "Paste"; -"ペーストボタン" = "Enable paste button"; -"左下のカーソル移動キーの上フリックにペーストボタンを追加します" = "Add a paste button to the upper flick of the lower left cursor bar key."; - -"「ペーストを許可」のダイアログについて" = "About the 'Allow Paste' Dialog"; -"クリップボードの履歴" = "Clipboard histories"; -"クリップボードの履歴を保存" = "Keep clipboard histories"; -"コピーした文字列の履歴を保存し、専用のタブから入力できるようにします。" = "Keeping histories of copied text, and make it possible to input them from clipboard history tab."; -"タブバーに「コピー履歴」ボタンを追加しました。" = "'コピー履歴' button is added into tab bar."; - -"変換" = "Candidates"; -"ライブ変換" = "Live Conversion"; -"ライブ変換の設定" = "Settings for Live Conversion"; -"入力中の文字列を自動的に変換します。" = "Hiragana characters you input are immediately converted into kanji text, without manual operation"; -"macOSなどに搭載されている、入力中の文字列を自動的に変換する「ライブ変換」が利用できます。" = "You can use 'Live Conversion' with which hiragana characters you input are immediately converted into kanji text. This feature is often used in macOS, and now this feature is available on iOS!"; -"自動確定" = "Auto Prefix Completion"; -"自動確定を使うと長い文章を打っているときに候補の選択がしやすくなります。" = "With auto-prefix-completion, selecting candidate is more easy when you are inputting long text."; -"自動確定の速さ" = "Speed of Auto Prefix Completion"; -"しない" = "Disabled"; -"ゆっくり" = "Slow"; -"普通" = "Normal"; -"少し速い" = "Fast"; -"速い" = "Very fast"; - -"日本語入力中の英単語変換" = "Conversion to English words during Japanese input"; -"「いんてれsちんg」→「interesting」のように、ローマ字日本語入力中も英語への変換候補を表示します。" = "Display English word candidates during qwerty Japanese inputting like 「いんてれsちんg」→「interesting」."; -"半角カナ変換" = "Half-width kana candidates"; -"半角カタカナへの変換を候補に表示します。" = "Display half-width カタカナ(katakana) candidates."; -"全角英数字変換" = "Full-width numbers and roman letters candidates"; -"全角英数字(abc123)への変換候補を表示します。" = "Display full-width numbers and roman letters candidates like 'abc123'"; -"装飾英字変換" = "Decorated letters candidates"; -"英字入力をした際、「𝕥𝕪𝕡𝕠𝕘𝕣𝕒𝕡𝕙𝕪」のような装飾字体を候補に表示します。" = "Display decorated font candidates like '𝕥𝕪𝕡𝕠𝕘𝕣𝕒𝕡𝕙𝕪' during English inputting."; -"西暦⇄和暦変換" = "Gregorian - Japanese calendar conversion"; -"「2020ねん→令和2年」「れいわ2ねん→2020年」のように西暦と和暦を相互に変換して候補に表示します。" = "Convert Gregorian year and Japanese year mutually and display candidates like 「2020ねん→令和2年」「れいわ2ねん→2020年」."; -"unicode変換" = "Unicode letters conversion"; -"「u3042→あ」のように、入力されたunicode番号に対応する文字に変換します。接頭辞にはu, u+, U, U+が使えます。" = "Convert Unicode order to letter and display candidates like 「u3042→あ」"; -"絵文字と顔文字" = "Emojis and Kaomojis"; -"絵文字" = "Emoji"; -"顔文字" = "Kaomoji"; -"絵文字と顔文字は別々にオン・オフを選択可能です。" = "You can decide whether you use emoji and whether you use kaomoji."; -"絵文字の一覧を表示したい場合、標準の絵文字キーボードをご利用ください。" = "If you want to get the list of emoji, please use the device's emojis keyboard."; -"利用するもの" = "You use"; -"不快な絵文字を表示しない" = "Block unpleasant Emojis"; -"ゴキブリの絵文字を非表示" = "Forbid cockroach emojis"; -"クモの絵文字を非表示" = "Forbid spider emojis"; - -"ユーザ辞書" = "Text replacement"; -"OSのユーザ辞書の利用" = "Use device text replacement"; -"OS標準のユーザ辞書を利用します。" = "Use device text replacement and display the candidates."; -"azooKeyユーザ辞書" = "azooKey's Text replacement"; -"変換候補に単語を追加することができます。iOSの標準のユーザ辞書とは異なります。" = "You can add text replacements. It is different from thee device's text replacements."; - -"iOS15のサポートを終了します" = "Support for iOS15 is ending"; -"バージョン2.3(公開時期未定)以降のazooKeyではiOS15のサポートを終了する予定です。" = "Support for iOS 15 will be discontinued in azooKey version 2.3 (release date TBD) and beyond."; -"iOS16以降では引き続き最新バージョンのazooKeyをご利用いただけます。" = "You can continue using the latest version of azooKey on iOS 16 and later."; -"ぜひiOSをアップデートしてazooKeyをご利用ください。" = "Please update iOS and continue using azooKey."; - -"追加する" = "Add"; -"詳細設定" = "Details"; -"詳しい設定" = "Details"; -"単語" = "Word"; -"読み" = "Ruby"; -"読みと単語" = "Ruby and word"; -"詳細な設定" = "High-level settings"; -"人・動物・会社などの名前である" = "It is the name of persons, pets, and groups."; -"場所・建物などの名前である" = "It is the name of places and buildings"; -"読みが空です" = "Ruby is empty"; -"単語が空です" = "Word is empty"; -"読みに使用できない文字が含まれます。ひらがな、英字、数字を指定してください" = "Contains unusable characters. Please use hiragana, roman letters, and numbers."; - -"フリックの感度" = "Flicking sensitivity"; -"どれだけ指を動かしたらフリックと判定するか調整できます。" = "You can adjust how much you move your finger to determine a flick."; -"操作性" = "Usability"; -"とても反応しにくい" = "Very insensitive"; -"反応しにくい" = "Insensitive"; -"普通" = "Normal"; -"反応しやすい" = "Sensitive"; -"とても反応しやすい" = "Very sensitive"; - -"キーボードの高さ" = "Keyboard height"; -"キーボードの高さを調整できます。" = "You can edit keyboard height."; - -"テンプレート" = "Templates"; -"テンプレートの管理" = "Manage templates"; -"テンプレートを編集" = "Edit template"; -"テンプレートを編集する" = "Edit template"; -"テンプレートを選ぶ" = "Select template"; -"%@を編集できます" = "%@ can be edited"; -"%@というテンプレートが見つかりません。" = "Template '%@' cannot be found"; -"%を新規作成" = "Create new template %@"; -"時刻" = "Dates"; -"ランダム" = "Random"; -"書式の設定" = "Format"; -"書式" = "Format"; -"プレビュー" = "Preview"; -"更新" = "Update"; -"ズレ" = "Delta"; -"暦の種類" = "Calendar"; -"言語" = "Language"; -"西暦" = "Gregorian"; -"和暦" = "Japanese"; -"秒" = "Seconds"; -"分" = "Minutes"; -"時間" = "Hours"; -"日" = "Days"; -"カスタム書式" = "Custom format"; -"書式はyyyyMMddhhmmssフォーマットで記述します。詳しい記法はインターネット等で確認できます。" = "Formats can be specified by yyyyMMddhhmmss style. You can check details on the Internet."; -"Web検索" = "Google search"; -"値の種類" = "Type of value"; -"整数" = "Integers"; -"小数" = "Decimals"; -"文字列" = "Words"; -"から" = "starts"; -"まで" = "ends"; -"名前" = "Name"; - -"ショートカットを実行" = "Run shortcut"; -"オプション" = "Options"; -"オプションの設定方法" = "How to specify options"; - -"学習機能" = "Memories"; -"学習の使用" = "Use memorizing"; -"学習のリセット" = "Reset memories"; -"学習する(デフォルト)" = "Use memorizing (default)"; -"新たな学習を停止" = "Stop memorizing"; -"これまでの学習を反映しない" = "Ignore memories"; -"学習履歴をリセットします。よろしいですか?" = "Reset memories. Is this alright?"; -"この操作は取り消せません。" = "This operation cannot be canceled."; - -"このアプリについて" = "About azooKey"; -"azooKeyはオープンソースソフトウェアであり、GitHubでソースコードを公開しています。" = "azooKey is open source software and its source code is available on GitHub."; -"プライバシーポリシー" = "Privacy Policy (Japanese)"; -"利用規約" = "Terms of use (Japanese)"; -"更新履歴" = "Update histories (Japanese)"; -"オープンソースソフトウェア" = "Open source softwares (Japanese)"; -"バージョン" = "Version"; - -"カスタムタブ" = "Custom tabs"; -"好きな文字や文章を並べたオリジナルのタブを作成することができます。" = "You can make your original tab includes letters and sentences you need to input daily."; -"カスタムタブの管理" = "Manage custom tabs"; -"タブバー" = "Tab bar"; -"カスタムタブを使うにはタブバーを利用します。" = "You can use Tab Bar to move custom tabs."; -"あずきのマークを押すと表示されます。" = "Tab bar will appear when you press azooKey's icon on the keyboard."; -"フリック入力では左上の「☆123」・ローマ字入力では左下の「123」「#+=」キーを長押ししても表示されます。" = "Using flick input style, you can also show it by longpressing ☆123 key at the left top edge of the keyboard. Using qwerty input style, you can show it by longpressing #+= key or 123 key at the left bottom edge of the keyboard."; -"もっと便利にする" = "More useful"; -"タブバーを編集し、タブの並び替え、削除、追加を行ったり、文字の入力やカーソルの移動など様々な機能を追加することができます。" = "You can edit the tab bar. You can rearrange, delete, append tabs and also add features like inputting, moving the cursor, and so on."; -"タブバーを編集" = "Edit tab bar"; -"一覧" = "List"; -"URLが間違っている可能性があります" = "Wrong URL"; -"データが取得できませんでした" = "Failed to get data from URL"; -"正しくない形式のファイルです" = "Incorrectly formatted file"; -"読み込みに失敗したカスタムタブ「%@」を書き出す" = "Export custom tab '%@' that failed to load"; -"ファイルを取得中" = "Getting file"; -"URLを取得中" = "Getting URL"; -"ファイルを処理中" = "Processing file"; -"カスタムタブがまだありません" = "Custom tabs have yet created"; -"登録したい文字や単語を順番に書いていくだけでスクロール式のカスタムタブを作成することができます。" = "You can make scroll style custom tabs only by listing up the words and sentences."; -"スクロール式のカスタムタブを作る" = "Make scroll style custom tabs"; -"フリック式のカスタムタブを作成することができます。" = "You can make tenkey style custom tabs."; -"フリック式のカスタムタブを作る" = "Make tenkey style custom tabs"; - -"コピーする" = "Copy"; -"ペーストする" = "Paste"; -"下に行を追加" = "Insert a row below"; -"上に行を追加" = "Insert a row above"; -"左に列を追加" = "Insert a column to left"; -"右に列を追加" = "Insert a column to right"; -"この行を削除" = "Delete this row"; -"この列を削除" = "Delete this column"; - -"「%@(%@)」の読み込みに成功しました" = "Successfuly imported '%1$@'(%2$@)"; -"保存" = "Save"; -"タブバーに追加" = "Add to tab bar"; -"読み込む" = "Import"; -"iCloudから読み込む" = "Import from iCloud"; -"URLから読み込む" = "Import from URL"; -"URLを入力" = "URL"; -"カスタムタブをファイルとして外部で作成し、azooKeyに読み込むことができます。より高機能なタブの作成が可能です。詳しくは以下をご覧ください。" = "You can create custom tabs as files outside of this app and import them. You can create more high-functional tabs. For detail please check below."; -"カスタムタブファイルの作り方" = "How to make custom tab files."; -"注意" = "Warning"; -"識別子%@を持つカスタムタブが既に登録されています。上書きしますか?" = "You have been already using a custom tab that has identifier %@. Do you overwrap it?"; -"上書き" = "Overwrap"; -"タブ名" = "Tab Name"; -"タブの名前" = "Tab Name"; -"識別子" = "Identifier"; -"入力方式" = "Input style"; -"由来" = "Origin"; -"タブバーに追加済み" = "Already in tab bar"; -"タブバーに追加する" = "Add to tab bar"; -"書き出す" = "Export"; -"変換なし" = "None"; -"指定なし" = "Not specified"; -"ダイレクト" = "Direct"; -"ローマ字かな入力" = "Roman to kana input style"; -"このアプリで作成" = "Made in this app"; -"読み込んだデータ" = "Imported data"; -"カスタムタブの情報" = "Information of custom tab"; -"カスタムタブを作る" = "Make custom tab"; -"一行ずつ登録したい文字や単語を入力してください" = "List up letters and sentences you want to use in this custom tab in line-separated format"; -"スクロール方向" = "Scroll direction"; -"縦" = "Vertical"; -"横" = "Horizontal"; -"横方向キー数" = "Row key count"; -"縦方向キー数" = "Column key count"; -"自動的にタブバーに追加" = "Add to tab bar automatically"; - -"タブバーの編集" = "Edit tab bar"; -"アイテムを追加" = "Add new item"; -"アイテム" = "Items"; -"アクション" = "Actions"; -"削除と順番" = "Delete & Rearrange"; -"押した時の動作" = "Actions when select"; -"動作の編集" = "Edit actions"; -"上から順に実行されます" = "Actions are executed in order"; -"アクションを追加" = "Add new action"; -"このアプリでは編集できないアクションです" = "An action which cannot be edited in this app"; - -"基本" = "Basic"; -"高度" = "Advanced"; -"押し始めのアクション" = "Actions done when longpress starts"; -"押している間のアクション" = "Actions repeated during longpress"; - -"タブバーの表示" = "Show tab bar"; -"文字の入力" = "Input letters"; -"文字の削除" = "Delete letters"; -"入力の確定" = "Complete"; -"カーソル移動" = "Moving cursor"; -"カーソルバーの表示" = "Show cursor bar"; -"片手モードをオン" = "Enable one-handed mode"; -"片手モードをオンにする" = "Enable one-handed mode"; -"%@など" = "%@, etc"; - -"キーの編集" = "Edit key"; - -"確定" = "Complete"; -"大文字/小文字、拗音/濁音/半濁音の切り替え" = "Change uppercase ⇆ lowercase"; -"「%@」を入力" = "Input '%@'"; -"「%@」を繰り返し入力" = "Input '%@' repeatedly"; -"入力する文字" = "Letters to input"; -"削除する文字数" = "Count to delete"; -"%@文字削除" = "Delete %@ character"; -"%@文字ずつ削除" = "Delete %@ character repeatedly"; -"負の値を指定すると右側の文字を削除します" = "Negative number means delete forward"; -"%@文字分カーソルを移動" = "Move cursor for %@ characters"; -"%@文字ずつカーソルを移動" = "Move cursor for %@ characters repeatedly"; -"負の値を指定すると左にカーソルが動きます" = "Negative number means moving backward"; -"移動する文字数" = "Count of movement"; -"タブの移動" = "Move to tab"; -"タブを選択" = "Select destination tab"; -"ペーストする" = "Paste copied text"; -"文頭まで削除" = "Delete to beginning of the sentence"; -"Caps lockのモードの切り替え" = "Toggle caps lock"; -"カーソルバーの切り替え" = "Toggle show or not show cursor bar"; -"タブバーの切り替え" = "Toggle show or not show tab bar"; -"キーボードを閉じる" = "Dismiss keyboard"; -"アプリを開く" = "Open app"; -"このアクションはiOSのメジャーアップデートで利用できなくなる可能性があります" = "This action could be invalid in future iOS versions"; - -"日本語(設定に合わせる)" = "Japanese (follow your setting)"; -"英語(設定に合わせる)" = "English (follow your setting)"; -"記号と数字(フリック入力)" = "Symbols and numbers (flick style)"; -"数字(ローマ字入力)" = "Numbers (qwerty style)"; -"記号(ローマ字入力)" = "Symbols (qwerty style)"; -"日本語(フリック入力)" = "Japanese (flick style)"; -"日本語(ローマ字入力)" = "Japanese (qwerty style)"; -"英語(フリック入力)" = "English (flick style)"; -"英語(ローマ字入力)" = "English (qwerty style)"; -"最後に表示していたタブ" = "Last used tab"; - -"移動先:%@" = "Destination: %@"; -"azooKeyを使ってくれてありがとう!" = "Thank you for using azooKey!"; -"移動先のタブ" = "Tab to move"; -"キーをドラッグして移動してください。" = "Drag the key to move it."; -"移動・追加" = "Move/Add"; -"このキーは編集できません" = "This key cannot be edited"; -"このキーを並び替える" = "Rearrange this key"; -"このキーに長押しキーを追加する" = "Add a new alternative key which appears when longpressed"; -"タブバーボタン" = "Tab bar button"; -"変換候補欄が空のときにタブバーボタンを表示します" = "Display tab bar button when there is no candidates"; - -"新しいカーソルバーを使う (試験版)" = "Use new cursor bar (experimental)"; -"新しいカーソルバーを有効化します。\n試験的機能のため、予告なく提供を終了する可能性があります。" = "Enable new cursor bar. \nSince this is an experimental feature, this feature may be discontinued without notice."; - -"片手モードで解除ボタンを表示しない" = "Do not display release button in one-handed mode"; -"片手モードの際に表示される解除ボタンを非表示にします。片手モードの調整はタブバーのボタンから行えます。" = "Hide the reset button displayed in one-handed mode. One-handed mode adjustment can be done from the tab bar button."; - -"より強力な学習を有効化 (試験版)" = "Enable more strong learning (experimental)"; -"より長い期間学習が保持されます。\n試験的機能のため、予告なく提供を終了する可能性があります。" = "Histories can be remembered much longer. \nSince this is an experimental feature, this feature may be discontinued without notice."; - -"入力中のテキストを保護 (試験版)" = "Protect composing text (experimental)"; -"入力中のテキストを保護し、Webアプリなどでの入力において挙動を安定させます。\n試験的機能のため、仕様の変更、不具合などが発生する可能性があります。" = "By protecting composing text, azooKey will behave more stably in some web apps. \nSince this is an experimental feature, this feature may be discontinued without notice."; diff --git a/Resources/ja.lproj/Localizable.strings b/Resources/ja.lproj/Localizable.strings deleted file mode 100644 index 2bc5a70f..00000000 --- a/Resources/ja.lproj/Localizable.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* - Localizable.strings - azooKey - - Created by ensan on 2021/02/14. - Copyright © 2021 ensan. All rights reserved. -*/ diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index d739d9d5..32941ef4 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -128,7 +128,6 @@ 1AC03159251103EF004CA505 /* Designs.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1AC03158251103EF004CA505 /* Designs.xcassets */; }; 1AC0315D25120A17004CA505 /* SettingTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AC0315C25120A17004CA505 /* SettingTab.swift */; }; 1AC09DBE299533E0009BDBC7 /* DicdataStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AC09DBD299533DF009BDBC7 /* DicdataStoreTests.swift */; }; - 1AC5876525D930D000BB060E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1AC5876825D930D000BB060E /* Localizable.strings */; }; 1AC8A5822594EF6500B71E5A /* TemplateSettingTipsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AC8A5812594EF6500B71E5A /* TemplateSettingTipsView.swift */; }; 1AC8A5D3259815C300B71E5A /* FlickCustomKeySettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AC8A5D2259815C300B71E5A /* FlickCustomKeySettingView.swift */; }; 1ACB07CA25E552940077DE04 /* EditingScrollCustardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACB07C925E552940077DE04 /* EditingScrollCustardView.swift */; }; @@ -167,11 +166,12 @@ 1AFA57602584810800477DC2 /* Focus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFA575F2584810800477DC2 /* Focus.swift */; }; 1AFA57662584815B00477DC2 /* QwertyCustomKeysItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFA57652584815A00477DC2 /* QwertyCustomKeysItemView.swift */; }; 1AFB68422518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFB68412518C48100C649C4 /* OpenSourceSoftwaresLicenseView.swift */; }; - 1AFB685328D56F1800B5C717 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1AC5876825D930D000BB060E /* Localizable.strings */; }; 1AFE773026077E0E0041D74D /* WalkthroughState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AFE772F26077E0E0041D74D /* WalkthroughState.swift */; }; 557D9DFB2ABEE7970028F3A0 /* ContactAuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557D9DFA2ABEE7970028F3A0 /* ContactAuthManager.swift */; }; 557D9DFD2ABEF6560028F3A0 /* ContactImportSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557D9DFC2ABEF6560028F3A0 /* ContactImportSettingView.swift */; }; 557D9DFF2ABF2B9D0028F3A0 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557D9DFE2ABF2B9D0028F3A0 /* InfoPlist.xcstrings */; }; + 557D9E012ABF320F0028F3A0 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557D9E002ABF320F0028F3A0 /* Localizable.xcstrings */; }; + 557D9E022ABF320F0028F3A0 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557D9E002ABF320F0028F3A0 /* Localizable.xcstrings */; }; 5598472E2AB84F5200B18C15 /* PredictionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5598472D2AB84F5200B18C15 /* PredictionManager.swift */; }; /* End PBXBuildFile section */ @@ -326,9 +326,6 @@ 1AC0315E25120AA2004CA505 /* azooKey.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = azooKey.entitlements; sourceTree = ""; }; 1AC0315F25120B3B004CA505 /* Keyboard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Keyboard.entitlements; sourceTree = ""; }; 1AC09DBD299533DF009BDBC7 /* DicdataStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DicdataStoreTests.swift; sourceTree = ""; }; - 1AC5875925D9309500BB060E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/LaunchScreen.strings; sourceTree = ""; }; - 1AC5876725D930D000BB060E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; - 1AC5876D25D930E700BB060E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 1AC8A5812594EF6500B71E5A /* TemplateSettingTipsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateSettingTipsView.swift; sourceTree = ""; }; 1AC8A5D2259815C300B71E5A /* FlickCustomKeySettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlickCustomKeySettingView.swift; sourceTree = ""; }; 1ACB07C925E552940077DE04 /* EditingScrollCustardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditingScrollCustardView.swift; sourceTree = ""; }; @@ -365,6 +362,8 @@ 557D9DFA2ABEE7970028F3A0 /* ContactAuthManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactAuthManager.swift; sourceTree = ""; }; 557D9DFC2ABEF6560028F3A0 /* ContactImportSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImportSettingView.swift; sourceTree = ""; }; 557D9DFE2ABF2B9D0028F3A0 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = ""; }; + 557D9E002ABF320F0028F3A0 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; + 557D9E032ABF3E350028F3A0 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/LaunchScreen.strings; sourceTree = ""; }; 5598472D2AB84F5200B18C15 /* PredictionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PredictionManager.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -716,7 +715,7 @@ children = ( 1AC03158251103EF004CA505 /* Designs.xcassets */, 557D9DFE2ABF2B9D0028F3A0 /* InfoPlist.xcstrings */, - 1AC5876825D930D000BB060E /* Localizable.strings */, + 557D9E002ABF320F0028F3A0 /* Localizable.xcstrings */, 1AE191FB25D7E3B40044EE4B /* AzooKeyIcon-Regular.otf */, 1A1A62F029C8BCA400EF7B26 /* Data */, ); @@ -1095,7 +1094,7 @@ }; buildConfigurationList = 1A3DC1BD2500D44A002CAA93 /* Build configuration list for PBXProject "azooKey" */; compatibilityVersion = "Xcode 12.0"; - developmentRegion = en; + developmentRegion = ja; hasScannedForEncodings = 0; knownRegions = ( en, @@ -1142,9 +1141,9 @@ 1A1A62FF29C8BCD400EF7B26 /* emoji_genre_E15.0.txt.gen in Resources */, 1A1A62F929C8BCD400EF7B26 /* emoji_all_E15.0.txt.gen in Resources */, 1A3DC1D22500D44E002CAA93 /* LaunchScreen.storyboard in Resources */, + 557D9E012ABF320F0028F3A0 /* Localizable.xcstrings in Resources */, 1A1A630829C9C91A00EF7B26 /* emoji_dict_E14.0.txt.gen in Resources */, 557D9DFF2ABF2B9D0028F3A0 /* InfoPlist.xcstrings in Resources */, - 1AC5876525D930D000BB060E /* Localizable.strings in Resources */, 1AE191FC25D7E3B40044EE4B /* AzooKeyIcon-Regular.otf in Resources */, 1A1A62FB29C8BCD400EF7B26 /* emoji_all_E13.1.txt.gen in Resources */, 1AF679B625CEE92600F3987B /* Designs.xcassets in Resources */, @@ -1186,9 +1185,9 @@ 1A1A62F829C8BCD400EF7B26 /* emoji_genre_E13.1.txt.gen in Resources */, 1A09112C2A20B13C00ABFC72 /* Dictionary in Resources */, 1A1A62FC29C8BCD400EF7B26 /* emoji_all_E13.1.txt.gen in Resources */, - 1AFB685328D56F1800B5C717 /* Localizable.strings in Resources */, 1A1A630029C8BCD400EF7B26 /* emoji_genre_E15.0.txt.gen in Resources */, 1AC03159251103EF004CA505 /* Designs.xcassets in Resources */, + 557D9E022ABF320F0028F3A0 /* Localizable.xcstrings in Resources */, 1A7F547126A96A5F0032E91E /* AzooKeyIcon-Regular.otf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1425,20 +1424,11 @@ isa = PBXVariantGroup; children = ( 1A3DC1D12500D44E002CAA93 /* Base */, - 1AC5875925D9309500BB060E /* ja */, + 557D9E032ABF3E350028F3A0 /* ja */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; - 1AC5876825D930D000BB060E /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 1AC5876725D930D000BB060E /* ja */, - 1AC5876D25D930E700BB060E /* en */, - ); - name = Localizable.strings; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -1661,6 +1651,7 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1697,6 +1688,7 @@ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_STRICT_CONCURRENCY = targeted; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1829,6 +1821,7 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_DISABLE_SAFETY_CHECKS = NO; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; @@ -1864,6 +1857,7 @@ SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_DISABLE_SAFETY_CHECKS = YES; + SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_STRICT_CONCURRENCY = targeted; SWIFT_VERSION = 5.0; From 8659ccb1d6e0a4854e2c9994e87d03563ace8549 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 01:48:42 +0900 Subject: [PATCH 059/124] add resume for tutorial --- MainApp/ContentView.swift | 14 +++++++++++++- .../EnableAzooKeyView/EnableAzooKeyView.swift | 16 +++++++++++++--- MainApp/MainApp.swift | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/MainApp/ContentView.swift b/MainApp/ContentView.swift index 956fd2fe..8a898518 100644 --- a/MainApp/ContentView.swift +++ b/MainApp/ContentView.swift @@ -45,8 +45,20 @@ struct ContentView: View { } .tag(TabSelection.settings) } + .onAppear { + if appStates.isKeyboardActivated && !appStates.tutorialFinishedSuccessfully() { + appStates.requireFirstOpenView = true + } + } .fullScreenCover(isPresented: $appStates.requireFirstOpenView, content: { - EnableAzooKeyView() + // キーボードは有効化されているが正しく終了していない場合 + if appStates.isKeyboardActivated && !appStates.tutorialFinishedSuccessfully() { + // 「最初の設定」を再表示する + EnableAzooKeyView(resumeProgress: .setting) + } else { + // 最初からやる + EnableAzooKeyView() + } }) .onChange(of: selection) {value in if value == .customize { diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift index 5455c0f0..2f2d1244 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift @@ -11,20 +11,30 @@ import SwiftUI import SwiftUIUtils import func SwiftUtils.debug -private enum EnableAzooKeyViewStep { +enum EnableAzooKeyViewProgress: String, Hashable, Codable, Sendable { case menu case append - case finish case setting + case finish } @MainActor struct EnableAzooKeyView: View { @EnvironmentObject private var appStates: MainAppStates - @State private var step: EnableAzooKeyViewStep = .menu + @State private var step: EnableAzooKeyViewProgress = .menu { + didSet { + self.appStates.setTutorialProgress(step) + } + } @State private var text = "" @State private var showDoneMessage = false + init(resumeProgress: EnableAzooKeyViewProgress? = nil) { + if let resumeProgress { + self._step = .init(initialValue: resumeProgress) + } + } + var body: some View { ScrollView { ScrollViewReader {value in diff --git a/MainApp/MainApp.swift b/MainApp/MainApp.swift index 16c8d8f9..3d09b9ad 100644 --- a/MainApp/MainApp.swift +++ b/MainApp/MainApp.swift @@ -32,6 +32,25 @@ final class MainAppStates: ObservableObject { SemiStaticStates.shared.setHapticsAvailable() SemiStaticStates.shared.setScreenWidth(UIScreen.main.bounds.width) } + + func setTutorialProgress(_ progress: EnableAzooKeyViewProgress) { + UserDefaults.standard.set(progress.rawValue, forKey: "tutorial_progress") + } + private func resumeTutorialProgress() -> EnableAzooKeyViewProgress? { + if let progressString = UserDefaults.standard.string(forKey: "tutorial_progress") { + return EnableAzooKeyViewProgress(rawValue: progressString) + } else { + return nil + } + } + func tutorialFinishedSuccessfully() -> Bool { + if let progress = resumeTutorialProgress() { + // finishで終わっていない場合、適切ではない + return progress == .finish + } else { + return true + } + } } @main From dcab0fd95613c5d98e92c188d7bba1b8f71b73c7 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 04:04:57 +0900 Subject: [PATCH 060/124] =?UTF-8?q?feature:=20=E6=A4=9C=E7=B4=A2=E3=83=95?= =?UTF-8?q?=E3=82=A3=E3=83=BC=E3=83=AB=E3=83=89=E3=81=AA=E3=81=A9=E3=81=A7?= =?UTF-8?q?=E5=86=8D=E5=A4=89=E6=8F=9B=E3=82=92=E6=8A=91=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyboardViews/VariableStates.swift | 9 ++++-- Keyboard/Display/InputManager.swift | 29 +++++++------------ Keyboard/Display/KeyboardActionManager.swift | 20 ++++++++++++- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift index f7e94a68..f2f1fa16 100644 --- a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift +++ b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift @@ -118,6 +118,8 @@ public final class VariableStates: ObservableObject { @Published private(set) public var keyboardOrientation: KeyboardOrientation = .vertical @Published private(set) public var keyboardLayout: KeyboardLayout = .flick + private(set) public var keyboardType: UIKeyboardType = .default + /// `ResultModel`の変数 @Published public var resultModelVariableSection = ResultModelVariableSection() @@ -129,7 +131,7 @@ public final class VariableStates: ObservableObject { @Published public var interfacePosition: CGPoint = .zero /// 外部では利用しないが、`enterKeyState`の更新時に必要になる - private var enterKeyType: UIReturnKeyType = .default + private(set) public var returnKeyType: UIReturnKeyType = .default @Published private(set) var enterKeyState: EnterKeyState = .return(.default) @Published public var barState: BarState = .none @@ -214,6 +216,7 @@ public final class VariableStates: ObservableObject { guard let type else { return } + self.keyboardType = type switch type { case .default, .asciiCapable: return @@ -245,7 +248,7 @@ public final class VariableStates: ObservableObject { public func setEnterKeyState(_ state: RoughEnterKeyState) { switch state { case .return: - self.enterKeyState = .return(enterKeyType) + self.enterKeyState = .return(returnKeyType) case .complete: self.enterKeyState = .complete } @@ -265,7 +268,7 @@ public final class VariableStates: ObservableObject { } public func setUIReturnKeyType(type: UIReturnKeyType) { - self.enterKeyType = type + self.returnKeyType = type if case let .return(prev) = self.enterKeyState, prev != type { self.setEnterKeyState(.return) } diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 3737ccd3..6824c315 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -836,27 +836,20 @@ import UIKit } // ユーザが文章を選択した場合、その部分を入力中であるとみなす(再変換) - func userSelectedText(text: String) { - if text.isEmpty { - return - } - // 長すぎるのはダメ - if text.count > 100 { - return - } - if text.hasPrefix("http") { - return - } - // 改行文字はだめ - if text.contains("\n") || text.contains("\r") { - return - } - // 空白文字もだめ - if text.contains(" ") || text.contains("\t") { + func userSelectedText(text: String, lengthLimit: Int) { + self.composingText.stopComposition() + // 文字がない場合 + if text.isEmpty + // 文字数が多すぎる場合 + || text.count > lengthLimit + // httpで始まる場合 + || text.hasPrefix("http") + // 扱いにくい文字を含む場合 + || text.contains("\n") || text.contains("\r") || text.contains(" ") || text.contains("\t") { + self.setResult() return } // 過去のログを見て、再変換に利用する - self.composingText.stopComposition() let ruby = getReadingFromSystemAPI(self.getRubyIfPossible(text: text) ?? text) self.composingText.insertAtCursorPosition(ruby, inputStyle: .direct) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 54d86342..bc72cf27 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -537,7 +537,25 @@ import SwiftUtils if isSelected { debug("user operation id: 0", a_center) - self.inputManager.userSelectedText(text: a_center) + // 検索フィールドなどでは再変換を抑制する + let lengthLimit: Int = switch variableStates.keyboardType { + case .default, .twitter: + switch variableStates.returnKeyType { + case .emergencyCall: + 0 + case .search, .google, .yahoo, .route: + 5 + default: + 100 + } + case .decimalPad, .URL, .asciiCapableNumberPad, .emailAddress, .phonePad, .namePhonePad, .alphabet, .numbersAndPunctuation, .numberPad, .asciiCapable: + 0 + case .webSearch: + 5 + @unknown default: + 50 + } + self.inputManager.userSelectedText(text: a_center, lengthLimit: lengthLimit) return } From cdaf2fe9dd267e7f5c6ed582415990c11ac3400f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 05:09:18 +0900 Subject: [PATCH 061/124] add smart_move_cursor and smart_delete editor --- .../Customize/CodableActionDataEditor.swift | 84 ++++++++++++++----- Resources/Localizable.xcstrings | 60 +++++++++++++ 2 files changed, 121 insertions(+), 23 deletions(-) diff --git a/MainApp/Customize/CodableActionDataEditor.swift b/MainApp/Customize/CodableActionDataEditor.swift index 11015948..14f7b3c5 100644 --- a/MainApp/Customize/CodableActionDataEditor.swift +++ b/MainApp/Customize/CodableActionDataEditor.swift @@ -46,29 +46,6 @@ extension CodableActionData { case .shortcuts: return "ショートカットを実行する" } - // case .setBoolState: return "Bool変数を設定" - // case .boolSwitch: return "条件分岐" - // case let .setCursorBar(value): - // // TODO: LOCALIZE - // switch value { - // case .on: return "カーソルバーを表示する" - // case .off: return "カーソルバーを消す" - // case .toggle: return "カーソルバーの切り替え" - // } - // case let .setCapsLockState(value): - // // TODO: LOCALIZE - // switch value { - // case .on: return "Caps lockのモードのオン" - // case .off: return "Caps lockのモードのオフ" - // case .toggle: return "Caps lockのモードの切り替え" - // } - // case let .setTabBar(value): - // // TODO: LOCALIZE - // switch value { - // case .on: return "タブバーを表示する" - // case .off: return "タブバーを消す" - // case .toggle: return "タブバーの切り替え" - // } } } } @@ -208,6 +185,18 @@ private struct CodableActionEditor: View { Text("負の値を指定すると左にカーソルが動きます") case .moveTab: ActionMoveTabEditView($action, availableCustards: availableCustards) + case .smartDelete(let item): + ActionScanItemEditor(action: $action) { item } convert: { value in + // 重複を除去し、改行を追加する + let targets = Array(Set(item.targets + ["\n"]) ) + return .smartDelete(ScanItem(targets: targets, direction: item.direction)) + } + case .smartMoveCursor(let item): + ActionScanItemEditor(action: $action) { item } convert: { value in + // 重複を除去し、改行を追加する + let targets = Array(Set(item.targets + ["\n"]) ) + return .smartMoveCursor(ScanItem(targets: targets, direction: item.direction)) + } case .replaceLastCharacters: EmptyView() case let .launchApplication(item): @@ -225,6 +214,49 @@ private struct CodableActionEditor: View { } } +private struct ActionScanItemEditor: View { + @Binding private var action: EditingCodableActionData + private let convert: (ScanItem) -> CodableActionData? + @State private var value: ScanItem = .init(targets: CodableActionData.scanTargets, direction: .backward) + + init(action: Binding, initialValue: () -> ScanItem?, convert: @escaping (ScanItem) -> CodableActionData?) { + self.convert = convert + self._action = action + if let initialValue = initialValue() { + self._value = State(initialValue: initialValue) + } + } + + var body: some View { + Group { + Picker("方向", selection: $value.direction) { + Text("左向き").tag(ScanItem.Direction.backward) + Text("右向き").tag(ScanItem.Direction.forward) + } + .pickerStyle(.menu) + HStack { + Text("目指す文字(改行区切り)") + Spacer() + TextEditor(text: $value.targets.converted( + // バックスラッシュでエスケープする + forward: {$0.joined(separator: "\n")}, + backward: {$0.components(separatedBy: "\n")} + )) + .background { + Color.systemGray6 + } + .font(.body.monospaced()) + .frame(maxWidth: 50) + } + } + .onChange(of: value) {value in + if let data = convert(value) { + action.data = data + } + } + } +} + private struct ActionEditTextField: View { private let title: LocalizedStringKey @Binding private var action: EditingCodableActionData @@ -533,6 +565,12 @@ private struct ActionPicker: View { Button("文頭まで削除") { process(.smartDeleteDefault) } + Button("特定の文字まで削除") { + process(.smartDelete(ScanItem(targets: ["。", "、", "\n"], direction: .backward))) + } + Button("特定の文字まで移動") { + process(.smartMoveCursor(ScanItem(targets: ["。", "、", "\n"], direction: .backward))) + } Button("片手モードをオン") { process(.enableResizingMode) } diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 2cc8faac..84f3c013 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -6041,6 +6041,16 @@ } } }, + "右向き" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Forward" + } + } + } + }, "右端の値" : { "localizations" : { "en" : { @@ -6683,6 +6693,16 @@ } } }, + "左向き" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Backward" + } + } + } + }, "左端の値" : { "localizations" : { "en" : { @@ -7168,6 +7188,16 @@ } } }, + "方向" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Direction" + } + } + } + }, "日" : { "localizations" : { "en" : { @@ -7989,6 +8019,26 @@ } } }, + "特定の文字まで削除" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Delete until certain letters" + } + } + } + }, + "特定の文字まで移動" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move cursor until certain letters" + } + } + } + }, "特殊キーの背景色" : { "localizations" : { "en" : { @@ -8168,6 +8218,16 @@ } } }, + "目指す文字(改行区切り)" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Target characters (line-separated)" + } + } + } + }, "目立たないキー" : { "localizations" : { "en" : { From 10b3638c4a0eb9932f96fe330a5807495fee0b9b Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 05:40:37 +0900 Subject: [PATCH 062/124] Support upper/lower key --- .../View/CustomKeybaord/CustomKeyboard.swift | 6 ++++++ MainApp/Customize/CustardInterfaceKeyEditor.swift | 1 + Resources/Localizable.xcstrings | 10 ++++++++++ azooKey.xcodeproj/project.pbxproj | 5 +++-- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index 02f5c45f..859f7888 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -134,6 +134,8 @@ extension CustardInterfaceKey { return FlickChangeKeyboardModel.shared case .enter: return FlickEnterKeyModel() + case .upperLower: + return FlickAaKeyModel() case .flickKogaki: return FlickKogakiKeyModel.shared case .flickKutoten: @@ -189,6 +191,8 @@ extension CustardInterfaceKey { return changeKeyboardKey case .enter: return QwertyEnterKeyModel(keySizeType: .enter) + case .upperLower: + return QwertyAaKeyModel() case .flickKogaki: return convertToQwertyKeyModel(customKey: Extension.SettingProvider.koganaFlickCustomKey.compiled(), extension: Extension.self) case .flickKutoten: @@ -231,6 +235,8 @@ extension CustardInterfaceKey { return SimpleChangeKeyboardKeyModel() case .enter: return SimpleEnterKeyModel() + case .upperLower: + return SimpleKeyModel(keyLabelType: .text("a/A"), unpressedKeyColorType: .special, pressActions: [.changeCharacterType]) case .flickKogaki: return SimpleKeyModel(keyLabelType: .text("小゙゚"), unpressedKeyColorType: .special, pressActions: [.changeCharacterType]) case .flickKutoten: diff --git a/MainApp/Customize/CustardInterfaceKeyEditor.swift b/MainApp/Customize/CustardInterfaceKeyEditor.swift index 5d3cff67..595f00f5 100644 --- a/MainApp/Customize/CustardInterfaceKeyEditor.swift +++ b/MainApp/Customize/CustardInterfaceKeyEditor.swift @@ -431,6 +431,7 @@ struct CustardInterfaceKeyEditor: View { Text("空白キー").tag(CustardInterfaceKey.custom(.flickSpace())) Text("地球儀キー").tag(CustardInterfaceKey.system(.changeKeyboard)) Text("小書き・濁点化キー").tag(CustardInterfaceKey.system(.flickKogaki)) + Text("大文字・小文字キー").tag(CustardInterfaceKey.system(.upperLower)) Text("句読点キー").tag(CustardInterfaceKey.system(.flickKutoten)) Text("日本語タブキー").tag(CustardInterfaceKey.system(.flickHiraTab)) Text("英語タブキー").tag(CustardInterfaceKey.system(.flickAbcTab)) diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 2cc8faac..f76c578a 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -6424,6 +6424,16 @@ } } }, + "大文字・小文字キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Case key" + } + } + } + }, "大文字/小文字、拗音/濁音/半濁音の切り替え" : { "localizations" : { "en" : { diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index 32941ef4..03731d56 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -1937,8 +1937,9 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ensan-hcl/CustardKit"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.0; + kind = versionRange; + maximumVersion = 1.4.0; + minimumVersion = 1.3.0; }; }; 1A9E908A2822CEB400E73846 /* XCRemoteSwiftPackageReference "swift-collections" */ = { From 1a7ff2a75bc8b36d61cdf9a2fbcb53d3c90f8eb9 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 05:48:12 +0900 Subject: [PATCH 063/124] Apply lint --- .../AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift | 2 +- .../View/FlickKeyboard/SuggestView/FlickSuggestState.swift | 2 +- .../View/FlickKeyboard/SuggestView/FlickSuggestType.swift | 2 +- .../SuggestView/extension FlickDirection.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift | 2 +- Keyboard/Display/PredictionManager.swift | 4 ++-- MainApp/Customize/CodableActionDataEditor.swift | 6 +++--- .../FlickCustomKeys/FlickCustomKeySettingView.swift | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift index fcab3762..1358c27a 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/KeyboardSetting.swift @@ -32,7 +32,7 @@ public struct KeyboardSetting { /// 生の`SettingKey`の値を`@State`で宣言した場合、更新の反映ができない。 /// `SettingUpdater`で包むことで、設定の更新を行いつつUIの更新も行われるようにできる。 @MainActor public struct SettingUpdater { - public var value: Wrapped.Value { + public var value: Wrapped.Value { didSet { let newValue = value Wrapped.value = newValue diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift index 6bbf7e7a..af1052a1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestState.swift @@ -1,6 +1,6 @@ // // FlickSuggestState.swift -// +// // // Created by miwa on 2023/08/20. // diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift index 0895295c..8959cb1b 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestType.swift @@ -1,6 +1,6 @@ // // FlickSuggestType.swift -// +// // // Created by miwa on 2023/08/20. // diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift index 8f850f0b..dbb35ca7 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/extension FlickDirection.swift @@ -1,6 +1,6 @@ // // extension FlickDirection.swift -// +// // // Created by miwa on 2023/08/20. // diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift index 49c1b595..751c657c 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift @@ -1,6 +1,6 @@ // // QwertyShiftKeyModel.swift -// +// // // Created by ensan on 2023/08/11. // diff --git a/Keyboard/Display/PredictionManager.swift b/Keyboard/Display/PredictionManager.swift index 02ae07af..2c5c35d8 100644 --- a/Keyboard/Display/PredictionManager.swift +++ b/Keyboard/Display/PredictionManager.swift @@ -69,9 +69,9 @@ extension PostCompositionPredictionCandidate: ResultViewItemData { public var inputable: Bool { true } -#if DEBUG + #if DEBUG public func getDebugInformation() -> String { text } -#endif + #endif } diff --git a/MainApp/Customize/CodableActionDataEditor.swift b/MainApp/Customize/CodableActionDataEditor.swift index 14f7b3c5..6dddb969 100644 --- a/MainApp/Customize/CodableActionDataEditor.swift +++ b/MainApp/Customize/CodableActionDataEditor.swift @@ -186,13 +186,13 @@ private struct CodableActionEditor: View { case .moveTab: ActionMoveTabEditView($action, availableCustards: availableCustards) case .smartDelete(let item): - ActionScanItemEditor(action: $action) { item } convert: { value in + ActionScanItemEditor(action: $action) { item } convert: { _ in // 重複を除去し、改行を追加する let targets = Array(Set(item.targets + ["\n"]) ) return .smartDelete(ScanItem(targets: targets, direction: item.direction)) } case .smartMoveCursor(let item): - ActionScanItemEditor(action: $action) { item } convert: { value in + ActionScanItemEditor(action: $action) { item } convert: { _ in // 重複を除去し、改行を追加する let targets = Array(Set(item.targets + ["\n"]) ) return .smartMoveCursor(ScanItem(targets: targets, direction: item.direction)) @@ -247,7 +247,7 @@ private struct ActionScanItemEditor: View { } .font(.body.monospaced()) .frame(maxWidth: 50) - } + } } .onChange(of: value) {value in if let data = convert(value) { diff --git a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift index 98bd28f9..99780ab2 100644 --- a/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift +++ b/MainApp/Setting/CustomKeys/FlickCustomKeys/FlickCustomKeySettingView.swift @@ -211,7 +211,7 @@ struct FlickCustomKeySettingView: Vie Button("リセット") { self.reload() } - .foregroundStyle(.red) + .foregroundStyle(.red) } else { Text("このキーは編集できません") } From fb497ef6330315c38c47972b87ca307f5db62417 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 05:49:54 +0900 Subject: [PATCH 064/124] Fix bugs --- MainApp/Customize/CodableActionDataEditor.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/MainApp/Customize/CodableActionDataEditor.swift b/MainApp/Customize/CodableActionDataEditor.swift index 6dddb969..053ec612 100644 --- a/MainApp/Customize/CodableActionDataEditor.swift +++ b/MainApp/Customize/CodableActionDataEditor.swift @@ -186,16 +186,16 @@ private struct CodableActionEditor: View { case .moveTab: ActionMoveTabEditView($action, availableCustards: availableCustards) case .smartDelete(let item): - ActionScanItemEditor(action: $action) { item } convert: { _ in + ActionScanItemEditor(action: $action) { item } convert: { value in // 重複を除去し、改行を追加する - let targets = Array(Set(item.targets + ["\n"]) ) - return .smartDelete(ScanItem(targets: targets, direction: item.direction)) + let targets = Array(Set(value.targets + ["\n"]) ) + return .smartDelete(ScanItem(targets: targets, direction: value.direction)) } case .smartMoveCursor(let item): - ActionScanItemEditor(action: $action) { item } convert: { _ in + ActionScanItemEditor(action: $action) { item } convert: { value in // 重複を除去し、改行を追加する - let targets = Array(Set(item.targets + ["\n"]) ) - return .smartMoveCursor(ScanItem(targets: targets, direction: item.direction)) + let targets = Array(Set(value.targets + ["\n"]) ) + return .smartMoveCursor(ScanItem(targets: targets, direction: value.direction)) } case .replaceLastCharacters: EmptyView() From 43c071c75f52a9205c793cacfef218222ad946bf Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 06:01:50 +0900 Subject: [PATCH 065/124] Update project setting --- .../xcschemes/KanaKanjiConverterModuleTests.xcscheme | 2 +- azooKey.xcodeproj/project.pbxproj | 4 +++- azooKey.xcodeproj/xcshareddata/xcschemes/Keyboard.xcscheme | 2 +- azooKey.xcodeproj/xcshareddata/xcschemes/MainApp.xcscheme | 2 +- .../xcshareddata/xcschemes/azooKeyTests.xcscheme | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/AzooKeyCore/.swiftpm/xcode/xcshareddata/xcschemes/KanaKanjiConverterModuleTests.xcscheme b/AzooKeyCore/.swiftpm/xcode/xcshareddata/xcschemes/KanaKanjiConverterModuleTests.xcscheme index 78693a4e..f6ac01e4 100644 --- a/AzooKeyCore/.swiftpm/xcode/xcshareddata/xcschemes/KanaKanjiConverterModuleTests.xcscheme +++ b/AzooKeyCore/.swiftpm/xcode/xcshareddata/xcschemes/KanaKanjiConverterModuleTests.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 24 Sep 2023 06:01:57 +0900 Subject: [PATCH 066/124] Adopt refactoring --- MainApp/Customize/CustomizeTabView.swift | 4 ++-- MainApp/EnableAzooKeyView/EnableAzooKeyView.swift | 6 +++--- .../EnableAzooKeyView/EnableAzooKeyViewComponent.swift | 8 ++++---- MainApp/General/ImageSlideshowView.swift | 4 ++-- .../QwertyCustomKeys/CustomKeysSettingView.swift | 4 ++-- MainApp/Tips/Articles/CursorMoveTips.swift | 2 +- MainApp/Tips/Articles/CustomKeyTipsView.swift | 4 ++-- MainApp/Tips/Articles/FullAccessTipsView.swift | 2 +- MainApp/Tips/Articles/KanjiLargeText.swift | 6 +++--- MainApp/Tips/Articles/OneHandedModeTips.swift | 8 ++++---- .../Articles/PasteFromOtherAppsPermissionTipsView.swift | 4 ++-- MainApp/Tips/Articles/SmoothDeleteTipsView.swift | 2 +- MainApp/Tips/Articles/TemplateSettingTipsView.swift | 8 ++++---- MainApp/Tips/TipsViewComponent.swift | 8 ++++---- 14 files changed, 35 insertions(+), 35 deletions(-) diff --git a/MainApp/Customize/CustomizeTabView.swift b/MainApp/Customize/CustomizeTabView.swift index 0612e193..2d0de750 100644 --- a/MainApp/Customize/CustomizeTabView.swift +++ b/MainApp/Customize/CustomizeTabView.swift @@ -19,7 +19,7 @@ struct CustomizeTabView: View { NavigationView { Form { Section(header: Text("カスタムタブ")) { - ImageSlideshowView(pictures: ["custard_1", "custard_2", "custard_3" ]) + ImageSlideshowView(pictures: [.custard1, .custard2, .custard3]) .listRowSeparator(.hidden, edges: .bottom) Text("好きな文字や文章を並べたオリジナルのタブを作成することができます。") NavigationLink("カスタムタブの管理", destination: ManageCustardView(manager: $appStates.custardManager)) @@ -28,7 +28,7 @@ struct CustomizeTabView: View { Section(header: Text("タブバー")) { CenterAlignedView { - Image("tabBar_1") + Image(.tabBar1) .resizable() .scaledToFit() .frame(maxWidth: MainAppDesign.imageMaximumWidth) diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift index 2f2d1244..1a46a0d0 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift @@ -62,9 +62,9 @@ struct EnableAzooKeyView: View { EnableAzooKeyViewHeader("追加する") EnableAzooKeyViewText("下にスクロールして「追加する」を押して", with: "plus.circle") EnableAzooKeyViewText("「キーボード」を押して", with: "keyboard") - EnableAzooKeyViewImage("initSettingKeyboardImage-hand") + EnableAzooKeyViewImage(.initSettingKeyboardImageHand) EnableAzooKeyViewText("azooKeyをオンにして", with: "square.and.line.vertical.and.square.fill") - EnableAzooKeyViewImage("initSettingAzooKeySwitchImage-hand") + EnableAzooKeyViewImage(.initSettingAzooKeySwitchImageHand) EnableAzooKeyViewText("このアプリを再び開いてください", with: "arrow.turn.down.left") CenterAlignedView { EnableAzooKeyViewButton("追加する", systemName: "plus.circle") { @@ -134,7 +134,7 @@ struct EnableAzooKeyView: View { appStates.requireFirstOpenView = false } if !showDoneMessage { - EnableAzooKeyViewImage("initSettingGlobeTapImage") + EnableAzooKeyViewImage(.initSettingGlobeTap) } EnableAzooKeyViewText("azooKeyをお楽しみください!", with: "star.fill") if !showDoneMessage { diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift index 6f73f7b9..0574c628 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift @@ -90,13 +90,13 @@ struct EnableAzooKeyViewButton: View { } struct EnableAzooKeyViewImage: View { - private let identifier: String - init(_ identifier: String) { - self.identifier = identifier + private let resource: ImageResource + init(_ resource: ImageResource) { + self.resource = resource } var body: some View { - Image(identifier) + Image(resource) .resizable() .scaledToFit() .cornerRadius(2) diff --git a/MainApp/General/ImageSlideshowView.swift b/MainApp/General/ImageSlideshowView.swift index 21c9f27a..a7ba4a71 100644 --- a/MainApp/General/ImageSlideshowView.swift +++ b/MainApp/General/ImageSlideshowView.swift @@ -10,8 +10,8 @@ import SwiftUI import SwiftUIUtils struct ImageSlideshowView: View { - private let pictures: [String] - init(pictures: [String]) { + private let pictures: [ImageResource] + init(pictures: [ImageResource]) { self.pictures = pictures } diff --git a/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift b/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift index 8c207198..6a50f245 100644 --- a/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift +++ b/MainApp/Setting/CustomKeys/QwertyCustomKeys/CustomKeysSettingView.swift @@ -10,13 +10,13 @@ import SwiftUI struct CustomKeysSettingView: View { var body: some View { - ImageSlideshowView(pictures: ["flickCustomKeySetting0", "flickCustomKeySetting1", "flickCustomKeySetting2"]) + ImageSlideshowView(pictures: [.flickCustomKeySetting0, .flickCustomKeySetting1, .flickCustomKeySetting2]) .listRowSeparator(.hidden, edges: .bottom) Text("「小゙゚」キーと「、。?!」キーで入力する文字をカスタマイズすることができます。") NavigationLink("設定する", destination: FlickCustomKeysSettingSelectView()) .foregroundStyle(.accentColor) .listRowSeparator(.visible, edges: .all) - ImageSlideshowView(pictures: ["qwertyCustomKeySetting0", "qwertyCustomKeySetting1", "qwertyCustomKeySetting2"]) + ImageSlideshowView(pictures: [.qwertyCustomKeySetting0, .qwertyCustomKeySetting1, .qwertyCustomKeySetting2]) .listRowSeparator(.hidden, edges: .bottom) Text("数字タブの青枠部分に好きな記号や文字を割り当てられます。") NavigationLink("設定する", destination: QwertyCustomKeysSettingView(.numberTabCustomKeys)) diff --git a/MainApp/Tips/Articles/CursorMoveTips.swift b/MainApp/Tips/Articles/CursorMoveTips.swift index e9bd1cf6..983b6316 100644 --- a/MainApp/Tips/Articles/CursorMoveTips.swift +++ b/MainApp/Tips/Articles/CursorMoveTips.swift @@ -14,7 +14,7 @@ struct CursorMoveTipsView: View { TipsContentView("カーソルを移動する") { TipsContentParagraph { Text("「空白」を長押しすると、カーソルバーが現れます。ホームボタンのない端末のフリック入力では左下の\(systemImage: "arrowtriangle.left.and.line.vertical.and.arrowtriangle.right")を押して表示することも可能です。") - TipsImage("moveCursor") + TipsImage(.moveCursor) } TipsContentParagraph { diff --git a/MainApp/Tips/Articles/CustomKeyTipsView.swift b/MainApp/Tips/Articles/CustomKeyTipsView.swift index 91f16943..dc6593c4 100644 --- a/MainApp/Tips/Articles/CustomKeyTipsView.swift +++ b/MainApp/Tips/Articles/CustomKeyTipsView.swift @@ -16,11 +16,11 @@ struct CustomKeyTipsView: View { } TipsContentParagraph { Text("フリック入力では、ひらがなタブの「小゙゚」キーと「、。?!」キーのフリックに最大3方向まで好きな文字を登録することができます。") - ImageSlideshowView(pictures: ["flickCustomKeySetting0", "flickCustomKeySetting1", "flickCustomKeySetting2"]) + ImageSlideshowView(pictures: [.flickCustomKeySetting0, .flickCustomKeySetting1, .flickCustomKeySetting2]) } TipsContentParagraph { Text("ローマ字入力では、数字タブの一部キーに好きな文字と長押ししたときの候補を登録することができます。") - ImageSlideshowView(pictures: ["qwertyCustomKeySetting0", "qwertyCustomKeySetting1", "qwertyCustomKeySetting2"]) + ImageSlideshowView(pictures: [.qwertyCustomKeySetting0, .qwertyCustomKeySetting1, .qwertyCustomKeySetting2]) } } } diff --git a/MainApp/Tips/Articles/FullAccessTipsView.swift b/MainApp/Tips/Articles/FullAccessTipsView.swift index ddfa1443..673f3d60 100644 --- a/MainApp/Tips/Articles/FullAccessTipsView.swift +++ b/MainApp/Tips/Articles/FullAccessTipsView.swift @@ -52,7 +52,7 @@ struct FullAccessTipsView: View { TipsContentParagraph { Text("フルアクセスを有効化する際、以下のような警告が表示されますが、すべてのキーボードアプリで共通して表示されている警告です。") - TipsImage("fullAccessAlert") + TipsImage(.fullAccessAlert) Text("azooKeyは安全なキーボードアプリであり、ユーザの明示的な同意なく、個人情報を外部に送信したり、保存したりすることはありません。") Text("なお、azooKeyはオープンソースであり、誰もが実装を確認することができます。") } diff --git a/MainApp/Tips/Articles/KanjiLargeText.swift b/MainApp/Tips/Articles/KanjiLargeText.swift index d3639372..987e51b2 100644 --- a/MainApp/Tips/Articles/KanjiLargeText.swift +++ b/MainApp/Tips/Articles/KanjiLargeText.swift @@ -18,17 +18,17 @@ struct KanjiLargeTextTipsView: View { TipsContentParagraph { Text("文字を拡大するには、まず拡大したい文字を入力した上で変換候補を長押しします。") - TipsImage("LargeTextTips_1") + TipsImage(.largeTextTips1) } TipsContentParagraph { Text("長押し後表示される画面で「大きな文字で表示する」をタップします。") - TipsImage("LargeTextTips_2") + TipsImage(.largeTextTips2) } TipsContentParagraph { Text("最大限大きなサイズで文字が表示されます。右にスクロールすると途切れている文字を確認することができます。") - TipsImage("LargeTextTips_3") + TipsImage(.largeTextTips3) } TipsContentParagraph(style: .caption) { diff --git a/MainApp/Tips/Articles/OneHandedModeTips.swift b/MainApp/Tips/Articles/OneHandedModeTips.swift index 8605b87e..f91ba43f 100644 --- a/MainApp/Tips/Articles/OneHandedModeTips.swift +++ b/MainApp/Tips/Articles/OneHandedModeTips.swift @@ -18,22 +18,22 @@ struct OneHandedModeTipsView: View { TipsContentParagraph { Text("まずタブバーを表示します。変換候補欄を長押しするか記号タブキーを長押しすると表示されます。") Text("「片手」をタップします。") - TipsImage("oneHandedMode_1") + TipsImage(.oneHandedMode1) } TipsContentParagraph { Text("サイズの調整モードがオンになります。左右の白い部分をドラッグし、好みのサイズに調整してください。") - TipsImage("oneHandedMode_2") + TipsImage(.oneHandedMode2) } TipsContentParagraph { Text("\(systemImage: "checkmark")をタップすると完了します。") Text("\(systemImage: "arrow.triangle.2.circlepath")をタップするとリセットされます。") - TipsImage("oneHandedMode_3") + TipsImage(.oneHandedMode3) } TipsContentParagraph { Text("\(systemImage: "checkmark")を押して完了したあとは通常のキーボードと同様に使えます。") Text("\(systemImage: "aspectratio")を押すと再度編集できます。") Text("\(systemImage: "arrow.up.backward.and.arrow.down.forward")を押すと通常の両手モードに戻ります。") - TipsImage("oneHandedMode_4") + TipsImage(.oneHandedMode4) } } } diff --git a/MainApp/Tips/Articles/PasteFromOtherAppsPermissionTipsView.swift b/MainApp/Tips/Articles/PasteFromOtherAppsPermissionTipsView.swift index 2057bc7e..48e5ac81 100644 --- a/MainApp/Tips/Articles/PasteFromOtherAppsPermissionTipsView.swift +++ b/MainApp/Tips/Articles/PasteFromOtherAppsPermissionTipsView.swift @@ -13,7 +13,7 @@ struct PasteFromOtherAppsPermissionTipsView: View { TipsContentView("「ほかのAppからペースト」について") { TipsContentParagraph { Text("「クリップボードの履歴」や「ペーストボタン」の機能を利用している際、頻繁に「ペーストの許可」を求めるダイアログが出ることがあります。") - TipsImage("pasteRequestDialogue") + TipsImage(.pasteRequestDialogue) Text("azooKeyはクリップボードの履歴を保存するため、定期的にクリップボードをチェックします。また、ペーストする際にもクリップボードの情報を利用します。") } TipsContentParagraph { @@ -27,7 +27,7 @@ struct PasteFromOtherAppsPermissionTipsView: View { } } TipsContentParagraph { - TipsImage("pasteFromOtherAppsSetting") + TipsImage(.pasteFromOtherAppsSetting) } TipsContentParagraph { Text("なお、「クリップボードの履歴」を有効にしていない場合、クリップボードの中身を定期的に取得することはありません。また、取得したクリップボードのテキストはアプリ内でのみ利用されます。") diff --git a/MainApp/Tips/Articles/SmoothDeleteTipsView.swift b/MainApp/Tips/Articles/SmoothDeleteTipsView.swift index 2102d049..2a3dd8db 100644 --- a/MainApp/Tips/Articles/SmoothDeleteTipsView.swift +++ b/MainApp/Tips/Articles/SmoothDeleteTipsView.swift @@ -14,7 +14,7 @@ struct SmoothDeleteTipsView: View { TipsContentView("文頭まで削除する") { TipsContentParagraph { Text("フリックのキーボードでは削除\(systemImage: "delete.left")キーを左にフリックすると、文頭まで削除することができます。") - TipsImage("smoothDelete") + TipsImage(.smoothDelete) } TipsContentParagraph { Text("誤って削除してしまった場合は端末を振るか、入力欄を三本指でスワイプすることで取り消し操作を行うことが可能です。") diff --git a/MainApp/Tips/Articles/TemplateSettingTipsView.swift b/MainApp/Tips/Articles/TemplateSettingTipsView.swift index fd87a9df..20f14ff2 100644 --- a/MainApp/Tips/Articles/TemplateSettingTipsView.swift +++ b/MainApp/Tips/Articles/TemplateSettingTipsView.swift @@ -18,7 +18,7 @@ struct TemplateSettingTipsView: View { } TipsContentParagraph { Text("まず「テンプレートの管理」から新しいテンプレートを作成します。画面右上の\(systemImage: "plus", color: .accentColor)を押して、テンプレートを追加しましょう。") - TipsImage("templateSettingTips_1") + TipsImage(.templateSettingTips1) } TipsContentParagraph { Text("追加したテンプレートを選ぶと編集画面が開きます。") @@ -26,19 +26,19 @@ struct TemplateSettingTipsView: View { Text("・名前を「タイムスタンプ」に設定") Text("・書式で「カスタム」を選択") Text("・カスタム書式に「yyyy/MM/dd hh:mm」と入力") - TipsImage("templateSettingTips_2") + TipsImage(.templateSettingTips2) Text("編集が終わったら完了ボタンを押してください。") } TipsContentParagraph { Text("次にユーザ辞書でテンプレートを使います。「追加する」から新規に単語を登録し、編集画面が開きます。") Text("ユーザ辞書で作成したテンプレートを使う際は、\(monospaced: "{{テンプレート名}}")という形式で記述します。") Text("今回は「タイムスタンプ」というテンプレートなので、\(monospaced: "{{タイムスタンプ}}")と入力します。") - TipsImage("templateSettingTips_3") + TipsImage(.templateSettingTips3) Text("編集が終わったら完了ボタンを押してください。") } TipsContentParagraph { Text("以上で設定が完了です。あとは実際に使ってみましょう。") - TipsImage("templateSettingTips_4") + TipsImage(.templateSettingTips4) } TipsContentParagraph { Text("「yyyy/MM/dd hh:mm」というのは日付の書式の書き方で、「yyyy」が4桁の年、「MM」が2桁の月、「dd」は2桁の日付を指しています。「hh」と「mm」も同様に時間と分です。") diff --git a/MainApp/Tips/TipsViewComponent.swift b/MainApp/Tips/TipsViewComponent.swift index 6275ac08..b51fbf4b 100644 --- a/MainApp/Tips/TipsViewComponent.swift +++ b/MainApp/Tips/TipsViewComponent.swift @@ -48,15 +48,15 @@ struct TipsContentParagraph: View { } struct TipsImage: View { - private let name: String + private let resource: ImageResource - init(_ name: String) { - self.name = name + init(_ resource: ImageResource) { + self.resource = resource } var body: some View { CenterAlignedView { - Image(self.name) + Image(self.resource) .resizable() .scaledToFit() .cornerRadius(2) From 354ed45977df738efa18ffac8606da4384f881af Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 18:33:20 +0900 Subject: [PATCH 067/124] fix build error --- azooKey.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index abb8494a..20109889 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -172,6 +172,7 @@ 557D9DFF2ABF2B9D0028F3A0 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557D9DFE2ABF2B9D0028F3A0 /* InfoPlist.xcstrings */; }; 557D9E012ABF320F0028F3A0 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557D9E002ABF320F0028F3A0 /* Localizable.xcstrings */; }; 557D9E022ABF320F0028F3A0 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 557D9E002ABF320F0028F3A0 /* Localizable.xcstrings */; }; + 5592F5AE2AC0395D00AA1325 /* PredictionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5598472D2AB84F5200B18C15 /* PredictionManager.swift */; }; 5598472E2AB84F5200B18C15 /* PredictionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5598472D2AB84F5200B18C15 /* PredictionManager.swift */; }; /* End PBXBuildFile section */ @@ -1370,6 +1371,7 @@ 1A2E58592951EC87004F959B /* (null) in Sources */, 1A2E585F2951ED56004F959B /* (null) in Sources */, 1A73F20B29C0B01C00833C11 /* InputManager.swift in Sources */, + 5592F5AE2AC0395D00AA1325 /* PredictionManager.swift in Sources */, 1AD8D749295E8A8E00112B80 /* LiveConversionManager.swift in Sources */, 1AC09DBE299533E0009BDBC7 /* DicdataStoreTests.swift in Sources */, 1A2E585A2951EC87004F959B /* (null) in Sources */, From 9874cbde0f25f8125a696bdf11140de49962d7c2 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 24 Sep 2023 18:58:38 +0900 Subject: [PATCH 068/124] relax bundle name check condition --- MainApp/EnableAzooKeyView/EnableAzooKeyView.swift | 2 +- MainApp/Utils/checkKeyboardActivation.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift index 1a46a0d0..4269783c 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift @@ -193,6 +193,6 @@ struct EnableAzooKeyView: View { .filtered(using: NSPredicate(format: "isDisplayed = YES")) .first .flatMap {($0 as? UITextInputMode)?.value(forKey: "identifier") as? String} - return currentKeyboardIdentifier == SharedStore.bundleName + return currentKeyboardIdentifier?.hasPrefix(SharedStore.bundleName) == true } } diff --git a/MainApp/Utils/checkKeyboardActivation.swift b/MainApp/Utils/checkKeyboardActivation.swift index b0420ea8..eefc5d0c 100644 --- a/MainApp/Utils/checkKeyboardActivation.swift +++ b/MainApp/Utils/checkKeyboardActivation.swift @@ -13,6 +13,6 @@ import enum AzooKeyUtils.SharedStore extension SharedStore { @MainActor static func checkKeyboardActivation() -> Bool { let keyboards = UITextInputMode.activeInputModes.compactMap {$0.value(forKey: "identifier") as? String} - return keyboards.contains(SharedStore.bundleName) + return keyboards.contains { $0.hasPrefix(SharedStore.bundleName) } } } From 0f96594cd64837ba33f6304191c4c8c34e692b2b Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 26 Sep 2023 21:42:34 +0900 Subject: [PATCH 069/124] improve action optimization logic --- Keyboard/Display/KeyboardActionManager.swift | 56 ++++++++++++++------ 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index bc72cf27..5665d9f2 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -306,21 +306,33 @@ import SwiftUtils self.doAction(action, variableStates: variableStates) } - /// 複数のアクションを実行する - /// - note: アクションを実行する前に最適化を施すことでパフォーマンスを向上させる - /// サポートされている最適化 - /// - `setResult`を一度のみ実施する - override func registerActions(_ actions: [ActionType], variableStates: VariableStates) { - let isSetActionTrigger = actions.map { action in - switch action { - case .input, .delete, .changeCharacterType, .smoothDelete, .smartDelete, .moveCursor, .replaceLastCharacters, .smartMoveCursor: - return true - default: - return false - } + private enum ActionTriggerStyle { + /// 集約対象ではない + case irrelevant + /// 集約を強制的に止める + case separator + /// 集約できるアクション + case maybe + } + + private func actionTriggerStyle(_ action: ActionType) -> ActionTriggerStyle { + switch action { + case .input, .delete, .changeCharacterType, .smoothDelete, .smartDelete, .moveCursor, .replaceLastCharacters, .smartMoveCursor: + .maybe + case .enter: + .separator + default: + .irrelevant } - if let lastIndex = isSetActionTrigger.lastIndex(where: { $0 }) { - for (i, action) in actions.enumerated() { + } + + /// actionの塊を実行する + /// - parameters: + /// - actionBlock: アクションの一連の列。1つのブロックの中には任意個の集約対象のアクションと集約対象でないアクションが含まれ、先頭にのみ集約できないアクションが出現できる + private func runActionBlock(actionBlock: some BidirectionalCollection, variableStates: VariableStates) { + // setResult可能な最後の + if let lastIndex = actionBlock.lastIndex(where: { actionTriggerStyle($0) != .irrelevant }) { + for (i, action) in zip(actionBlock.indices, actionBlock) { if i == lastIndex { self.doAction(action, requireSetResult: true, variableStates: variableStates) } else { @@ -328,12 +340,26 @@ import SwiftUtils } } } else { - for action in actions { + for action in actionBlock { self.doAction(action, variableStates: variableStates) } } } + /// 複数のアクションを実行する + /// - note: アクションを実行する前に最適化を施すことでパフォーマンスを向上させる + /// サポートされている最適化 + /// - `setResult`を一度のみ実施する + override func registerActions(_ actions: [ActionType], variableStates: VariableStates) { + var actions = actions[...] + while let firstIndex = actions.firstIndex(where: { actionTriggerStyle($0) == .separator }) { + self.runActionBlock(actionBlock: actions[...firstIndex], variableStates: variableStates) + self.doAction(actions[firstIndex], variableStates: variableStates) + actions = actions[(firstIndex + 1)...] + } + self.runActionBlock(actionBlock: actions, variableStates: variableStates) + } + /// 長押しを予約する関数。 /// - Parameters: /// - action: 長押しで起こる動作のタイプ。 From 8b0c5497dae7d31adff8f7e979f051868fa89a28 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Wed, 27 Sep 2023 00:34:09 +0900 Subject: [PATCH 070/124] feature: implement select_candidate action and its view behavior --- .../Sources/KeyboardViews/Action.swift | 9 +++ .../Sources/KeyboardViews/ActionUtils.swift | 2 +- .../KeyboardViews/VariableStates.swift | 2 +- .../View/Components/ExpandedResultView.swift | 2 +- .../View/KeyboardBar/EmojiTabResultBar.swift | 4 +- .../View/KeyboardBar/ResultBar.swift | 41 ++++++------ .../View/KeyboardBar/ResultViewItemData.swift | 63 ++++++++++++++++++- .../View/SpecialTabs/EmojiTab.swift | 4 +- .../UpsideComponents/UpsideSearchView.swift | 4 +- Keyboard/Display/InputManager.swift | 4 +- Keyboard/Display/KeyboardActionManager.swift | 18 ++++-- Keyboard/Display/KeyboardViewController.swift | 2 +- MainApp/General/KeyboardPreview.swift | 2 +- 13 files changed, 115 insertions(+), 42 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/Action.swift b/AzooKeyCore/Sources/KeyboardViews/Action.swift index 0ca7d7e1..f56e2cdb 100644 --- a/AzooKeyCore/Sources/KeyboardViews/Action.swift +++ b/AzooKeyCore/Sources/KeyboardViews/Action.swift @@ -57,6 +57,15 @@ public indirect enum ActionType: Equatable, Sendable { // 条件分岐アクション case boolSwitch(CompiledExpression, trueAction: [ActionType], falseAction: [ActionType]) + + // 選択アクション + case selectCandidate(CandidateSelectionRequest) +} +public enum CandidateSelectionRequest: Equatable, Sendable { + case first + case last + case exact(Int) + case offset(Int) } public struct LongpressActionType: Equatable, Sendable { diff --git a/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift b/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift index d2449242..7a8a8146 100644 --- a/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift +++ b/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift @@ -95,7 +95,7 @@ public extension ActionType { KeyboardFeedback.delete() case .smoothDelete, .smartDelete, .smartMoveCursor: KeyboardFeedback.smoothDelete() - case .moveTab, .enter, .changeCharacterType, .setCursorBar, .moveCursor, .enableResizingMode, .replaceLastCharacters, .setTabBar, .setBoolState, .setUpsideComponent, .setSearchQuery/*, ._setBoolState*/: + case .moveTab, .enter, .changeCharacterType, .setCursorBar, .moveCursor, .enableResizingMode, .replaceLastCharacters, .setTabBar, .setBoolState, .setUpsideComponent, .setSearchQuery, .selectCandidate/*, ._setBoolState*/: KeyboardFeedback.tabOrOtherKey() case .openApp, .dismissKeyboard, .hideLearningMemory: return diff --git a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift index f2f1fa16..042efc2a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift +++ b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift @@ -121,7 +121,7 @@ public final class VariableStates: ObservableObject { private(set) public var keyboardType: UIKeyboardType = .default /// `ResultModel`の変数 - @Published public var resultModelVariableSection = ResultModelVariableSection() + @Published public var resultModel = ResultModel() // Bool値の変数はここにまとめる @Published public var boolStates = BoolStates() diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift index bb2a2004..89d930cf 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/ExpandedResultView.swift @@ -15,7 +15,7 @@ struct ExpandedResultView: @Binding private var isResultViewExpanded: Bool private var splitedResults: [SplitedResultData] { - Self.registerResults(results: variableStates.resultModelVariableSection.results, interfaceWidth: variableStates.interfaceSize.width) + Self.registerResults(results: variableStates.resultModel.results, interfaceWidth: variableStates.interfaceSize.width) } private var buttonWidth: CGFloat { Design.keyboardBarHeight(interfaceHeight: variableStates.interfaceSize.height, orientation: variableStates.keyboardOrientation) * 0.5 diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift index 91a63514..4e6653be 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift @@ -59,7 +59,7 @@ struct EmojiTabResultBar: V .matchedGeometryEffect(id: "SearchBar", in: namespace) ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 10) { - ForEach(variableStates.resultModelVariableSection.results, id: \.id) {(data: ResultData) in + ForEach(variableStates.resultModel.results, id: \.id) {(data: ResultData) in if data.candidate.inputable { Button(data.candidate.text) { KeyboardFeedback.click() @@ -80,7 +80,7 @@ struct EmojiTabResultBar: V } } } - .onChange(of: variableStates.resultModelVariableSection.results.first?.candidate.text) { newValue in + .onChange(of: variableStates.resultModel.results.first?.candidate.text) { newValue in if newValue == nil && showResults { withAnimation(.easeIn(duration: 0.2)) { showResults = false diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index 22584804..b44cd162 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -51,21 +51,9 @@ struct ResultBar: View { .matchedGeometryEffect(id: "KeyboardBarButton", in: namespace) } - private var isResultMode: Bool { - !variableStates.resultModelVariableSection.results.isEmpty - } - - private var resultData: [ResultData] { - if isResultMode { - variableStates.resultModelVariableSection.results - } else { - variableStates.resultModelVariableSection.predictionResults - } - } - var body: some View { Group { - if resultData.isEmpty { + if variableStates.resultModel.displayState == .nothing { CenterAlignedView { if displayTabBarButton { tabBarButton @@ -103,20 +91,20 @@ struct ResultBar: View { } } else { HStack { - if !isResultMode && displayTabBarButton { + if variableStates.resultModel.displayState == .predictions && displayTabBarButton { tabBarButton Spacer() } ScrollView(.horizontal, showsIndicators: false) { ScrollViewReader {scrollViewProxy in LazyHStack(spacing: 10) { - ForEach(resultData, id: \.id) {(data: ResultData) in + ForEach(variableStates.resultModel.resultData, id: \.id) {(data: ResultData) in if data.candidate.inputable { Button(data.candidate.text) { KeyboardFeedback.click() self.pressed(candidate: data.candidate) } - .buttonStyle(ResultButtonStyle(height: buttonHeight)) + .buttonStyle(ResultButtonStyle(height: buttonHeight, selected: data.id == variableStates.resultModel.selection)) .contextMenu { ResultContextMenuView(candidate: data.candidate, displayResetLearningButton: Extension.SettingProvider.canResetLearningForCandidate, index: data.id) } @@ -127,13 +115,21 @@ struct ResultBar: View { .underline(true, color: .accentColor) } } - }.onChange(of: variableStates.resultModelVariableSection.updateResult) { _ in + } + .onChange(of: variableStates.resultModel.updateResult) { _ in scrollViewProxy.scrollTo(0, anchor: .trailing) } + .onChange(of: variableStates.resultModel.selection) { value in + if let value { + withAnimation(.easeIn(duration: 0.05)) { + scrollViewProxy.scrollTo(value, anchor: .trailing) + } + } + } } .padding(.horizontal, 5) } - if isResultMode { + if variableStates.resultModel.displayState == .results { // 候補を展開するボタン Button(action: {self.expand()}) { ZStack { @@ -150,8 +146,7 @@ struct ResultBar: View { } } } - .animation(.easeIn(duration: 0.2), value: variableStates.resultModelVariableSection.results.isEmpty) - .animation(.easeIn(duration: 0.2), value: variableStates.resultModelVariableSection.predictionResults.isEmpty) + .animation(.easeIn(duration: 0.2), value: variableStates.resultModel.displayState) } private func pressed(candidate: any ResultViewItemData) { @@ -217,12 +212,14 @@ struct ResultContextMenuView: View { struct ResultButtonStyle: ButtonStyle { private let height: CGFloat private let userSizePreference: Double + private let selected: Bool @Environment(Extension.Theme.self) private var theme - @MainActor init(height: CGFloat) { + @MainActor init(height: CGFloat, selected: Bool = false) { self.userSizePreference = Extension.SettingProvider.resultViewFontSize self.height = height + self.selected = selected } func makeBody(configuration: Configuration) -> some View { @@ -232,7 +229,7 @@ struct ResultButtonStyle: B .padding(.all, 5) .foregroundStyle(theme.resultTextColor.color) // 文字色は常に不透明度1で描画する .background( - configuration.isPressed ? + (configuration.isPressed || self.selected) ? theme.pushedKeyFillColor.color.opacity(0.5) : theme.resultBackgroundColor.color ) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift index 2135a69c..9bfa7086 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift @@ -16,24 +16,83 @@ public protocol ResultViewItemData { #endif } -public struct ResultModelVariableSection { +public struct ResultModel { private(set) var results: [ResultData] = [] - private(set) var predictionResults: [ResultData] = [] + private var predictionResults: [ResultData] = [] private(set) var searchResults: [ResultData] = [] private(set) var updateResult: Bool = false + private(set) var selection: Int? + + enum DisplayState: Hashable, Sendable { + case nothing + case results + case predictions + } + + /// `results`が空でない場合は`results`の表示を常に優先する + var displayState: DisplayState { + if !results.isEmpty { + .results + } else if !predictionResults.isEmpty { + .predictions + } else { + .nothing + } + } + + var resultData: [ResultData] { + switch displayState { + case .results: + results + case .predictions: + predictionResults + case .nothing: + [] + } + } public mutating func setResults(_ results: [any ResultViewItemData]) { self.results = results.indices.map {ResultData(id: $0, candidate: results[$0])} self.predictionResults = [] + self.selection = nil self.updateResult.toggle() } public mutating func setSearchResults(_ results: [any ResultViewItemData]) { self.searchResults = results.enumerated().map {ResultData(id: $0.offset, candidate: $0.element)} + self.selection = nil } public mutating func setPredictionResults(_ results: [any ResultViewItemData]) { self.predictionResults = results.enumerated().map {ResultData(id: $0.offset, candidate: $0.element)} + self.selection = nil self.updateResult.toggle() } + public mutating func setSelectionRequest(_ request: CandidateSelectionRequest?) { + self.selection = switch request { + case .none: + nil + case .first: + 0 + case .last: + self.resultData.endIndex - 1 + case .exact(let value): + min(max(0, value), self.resultData.endIndex - 1) + case .offset(let value): + if let selection { + min(max(0, selection + value), self.resultData.endIndex - 1) + } else { + 0 + } + } + } + + public func getSelectedCandidate() -> (any ResultViewItemData)? { + if let selection, + self.resultData.indices.contains(selection) { + self.resultData[selection].candidate + } else { + nil + } + } } struct ResultData: Identifiable { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift index fae49311..feb05958 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift @@ -356,11 +356,11 @@ struct EmojiTab: View { if !self.emojis[.recent, default: []].isEmpty { self.selectedGenre = .recent } - variableStates.resultModelVariableSection.setResults([]) + variableStates.resultModel.setResults([]) variableStates.barState = .none } .onDisappear { - variableStates.resultModelVariableSection.setResults([]) + variableStates.resultModel.setResults([]) } } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift b/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift index 4c359c16..87869fd3 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/UpsideComponents/UpsideSearchView.swift @@ -35,7 +35,7 @@ struct UpsideSearchView: Vi VStack { ScrollView(.horizontal, showsIndicators: false) { LazyHStack(spacing: 10) { - ForEach(variableStates.resultModelVariableSection.searchResults, id: \.id) {(data: ResultData) in + ForEach(variableStates.resultModel.searchResults, id: \.id) {(data: ResultData) in if data.candidate.inputable { Button(data.candidate.text) { KeyboardFeedback.click() @@ -76,7 +76,7 @@ struct UpsideSearchView: Vi self.action.setTextDocumentProxy(.preference(.ikTextField)) } .onDisappear { - self.variableStates.resultModelVariableSection.setSearchResults([]) + self.variableStates.resultModel.setSearchResults([]) } } private func pressed(candidate: any ResultViewItemData) { diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 6824c315..c42e68f5 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -46,7 +46,7 @@ import UIKit private var rubyLog: OrderedDictionary = [:] // 変換結果の通知用関数 - private var updateResult: (((inout ResultModelVariableSection) -> Void) -> Void)? + private var updateResult: (((inout ResultModel) -> Void) -> Void)? private var liveConversionEnabled: Bool { liveConversionManager.enabled && !self.isSelected @@ -194,7 +194,7 @@ import UIKit self.displayedTextManager.setTextDocumentProxy(proxy) } - func setUpdateResult(_ updateResult: (((inout ResultModelVariableSection) -> Void) -> Void)?) { + func setUpdateResult(_ updateResult: (((inout ResultModel) -> Void) -> Void)?) { self.updateResult = updateResult } diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 5665d9f2..22f42eda 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -46,7 +46,7 @@ import SwiftUtils func setResultViewUpdateCallback(_ variableStates: VariableStates) { self.inputManager.setUpdateResult { [weak variableStates] in if let variableStates { - $0(&variableStates.resultModelVariableSection) + $0(&variableStates.resultModel) } } } @@ -190,8 +190,12 @@ import SwiftUtils case .enter: self.showResultView(variableStates: variableStates) self.shiftStateOff(variableStates: variableStates) - let actions = self.inputManager.enter(requireSetResult: requireSetResult) - self.registerActions(actions, variableStates: variableStates) + if let candidate = variableStates.resultModel.getSelectedCandidate() { + self.notifyComplete(candidate, variableStates: variableStates) + } else { + let actions = self.inputManager.enter(requireSetResult: requireSetResult) + self.registerActions(actions, variableStates: variableStates) + } case .changeCharacterType: self.showResultView(variableStates: variableStates) @@ -203,6 +207,8 @@ import SwiftUtils self.shiftStateOff(variableStates: variableStates) self.inputManager.replaceLastCharacters(table: table, requireSetResult: requireSetResult, inputStyle: variableStates.inputStyle) + case let .selectCandidate(selection): + variableStates.resultModel.setSelectionRequest(selection) case let .moveTab(type): // タブ移動ではシフトを解除しない variableStates.setTab(type) @@ -272,7 +278,7 @@ import SwiftUtils } case let .setSearchQuery(query, target): let results = self.inputManager.getSearchResult(query: query, target: target) - variableStates.resultModelVariableSection.setSearchResults(results) + variableStates.resultModel.setSearchResults(results) } if requireSetResult { @@ -281,7 +287,9 @@ import SwiftUtils let (left, center, right) = self.inputManager.getSurroundingText() variableStates.setSurroundingText(leftSide: left, center: center, rightSide: right) // エンターキーの状態 - variableStates.setEnterKeyState(self.inputManager.getEnterKeyState()) + variableStates.setEnterKeyState( + variableStates.resultModel.getSelectedCandidate() == nil ? self.inputManager.getEnterKeyState() : .complete + ) // 文字列の変更を適用 variableStates.textChangedCount = self.inputManager.getTextChangedCount() // 必要に応じて予測変換をリセット diff --git a/Keyboard/Display/KeyboardViewController.swift b/Keyboard/Display/KeyboardViewController.swift index 61ecffed..65d14552 100644 --- a/Keyboard/Display/KeyboardViewController.swift +++ b/Keyboard/Display/KeyboardViewController.swift @@ -233,7 +233,7 @@ final class KeyboardViewController: UIInputViewController { } func updateResultView(_ candidates: [any ResultViewItemData]) { - KeyboardViewController.variableStates.resultModelVariableSection.setResults(candidates) + KeyboardViewController.variableStates.resultModel.setResults(candidates) } func makeChangeKeyboardButtonView(size: CGFloat) -> ChangeKeyboardButtonView { diff --git a/MainApp/General/KeyboardPreview.swift b/MainApp/General/KeyboardPreview.swift index 8b00bef4..76aacf78 100644 --- a/MainApp/General/KeyboardPreview.swift +++ b/MainApp/General/KeyboardPreview.swift @@ -49,7 +49,7 @@ struct KeyboardPreview: View { .scaleEffect(scale) .frame(width: SemiStaticStates.shared.screenWidth * scale, height: Design.keyboardScreenHeight(upsideComponent: nil, orientation: MainAppDesign.keyboardOrientation) * scale) .onAppear { - variableStates.resultModelVariableSection.setResults([ + variableStates.resultModel.setResults([ CandidateMock(text: "azooKey"), CandidateMock(text: "あずーきー"), CandidateMock(text: "アズーキー") From 32cfb3007cbf64834f80522ec369ebb76f53e870 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 28 Sep 2023 14:39:42 +0900 Subject: [PATCH 071/124] Implement NextCandidateKeyModel for custom keys --- .../SimpleKeyView/SimpleKeyModel.swift | 54 +++++++++++++- .../SimpleKeyView/SimpleKeyView.swift | 8 +-- .../KeyView/FlickAaKeyModel.swift | 5 +- .../KeyView/FlickChangeKeyboardKeyModel.swift | 4 +- .../KeyView/FlickEnterKeyModel.swift | 2 +- .../KeyView/FlickKanaSymbolsKeyModel.swift | 2 +- .../FlickKeyboard/KeyView/FlickKeyModel.swift | 4 ++ .../KeyView/FlickKeyModelProtocol.swift | 3 +- .../FlickKeyboard/KeyView/FlickKeyView.swift | 10 +-- .../KeyView/FlickKogakiKeyModel.swift | 6 +- .../KeyView/FlickNextCandidateKeyModel.swift | 70 +++++++++++++++++++ .../KeyView/FlickSpaceKeyModel.swift | 6 +- .../KeyView/FlickTabKeyModel.swift | 2 +- .../KeyView/QwertyAaKeyModel.swift | 2 +- .../QwertyChangeKeyboardKeyModel.swift | 6 +- .../KeyView/QwertyEnterKeyModel.swift | 4 +- .../KeyView/QwertyFunctionalKeyModel.swift | 4 ++ .../KeyView/QwertyKeyModel.swift | 4 ++ .../KeyView/QwertyKeyModelProtocol.swift | 2 +- .../KeyView/QwertyKeyView.swift | 4 +- .../QwertyLanguageSwitchKeyModel.swift | 6 +- .../KeyView/QwertyNextCandidateKeyModel.swift | 67 ++++++++++++++++++ .../KeyView/QwertyShiftKeyModel.swift | 2 +- .../KeyView/QwertySpaceKeyModel.swift | 5 +- .../KeyView/QwertyTabKeyModel.swift | 6 +- .../View/SpecialTabs/EmojiTab.swift | 11 ++- 26 files changed, 261 insertions(+), 38 deletions(-) create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickNextCandidateKeyModel.swift create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift index 3c164299..1314062a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift @@ -50,9 +50,9 @@ enum SimpleUnpressedKeyColorType: UInt8 { protocol SimpleKeyModelProtocol { associatedtype Extension: ApplicationSpecificKeyboardViewExtension - var longPressActions: LongpressActionType {get} var unpressedKeyColorType: SimpleUnpressedKeyColorType {get} @MainActor func pressActions(variableStates: VariableStates) -> [ActionType] + @MainActor func longPressActions(variableStates: VariableStates) -> LongpressActionType @MainActor func feedback(variableStates: VariableStates) @MainActor func label(width: CGFloat, states: VariableStates, theme: Extension.Theme) -> KeyLabel @MainActor func backGroundColorWhenPressed(theme: Extension.Theme) -> Color @@ -89,6 +89,10 @@ struct SimpleKeyModel: Simp func pressActions(variableStates: VariableStates) -> [ActionType] { pressActions } + + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + longPressActions + } func feedback(variableStates: VariableStates) { self.pressActions.first?.feedback(variableStates: variableStates, extension: Extension.self) @@ -106,7 +110,10 @@ struct SimpleEnterKeyModel: } } - let longPressActions: LongpressActionType = .none + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + .none + } + let unpressedKeyColorType: SimpleUnpressedKeyColorType = .enter func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { let text = Design.language.getEnterKeyText(states.enterKeyState) @@ -123,6 +130,45 @@ struct SimpleEnterKeyModel: } } +struct SimpleNextCandidateKeyModel: SimpleKeyModelProtocol { + var unpressedKeyColorType: SimpleUnpressedKeyColorType = .normal + + func pressActions(variableStates: VariableStates) -> [ActionType] { + if variableStates.resultModel.results.isEmpty { + [.input(" ")] + } else { + [.selectCandidate(.offset(1))] + } + } + @MainActor func longPressActions(variableStates: VariableStates) -> LongpressActionType { + if variableStates.resultModel.results.isEmpty { + .init(start: [.setCursorBar(.toggle)]) + } else { + .init(start: [.input(" ")]) + } + } + + func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { + if states.resultModel.results.isEmpty { + KeyLabel(.text("空白"), width: width) + } else { + KeyLabel(.text("次候補"), width: width) + } + } + + func feedback(variableStates: VariableStates) { + if variableStates.resultModel.results.isEmpty { + KeyboardFeedback.click() + } else { + KeyboardFeedback.tabOrOtherKey() + } + } + func backGroundColorWhenUnpressed(states: VariableStates, theme: ThemeData) -> Color { + theme.specialKeyFillColor.color + } +} + + struct SimpleChangeKeyboardKeyModel: SimpleKeyModelProtocol { func pressActions(variableStates: VariableStates) -> [ActionType] { if SemiStaticStates.shared.needsInputModeSwitchKey { @@ -132,7 +178,9 @@ struct SimpleChangeKeyboardKeyModel LongpressActionType { + .none + } func label(width: CGFloat, states: VariableStates, theme: ThemeData) -> KeyLabel { if SemiStaticStates.shared.needsInputModeSwitchKey { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift index a0f70421..e8257b63 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyView.swift @@ -58,16 +58,16 @@ struct SimpleKeyView: View isPressed = true pressStartDate = Date() model.feedback(variableStates: variableStates) - action.reserveLongPressAction(self.model.longPressActions, variableStates: variableStates) + action.reserveLongPressAction(self.model.longPressActions(variableStates: variableStates), variableStates: variableStates) } touchMovedCallBack: { state in if state.distance > 15 { isPressed = false pressStartDate = Date() - action.registerLongPressActionEnd(self.model.longPressActions) + action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) } } touchUpCallBack: {state in isPressed = false - action.registerLongPressActionEnd(self.model.longPressActions) + action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) if Date().timeIntervalSince(pressStartDate) < 0.4 && state.distance < 30 { action.registerActions(self.model.pressActions(variableStates: variableStates), variableStates: variableStates) self.model.additionalOnPress(variableStates: variableStates) @@ -76,7 +76,7 @@ struct SimpleKeyView: View } } .onDisappear { - action.registerLongPressActionEnd(self.model.longPressActions) + action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) } ) .frame(width: keyViewWidth, height: keyViewHeight) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift index 8ded3816..95de8648 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickAaKeyModel.swift @@ -23,7 +23,10 @@ struct FlickAaKeyModel: Fli } } - let longPressActions: LongpressActionType = .none + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { + .none + } + func flickKeys(variableStates: VariableStates) -> [CustardKit.FlickDirection: FlickedKeyModel] { if variableStates.boolStates.isCapsLocked { return [:] diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift index 255af3b7..e17f1be8 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift @@ -34,7 +34,9 @@ struct FlickChangeKeyboardModel LongpressActionType { + .none + } func flickKeys(variableStates: VariableStates) -> [FlickDirection: FlickedKeyModel] { if usePasteButton { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift index 98b9a304..4f31d162 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift @@ -24,7 +24,7 @@ struct FlickEnterKeyModel: } } - var longPressActions: LongpressActionType = .none + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { .init(start: [.selectCandidate(.offset(1))]) } func flickKeys(variableStates: VariableStates) -> [FlickDirection: FlickedKeyModel] { [:] diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift index 78f6e31a..6e84de08 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKanaSymbolsKeyModel.swift @@ -21,7 +21,7 @@ struct FlickKanaSymbolsKeyModel [ActionType] { customKey.compiled().actions } - @MainActor var longPressActions: LongpressActionType { + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { customKey.compiled().longpressActions } @MainActor var labelType: KeyLabelType { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift index b5530cde..22d6b30c 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModel.swift @@ -45,6 +45,10 @@ struct FlickKeyModel: Flick self.pressActions } + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + self.longPressActions + } + func flickKeys(variableStates: VariableStates) -> [FlickDirection: FlickedKeyModel] { self.flickKeys } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift index 2249a5df..fdee67ce 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyModelProtocol.swift @@ -36,9 +36,8 @@ public protocol FlickKeyModelProtocol { @MainActor var needSuggestView: Bool {get} - @MainActor var longPressActions: LongpressActionType {get} - @MainActor func pressActions(variableStates: VariableStates) -> [ActionType] + @MainActor func longPressActions(variableStates: VariableStates) -> LongpressActionType @MainActor func backGroundColorWhenPressed(theme: ThemeData) -> Color @MainActor func backGroundColorWhenUnpressed(states: VariableStates, theme: ThemeData) -> Color diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift index 559828e3..2920f698 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift @@ -82,12 +82,12 @@ public struct FlickKeyView: self.model.feedback(variableStates: variableStates) withAnimation(suggestAnimation) { // サジェストが必要な設定なら - if self.model.needSuggestView && self.model.longPressActions == .none { + if self.model.needSuggestView && self.model.longPressActions(variableStates: variableStates) == .none { // 全てのサジェストを表示する self.setSuggestState(.all) } // 長押しの予約をする。 - self.action.reserveLongPressAction(self.model.longPressActions, variableStates: variableStates) + self.action.reserveLongPressAction(self.model.longPressActions(variableStates: variableStates), variableStates: variableStates) } // 押し始めた後の変化である場合。 case let .started(date): @@ -98,7 +98,7 @@ public struct FlickKeyView: // 一つの方向でサジェストされた状態を登録する。 pressState = .oneDirectionSuggested(d, Date()) // 長押しされなかったと判断して終了する。 - self.action.registerLongPressActionEnd(self.model.longPressActions) + self.action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) // 長フリックを予約する self.longFlickReserve(d) } @@ -142,7 +142,7 @@ public struct FlickKeyView: // 一つの方向でサジェストされた状態を登録する。 pressState = .oneDirectionSuggested(d, Date()) // 長押しは終わりと判断して終了する。 - self.action.registerLongPressActionEnd(self.model.longPressActions) + self.action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) // 長フリックを予約する self.longFlickReserve(d) } @@ -184,7 +184,7 @@ public struct FlickKeyView: } } // 有無を言わさず終わらせる - self.action.registerLongPressActionEnd(self.model.longPressActions) + self.action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) self.flickKeys().forEach {_, flickKey in self.action.registerLongPressActionEnd(flickKey.longPressActions) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift index ebb697d0..ab2324c3 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKogakiKeyModel.swift @@ -15,8 +15,6 @@ struct FlickKogakiKeyModel: static var shared: Self { FlickKogakiKeyModel() } - var longPressActions: LongpressActionType = .none - let labelType: KeyLabelType = .text("小゙゚") @MainActor private var customKey: KeyFlickSetting { @@ -33,6 +31,10 @@ struct FlickKogakiKeyModel: [.changeCharacterType] } + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { + .none + } + func label(width: CGFloat, states: VariableStates) -> KeyLabel { KeyLabel(self.labelType, width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickNextCandidateKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickNextCandidateKeyModel.swift new file mode 100644 index 00000000..44e21300 --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickNextCandidateKeyModel.swift @@ -0,0 +1,70 @@ +// +// FlickNextCandidateKeyModel.swift +// +// +// Created by miwa on 2023/09/27. +// + +import Foundation +import KeyboardThemes +import enum CustardKit.FlickDirection +import SwiftUI + +struct FlickNextCandidateKeyModel: FlickKeyModelProtocol { + let needSuggestView: Bool = false + + static var shared: Self { FlickNextCandidateKeyModel() } + + func pressActions(variableStates: VariableStates) -> [ActionType] { + if variableStates.resultModel.results.isEmpty { + [.input(" ")] + } else { + [.selectCandidate(.offset(1))] + } + } + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + if variableStates.resultModel.results.isEmpty { + .init(start: [.setCursorBar(.toggle)]) + } else { + .init(start: [.input(" ")]) + } + } + func flickKeys(variableStates: VariableStates) -> [CustardKit.FlickDirection: FlickedKeyModel] { + [ + .left: FlickedKeyModel( + labelType: .text("←"), + pressActions: [.moveCursor(-1)], + longPressActions: .init(repeat: [.moveCursor(-1)]) + ), + .top: FlickedKeyModel( + labelType: .text("全角"), + pressActions: [.input(" ")] + ), + .bottom: FlickedKeyModel( + labelType: .text("Tab"), + pressActions: [.input("\u{0009}")] + ) + ] + } + + private init() {} + + func label(width: CGFloat, states: VariableStates) -> KeyLabel { + if states.resultModel.results.isEmpty { + KeyLabel(.text("空白"), width: width) + } else { + KeyLabel(.text("次候補"), width: width) + } + } + + func feedback(variableStates: VariableStates) { + if variableStates.resultModel.results.isEmpty { + KeyboardFeedback.click() + } else { + KeyboardFeedback.tabOrOtherKey() + } + } + func backGroundColorWhenUnpressed(states: VariableStates, theme: ThemeData) -> Color { + theme.specialKeyFillColor.color + } +} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift index 02847458..4b8bd688 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickSpaceKeyModel.swift @@ -15,8 +15,6 @@ struct FlickSpaceKeyModel: static var shared: Self { FlickSpaceKeyModel() } let needSuggestView = true - let longPressActions: LongpressActionType = .init(start: [.setCursorBar(.toggle)]) - func flickKeys(variableStates: VariableStates) -> [FlickDirection: FlickedKeyModel] { flickKeys } @@ -41,6 +39,10 @@ struct FlickSpaceKeyModel: [.input(" ")] } + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { + .init(start: [.setCursorBar(.toggle)]) + } + func label(width: CGFloat, states: VariableStates) -> KeyLabel { KeyLabel(.text("空白"), width: width) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift index 668d2fa1..c356e77a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickTabKeyModel.swift @@ -22,7 +22,7 @@ struct FlickTabKeyModel: Fl func pressActions(variableStates: VariableStates) -> [ActionType] { self.data.actions } - var longPressActions: LongpressActionType { + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { self.data.longpressActions } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift index 86efda10..03ff1ab8 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyAaKeyModel.swift @@ -24,7 +24,7 @@ struct QwertyAaKeyModel: Qw } } - var longPressActions: LongpressActionType { + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { .init(start: [.setBoolState(VariableStates.BoolStates.isCapsLockedKey, .toggle)]) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift index 92139067..dddafd1d 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyChangeKeyboardKeyModel.swift @@ -52,8 +52,10 @@ struct QwertyChangeKeyboardKeyModel LongpressActionType { + .none + } + let variationsModel = VariationsModel([]) let needSuggestView: Bool = false diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift index 98fe9dbd..e2fafb48 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyEnterKeyModel.swift @@ -30,7 +30,9 @@ struct QwertyEnterKeyModel: } } - let longPressActions: LongpressActionType = .none + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { + .none + } func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { let text = Design.language.getEnterKeyText(states.enterKeyState) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift index 357c6ed9..829396b5 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift @@ -34,6 +34,10 @@ struct QwertyFunctionalKeyModel LongpressActionType { + .none + } + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { KeyLabel(self.labelType, width: width, textColor: color) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift index a7a0048f..96acb6cb 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModel.swift @@ -42,6 +42,10 @@ struct QwertyKeyModel: Qwer self.pressActions } + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { + self.longPressActions + } + func feedback(variableStates: VariableStates) { self.pressActions.first?.feedback(variableStates: variableStates, extension: Extension.self) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift index d8bda6e1..e2fa274d 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyModelProtocol.swift @@ -83,13 +83,13 @@ enum QwertyUnpressedKeyColorType: Sendable { protocol QwertyKeyModelProtocol { associatedtype Extension: ApplicationSpecificKeyboardViewExtension - var longPressActions: LongpressActionType {get} var keySizeType: QwertyKeySizeType {get} var needSuggestView: Bool {get} var variationsModel: VariationsModel {get} @MainActor func pressActions(variableStates: VariableStates) -> [ActionType] + @MainActor func longPressActions(variableStates: VariableStates) -> LongpressActionType /// 二回連続で押した際に発火するActionを指定する @MainActor func doublePressActions(variableStates: VariableStates) -> [ActionType] @MainActor func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index ae6400f0..2aa020a2 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -128,7 +128,7 @@ struct QwertyKeyView: View self.model.feedback(variableStates: variableStates) self.pressState = .started(Date()) self.doublePressState.update(touchDownDate: Date()) - self.action.reserveLongPressAction(self.model.longPressActions, variableStates: variableStates) + self.action.reserveLongPressAction(self.model.longPressActions(variableStates: variableStates), variableStates: variableStates) self.longPressStartTask = Task { do { // 0.4秒待つ @@ -161,7 +161,7 @@ struct QwertyKeyView: View // 更新する let endDate = Date() self.doublePressState.update(touchUpDate: endDate) - self.action.registerLongPressActionEnd(self.model.longPressActions) + self.action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) self.suggest = false self.longPressStartTask?.cancel() self.longPressStartTask = nil diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift index 41550099..1d9e45c4 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyLanguageSwitchKeyModel.swift @@ -39,8 +39,10 @@ struct QwertySwitchLanguageKeyModel LongpressActionType { + .none + } + let variationsModel = VariationsModel([]) let needSuggestView: Bool = false diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift new file mode 100644 index 00000000..606a394e --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift @@ -0,0 +1,67 @@ +// +// QwertyNextCandidateKeyModel.swift +// azooKey +// +// Created by ensan on 2021/02/07. +// Copyright © 2021 ensan. All rights reserved. +// + +import CustardKit +import Foundation +import KeyboardThemes +import SwiftUI + +struct QwertyNextCandidateKeyModel: QwertyKeyModelProtocol { + let keySizeType: QwertyKeySizeType = .space + + let needSuggestView: Bool = false + + let variationsModel: VariationsModel = .init([]) + + let unpressedKeyColorType: QwertyUnpressedKeyColorType = .normal + + static var shared: Self { QwertyNextCandidateKeyModel() } + + func pressActions(variableStates: VariableStates) -> [ActionType] { + if variableStates.resultModel.results.isEmpty { + [.input(" ")] + } else { + [.selectCandidate(.offset(1))] + } + } + + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + if variableStates.resultModel.results.isEmpty { + .init(start: [.setCursorBar(.toggle)]) + } else { + .init(start: [.input(" ")]) + } + } + + func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { + if states.resultModel.results.isEmpty { + switch states.keyboardLanguage { + case .el_GR: + KeyLabel(.text("διάστημα"), width: width, textSize: .small, textColor: color) + case .en_US: + KeyLabel(.text("space"), width: width, textSize: .small, textColor: color) + case .ja_JP, .none: + KeyLabel(.text("空白"), width: width, textSize: .small, textColor: color) + } + } else { + KeyLabel(.text("次候補"), width: width, textSize: .small, textColor: color) + } + } + + func backGroundColorWhenUnpressed(states: VariableStates, theme: ThemeData) -> Color { + theme.specialKeyFillColor.color + } + + func feedback(variableStates: VariableStates) { + if variableStates.resultModel.results.isEmpty { + KeyboardFeedback.click() + } else { + KeyboardFeedback.tabOrOtherKey() + } + } +} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift index 751c657c..d8751a7e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyShiftKeyModel.swift @@ -25,7 +25,7 @@ struct QwertyShiftKeyModel: } } - var longPressActions: LongpressActionType { + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { .init(start: [.setBoolState(VariableStates.BoolStates.isCapsLockedKey, .toggle)]) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift index 8c97f4f7..16c20490 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertySpaceKeyModel.swift @@ -10,7 +10,6 @@ import Foundation import SwiftUI struct QwertySpaceKeyModel: QwertyKeyModelProtocol { - var longPressActions: LongpressActionType = .init(start: [.setCursorBar(.toggle)]) let needSuggestView: Bool = false let variationsModel = VariationsModel([]) @@ -34,6 +33,10 @@ struct QwertySpaceKeyModel: [.input(" ")] } + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { + .init(start: [.setCursorBar(.toggle)]) + } + func feedback(variableStates: VariableStates) { KeyboardFeedback.click() } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift index 969114b9..4cffc7f7 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyTabKeyModel.swift @@ -26,8 +26,10 @@ struct QwertyTabKeyModel: Q } } - let longPressActions: LongpressActionType = .none - /// 暫定 + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { + .none + } + let variationsModel = VariationsModel([]) let needSuggestView: Bool = false diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift index feb05958..0ddc8dd8 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift @@ -377,11 +377,13 @@ private struct ExpandKeyModel [ActionType] { [] } + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + .none + } func feedback(variableStates: VariableStates) { KeyboardFeedback.tabOrOtherKey() } @@ -403,11 +405,13 @@ private struct GenreKeyModel [ActionType] { [] } + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + .none + } func feedback(variableStates: VariableStates) { KeyboardFeedback.tabOrOtherKey() } @@ -443,6 +447,9 @@ private struct EmojiKeyModel [ActionType] { [.input(emoji)] } + func longPressActions(variableStates: VariableStates) -> LongpressActionType { + .none + } func feedback(variableStates: VariableStates) { KeyboardFeedback.click() } From 0c1662a4a6aec2a9eafccac5a2b8bf4f62ff41f7 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 28 Sep 2023 15:27:41 +0900 Subject: [PATCH 072/124] Support V1.4 CustardKit --- .../Sources/KeyboardViews/Action.swift | 8 +-- .../Sources/KeyboardViews/ActionUtils.swift | 2 + .../View/CustomKeybaord/CustomKeyboard.swift | 6 +++ .../View/KeyboardBar/ResultViewItemData.swift | 3 +- .../QwertyKeyboard/QwertyDataProvider.swift | 8 +-- .../Customize/CodableActionDataEditor.swift | 11 +++- .../Customize/CustardInterfaceKeyEditor.swift | 1 + Resources/Localizable.xcstrings | 50 +++++++++++++++++++ azooKey.xcodeproj/project.pbxproj | 5 +- 9 files changed, 77 insertions(+), 17 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/Action.swift b/AzooKeyCore/Sources/KeyboardViews/Action.swift index f56e2cdb..56226a4b 100644 --- a/AzooKeyCore/Sources/KeyboardViews/Action.swift +++ b/AzooKeyCore/Sources/KeyboardViews/Action.swift @@ -59,13 +59,7 @@ public indirect enum ActionType: Equatable, Sendable { case boolSwitch(CompiledExpression, trueAction: [ActionType], falseAction: [ActionType]) // 選択アクション - case selectCandidate(CandidateSelectionRequest) -} -public enum CandidateSelectionRequest: Equatable, Sendable { - case first - case last - case exact(Int) - case offset(Int) + case selectCandidate(CandidateSelection) } public struct LongpressActionType: Equatable, Sendable { diff --git a/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift b/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift index 7a8a8146..fc841dd3 100644 --- a/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift +++ b/AzooKeyCore/Sources/KeyboardViews/ActionUtils.swift @@ -25,6 +25,8 @@ extension CodableActionData { return .smoothDelete case let .smartDelete(value): return .smartDelete(value) + case .selectCandidate(let selection): + return .selectCandidate(selection) case .complete: return .enter case let .moveCursor(value): diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index 859f7888..3be6497f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -136,6 +136,8 @@ extension CustardInterfaceKey { return FlickEnterKeyModel() case .upperLower: return FlickAaKeyModel() + case .nextCandidate: + return FlickNextCandidateKeyModel.shared case .flickKogaki: return FlickKogakiKeyModel.shared case .flickKutoten: @@ -193,6 +195,8 @@ extension CustardInterfaceKey { return QwertyEnterKeyModel(keySizeType: .enter) case .upperLower: return QwertyAaKeyModel() + case .nextCandidate: + return QwertyNextCandidateKeyModel() case .flickKogaki: return convertToQwertyKeyModel(customKey: Extension.SettingProvider.koganaFlickCustomKey.compiled(), extension: Extension.self) case .flickKutoten: @@ -237,6 +241,8 @@ extension CustardInterfaceKey { return SimpleEnterKeyModel() case .upperLower: return SimpleKeyModel(keyLabelType: .text("a/A"), unpressedKeyColorType: .special, pressActions: [.changeCharacterType]) + case .nextCandidate: + return SimpleNextCandidateKeyModel() case .flickKogaki: return SimpleKeyModel(keyLabelType: .text("小゙゚"), unpressedKeyColorType: .special, pressActions: [.changeCharacterType]) case .flickKutoten: diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift index 9bfa7086..e129593c 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultViewItemData.swift @@ -6,6 +6,7 @@ // Copyright © 2023 ensan. All rights reserved. // +import enum CustardKit.CandidateSelection import Foundation public protocol ResultViewItemData { @@ -66,7 +67,7 @@ public struct ResultModel { self.selection = nil self.updateResult.toggle() } - public mutating func setSelectionRequest(_ request: CandidateSelectionRequest?) { + public mutating func setSelectionRequest(_ request: CandidateSelection?) { self.selection = switch request { case .none: nil diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift index 759d1028..6106d9d7 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyDataProvider.swift @@ -240,7 +240,7 @@ struct QwertyDataProvider { [ Self.tabKeys(rowInfo: (0, 2, 1, 1)).languageKey, Self.tabKeys(rowInfo: (0, 2, 1, 1)).changeKeyboardKey, - QwertySpaceKeyModel(), + QwertyNextCandidateKeyModel(), QwertyEnterKeyModel.shared ] ] @@ -462,7 +462,7 @@ struct QwertyDataProvider { [ Self.tabKeys(rowInfo: (0, 2, 1, 1)).languageKey, Self.tabKeys(rowInfo: (0, 2, 1, 1)).changeKeyboardKey, - QwertySpaceKeyModel(), + QwertyNextCandidateKeyModel(), QwertyEnterKeyModel.shared ] ]} @@ -507,7 +507,7 @@ struct QwertyDataProvider { [ Self.tabKeys(rowInfo: (0, 2, 1, 1)).numbersKey, Self.tabKeys(rowInfo: (0, 2, 1, 1)).changeKeyboardKey, - QwertySpaceKeyModel(), + QwertyNextCandidateKeyModel(), QwertyEnterKeyModel.shared ] ]} @@ -564,7 +564,7 @@ struct QwertyDataProvider { [ Self.tabKeys(rowInfo: (0, 2, 1, 1)).numbersKey, Self.tabKeys(rowInfo: (0, 2, 1, 1)).changeKeyboardKey, - QwertySpaceKeyModel(), + QwertyNextCandidateKeyModel(), QwertyEnterKeyModel.shared ] ]} diff --git a/MainApp/Customize/CodableActionDataEditor.swift b/MainApp/Customize/CodableActionDataEditor.swift index 053ec612..637f405d 100644 --- a/MainApp/Customize/CodableActionDataEditor.swift +++ b/MainApp/Customize/CodableActionDataEditor.swift @@ -16,8 +16,8 @@ import SwiftUIUtils extension CodableActionData { var hasAssociatedValue: Bool { switch self { - case .delete, .smartDelete, .input, .replaceLastCharacters, .moveCursor, .smartMoveCursor, .moveTab, .launchApplication: return true - case .enableResizingMode, .complete, .replaceDefault, .smartDeleteDefault, .toggleCapsLockState, .toggleCursorBar, .toggleTabBar, .dismissKeyboard, .paste: return false + case .delete, .smartDelete, .input, .replaceLastCharacters, .moveCursor, .smartMoveCursor, .moveTab, .launchApplication, .selectCandidate: true + case .enableResizingMode, .complete, .replaceDefault, .smartDeleteDefault, .toggleCapsLockState, .toggleCursorBar, .toggleTabBar, .dismissKeyboard, .paste: false } } @@ -31,6 +31,13 @@ extension CodableActionData { case .paste: return "ペーストする" case .moveTab: return "タブの移動" case .replaceLastCharacters: return "文字を置換" + case let .selectCandidate(selection): + return switch selection { + case .first: "最初の候補を選択" + case .last: "最後の候補を選択" + case .offset(let value): "\(value)個隣の候補を選択" + case .exact(let value): "\(value)番目の候補を選択" + } case .complete: return "確定" case .replaceDefault: return "大文字/小文字、拗音/濁音/半濁音の切り替え" case .smartDeleteDefault: return "文頭まで削除" diff --git a/MainApp/Customize/CustardInterfaceKeyEditor.swift b/MainApp/Customize/CustardInterfaceKeyEditor.swift index 595f00f5..d82d4db2 100644 --- a/MainApp/Customize/CustardInterfaceKeyEditor.swift +++ b/MainApp/Customize/CustardInterfaceKeyEditor.swift @@ -429,6 +429,7 @@ struct CustardInterfaceKeyEditor: View { Text("改行キー").tag(CustardInterfaceKey.system(.enter)) Text("削除キー").tag(CustardInterfaceKey.custom(.flickDelete())) Text("空白キー").tag(CustardInterfaceKey.custom(.flickSpace())) + Text("次候補キー").tag(CustardInterfaceKey.system(.nextCandidate)) Text("地球儀キー").tag(CustardInterfaceKey.system(.changeKeyboard)) Text("小書き・濁点化キー").tag(CustardInterfaceKey.system(.flickKogaki)) Text("大文字・小文字キー").tag(CustardInterfaceKey.system(.upperLower)) diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 2f55220b..149bc27c 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -810,6 +810,26 @@ } } }, + "%lld個隣の候補を選択" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select candidates %lld positions away" + } + } + } + }, + "%lld番目の候補を選択" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select %lldth candidate" + } + } + } + }, "%を新規作成" : { "extractionState" : "manual", "localizations" : { @@ -5687,6 +5707,16 @@ } } }, + "最初の候補を選択" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select first candidate" + } + } + } + }, "最初の設定" : { "localizations" : { "en" : { @@ -5735,6 +5765,16 @@ } } }, + "最後の候補を選択" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select last candidate" + } + } + } + }, "分" : { "localizations" : { "en" : { @@ -7835,6 +7875,16 @@ } } }, + "次候補キー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Next candidate key" + } + } + } + }, "正しくない形式のファイルです" : { "localizations" : { "en" : { diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index 20109889..c0a1e71b 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -1941,9 +1941,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ensan-hcl/CustardKit"; requirement = { - kind = versionRange; - maximumVersion = 1.4.0; - minimumVersion = 1.3.0; + kind = upToNextMinorVersion; + minimumVersion = 1.4.0; }; }; 1A9E908A2822CEB400E73846 /* XCRemoteSwiftPackageReference "swift-collections" */ = { From 21c7bb482fe6e7e12c316f2b8c70c4fff30283c8 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 28 Sep 2023 15:49:13 +0900 Subject: [PATCH 073/124] fix a bug which enter called twice --- Keyboard/Display/KeyboardActionManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 22f42eda..cfca34c9 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -361,7 +361,7 @@ import SwiftUtils override func registerActions(_ actions: [ActionType], variableStates: VariableStates) { var actions = actions[...] while let firstIndex = actions.firstIndex(where: { actionTriggerStyle($0) == .separator }) { - self.runActionBlock(actionBlock: actions[...firstIndex], variableStates: variableStates) + self.runActionBlock(actionBlock: actions[.. Date: Thu, 28 Sep 2023 16:24:52 +0900 Subject: [PATCH 074/124] apply zIndex to make tab bar button front --- .../Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index b44cd162..3f6dfc5b 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -48,6 +48,7 @@ struct ResultBar: View { KeyboardBarButton { self.action.registerAction(.setTabBar(.toggle), variableStates: variableStates) } + .zIndex(10) .matchedGeometryEffect(id: "KeyboardBarButton", in: namespace) } @@ -129,6 +130,7 @@ struct ResultBar: View { } .padding(.horizontal, 5) } + .zIndex(0) if variableStates.resultModel.displayState == .results { // 候補を展開するボタン Button(action: {self.expand()}) { From 27de7b38af5c58f5b30e950ab6f02155af521ff4 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 28 Sep 2023 19:53:36 +0900 Subject: [PATCH 075/124] fix dependency version --- AzooKeyCore/Package.swift | 7 +++++-- azooKey.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/AzooKeyCore/Package.swift b/AzooKeyCore/Package.swift index 870f6fec..82e1ea65 100644 --- a/AzooKeyCore/Package.swift +++ b/AzooKeyCore/Package.swift @@ -38,8 +38,11 @@ let package = Package( ], dependencies: [ // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - .package(url: "https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter", branch: "develop") + // MARK: You must specify version which results reproductive and stable result + // MARK: `_: .upToNextMinor(Version)` or `exact: Version` or `revision: Version`. + // MARK: For develop branch, you can use `revision:` specification. + // MARK: For main branch, you must use `upToNextMinor` specification. + .package(url: "https://github.com/ensan-hcl/AzooKeyKanaKanjiConverter", .upToNextMinor(from: "0.4.0")) ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/azooKey.xcodeproj/project.pbxproj b/azooKey.xcodeproj/project.pbxproj index c0a1e71b..1444fb74 100644 --- a/azooKey.xcodeproj/project.pbxproj +++ b/azooKey.xcodeproj/project.pbxproj @@ -1933,8 +1933,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ensan-hcl/BoolExpressionEvaluator"; requirement = { - branch = main; - kind = branch; + kind = exactVersion; + version = 0.0.1; }; }; 1A70DFFB291F2D1E00A83849 /* XCRemoteSwiftPackageReference "CustardKit" */ = { From 2eef4bcc6e367ef4293736f66ed845eabcafab39 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 30 Sep 2023 09:42:44 +0900 Subject: [PATCH 076/124] Update info --- MainApp/UpdateInformationView.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MainApp/UpdateInformationView.swift b/MainApp/UpdateInformationView.swift index ad460c12..d2437a2a 100644 --- a/MainApp/UpdateInformationView.swift +++ b/MainApp/UpdateInformationView.swift @@ -22,13 +22,18 @@ struct UpdateInformationView: View { "バージョン2.3以降でiOS15のサポートを終了します。iOS16以上で引き続きご利用いただけます。ご不便をおかけしますが、よろしくお願いいたします" } } - ParagraphView("予測変換を大幅に強化しました。") - ParagraphView("再変換を大幅に強化しました。") + ParagraphView("予測変換を大幅に強化しました。") { + "確定したあとに続けて打つ文字を予測するようになりました" + "より妥当な候補が表示されるようになりました" + } ParagraphView("機能を改善しました。") { + "再変換を大幅に強化しました。" "「連絡先」に登録されている氏名を読み込んで変換に利用できるようになりました" "テキストを選択した際に表示していた「編集」機能を廃止しました" "カーソルを動かした際、カーソルバーを表示するようにしました" + "カスタムキーで「次候補」と「A/a」の特殊キーを選べるようになりました" } + ParagraphView("複数の不具合を修正しました。") ParagraphView("その他辞書の改善を行いました。") } } From 7bcc89509dd6d956617cb13be0fbc8636677e0a6 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 30 Sep 2023 09:55:28 +0900 Subject: [PATCH 077/124] Rename files and Views --- .../AzooKeyKeyboardViewExtension.swift | 4 +- .../KeyboardSetting/BoolKeyboardSetting.swift | 11 +- ...nSpecificKeyboardViewSettingProvider.swift | 2 +- .../KeyboardViews/VariableStates.swift | 2 +- .../View/KeyboardBar/KeyboardBarView.swift | 9 +- ...rBar.swift => ReflectStyleCursorBar.swift} | 104 +----------------- .../KeyboardBar/SliderStyleCursorBar.swift | 99 +++++++++++++++++ MainApp/Setting/SettingTab.swift | 2 +- 8 files changed, 123 insertions(+), 110 deletions(-) rename AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/{MoveCursorBar.swift => ReflectStyleCursorBar.swift} (74%) create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift diff --git a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift index 7be8b828..db80f08b 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift @@ -90,8 +90,8 @@ public enum AzooKeyKeyboardViewExtension: ApplicationSpecificKeyboardViewExtensi HideResetButtonInOneHandedMode.value } - public static var useBetaMoveCursorBar: Bool { - UseBetaMoveCursorBar.value + public static var useSliderStyleCursorBar: Bool { + UseSliderStyleCursorBar.value } public static var useShiftKey: Bool { diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift index 5e2dc970..e9238240 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift @@ -167,15 +167,16 @@ public extension KeyboardSettingKey where Self == DisplayTabBarButton { static var displayTabBarButton: Self { .init() } } -public struct UseBetaMoveCursorBar: BoolKeyboardSettingKey { - public static let title: LocalizedStringKey = "新しいカーソルバーを使う (試験版)" - public static let explanation: LocalizedStringKey = "新しいカーソルバーを有効化します。\n試験的機能のため、予告なく提供を終了する可能性があります。" +public struct UseSliderStyleCursorBar: BoolKeyboardSettingKey { + public static let title: LocalizedStringKey = "新しいカーソルバーを使う" + public static let explanation: LocalizedStringKey = "操作性が向上した新しいカーソルバーを有効化します。" public static let defaultValue = false + // MARK: This setting is originally introduced as 'beta cursor bar' public static let key: String = "use_move_cursor_bar_beta" } -public extension KeyboardSettingKey where Self == UseBetaMoveCursorBar { - static var useBetaMoveCursorBar: Self { .init() } +public extension KeyboardSettingKey where Self == UseSliderStyleCursorBar { + static var useSliderStyleCursorBar: Self { .init() } } public struct HideResetButtonInOneHandedMode: BoolKeyboardSettingKey { diff --git a/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift b/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift index 615f07dd..5c4aaf0b 100644 --- a/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift +++ b/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift @@ -30,7 +30,7 @@ import Foundation static var enablePasteButton: Bool { get } static var displayTabBarButton: Bool { get } static var hideResetButtonInOneHandedMode: Bool { get } - static var useBetaMoveCursorBar: Bool { get } + static var useSliderStyleCursorBar: Bool { get } static var useShiftKey: Bool { get } static var canResetLearningForCandidate: Bool { get } diff --git a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift index 042efc2a..03a6806a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift +++ b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift @@ -162,7 +162,7 @@ public final class VariableStates: ObservableObject { @Published public var undoAction: UndoAction? - @Published var moveCursorBarState = BetaMoveCursorBarState() + @Published var moveCursorBarState = SliderStyleCursorBarState() @Published private(set) var leftSideText: String = "" @Published private(set) var centerText: String = "" diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift index 788f3d8d..eb6274cb 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift @@ -15,6 +15,9 @@ struct KeyboardBarView: Vie @EnvironmentObject private var variableStates: VariableStates @Binding private var isResultViewExpanded: Bool @Environment(Extension.Theme.self) private var theme + private var useReflectStyleCursorBar: Bool { + Extension.SettingProvider.useSliderStyleCursorBar + } init(isResultViewExpanded: Binding) { self._isResultViewExpanded = isResultViewExpanded @@ -23,7 +26,11 @@ struct KeyboardBarView: Vie var body: some View { switch variableStates.barState { case .cursor: - MoveCursorBar() + if useReflectStyleCursorBar { + ReflectStyleCursorBar() + } else { + SliderStyleCursorBar() + } case .tab: let tabBarData = (try? variableStates.tabManager.config.custardManager.tabbar(identifier: 0)) ?? .default TabBarView(data: tabBarData) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift similarity index 74% rename from AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift rename to AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift index 8ea44e5d..52aa5e74 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/MoveCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift @@ -1,9 +1,8 @@ // -// CursorMoveView.swift -// Keyboard +// ReflectStyleCursorBar.swift // -// Created by ensan on 2020/09/21. -// Copyright © 2020 ensan. All rights reserved. +// +// Created by miwa on 2023/09/30. // import Foundation @@ -11,7 +10,7 @@ import SwiftUI import SwiftUIUtils import SwiftUtils -struct BetaMoveCursorBarState { +struct SliderStyleCursorBarState { private(set) var displayLeftIndex = 0 private(set) var displayRightIndex = 0 fileprivate var line: [String] = [] @@ -69,7 +68,7 @@ struct BetaMoveCursorBarState { } @MainActor -struct MoveCursorBarBeta: View { +struct ReflectStyleCursorBar: View { init() {} @EnvironmentObject private var variableStates: VariableStates @@ -279,96 +278,3 @@ struct MoveCursorBarBeta: V } } -private enum MoveCursorBarGestureState { - case inactive - case moving(CGPoint, Int) // 右だったら+1、左だったら-1 -} - -@MainActor -struct MoveCursorBar: View { - init() {} - - @EnvironmentObject private var variableStates: VariableStates - @State private var gestureState: MoveCursorBarGestureState = .inactive - @Environment(Extension.Theme.self) private var theme - @Environment(\.userActionManager) private var action - - private var gesture: some Gesture { - DragGesture(minimumDistance: 0) - .onChanged {value in - switch self.gestureState { - case .inactive: - self.gestureState = .moving(value.location, 0) - case let .moving(previous, count): - let dx = (value.location.x - previous.x) - if dx.isZero { - break - } - let newCount = count + Int(dx / abs(dx)) - if newCount > 1 { - self.gestureState = .moving(value.location, 0) - self.action.registerAction(.moveCursor(1), variableStates: variableStates) - } else if newCount < -1 { - self.gestureState = .moving(value.location, 0) - self.action.registerAction(.moveCursor(-1), variableStates: variableStates) - } else { - self.gestureState = .moving(value.location, newCount) - } - } - } - .onEnded {_ in - self.gestureState = .inactive - } - } - - private var centerColor: Color { - theme.pushedKeyFillColor.color - } - - private var edgeColor: Color { - theme.backgroundColor.color - } - - private var symbolsFontWeight: Font.Weight { - theme.textFont.weight - } - - private var symbolsColor: Color { - theme.resultTextColor.color - } - - private var useBeta: Bool { - Extension.SettingProvider.useBetaMoveCursorBar - } - - var body: some View { - if useBeta { - MoveCursorBarBeta() - } else { - Group { - RadialGradient(gradient: Gradient(colors: [centerColor, edgeColor]), center: .center, startRadius: 1, endRadius: 200) - .cornerRadius(20) - .gesture(gesture) - .overlay(HStack { - Spacer() - Button(action: { - self.action.registerAction(.moveCursor(-1), variableStates: variableStates) - }, label: { - Image(systemName: "chevron.left.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) - .padding() - }) - Spacer() - Image(systemName: "circle.fill").font(.system(size: 22, weight: symbolsFontWeight, design: .default)) - Spacer() - Button(action: { - self.action.registerAction(.moveCursor(1), variableStates: variableStates) - }, label: { - Image(systemName: "chevron.right.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) - .padding() - }) - Spacer() - }.foregroundStyle(symbolsColor)) - } - } - } -} diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift new file mode 100644 index 00000000..c5531e36 --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift @@ -0,0 +1,99 @@ +// +// SliderStyleCursorBar.swift +// Keyboard +// +// Created by ensan on 2020/09/21. +// Copyright © 2020 ensan. All rights reserved. +// + +import Foundation +import SwiftUI +import SwiftUIUtils +import SwiftUtils + +@MainActor +struct SliderStyleCursorBar: View { + private enum MoveCursorBarGestureState { + case inactive + case moving(CGPoint, Int) // 右だったら+1、左だったら-1 + } + + init() {} + + @EnvironmentObject private var variableStates: VariableStates + @State private var gestureState: MoveCursorBarGestureState = .inactive + @Environment(Extension.Theme.self) private var theme + @Environment(\.userActionManager) private var action + + private var gesture: some Gesture { + DragGesture(minimumDistance: 0) + .onChanged {value in + switch self.gestureState { + case .inactive: + self.gestureState = .moving(value.location, 0) + case let .moving(previous, count): + let dx = (value.location.x - previous.x) + if dx.isZero { + break + } + let newCount = count + Int(dx / abs(dx)) + if newCount > 1 { + self.gestureState = .moving(value.location, 0) + self.action.registerAction(.moveCursor(1), variableStates: variableStates) + } else if newCount < -1 { + self.gestureState = .moving(value.location, 0) + self.action.registerAction(.moveCursor(-1), variableStates: variableStates) + } else { + self.gestureState = .moving(value.location, newCount) + } + } + } + .onEnded {_ in + self.gestureState = .inactive + } + } + + private var centerColor: Color { + theme.pushedKeyFillColor.color + } + + private var edgeColor: Color { + theme.backgroundColor.color + } + + private var symbolsFontWeight: Font.Weight { + theme.textFont.weight + } + + private var symbolsColor: Color { + theme.resultTextColor.color + } + + var body: some View { + RadialGradient(gradient: Gradient(colors: [centerColor, edgeColor]), center: .center, startRadius: 1, endRadius: 200) + .cornerRadius(20) + .gesture(gesture) + .overlay( + HStack { + Spacer() + Button { + self.action.registerAction(.moveCursor(-1), variableStates: variableStates) + } label: { + Image(systemName: "chevron.left.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) + .padding() + } + Spacer() + Image(systemName: "circle.fill").font(.system(size: 22, weight: symbolsFontWeight, design: .default)) + Spacer() + Button { + self.action.registerAction(.moveCursor(1), variableStates: variableStates) + } label: { + Image(systemName: "chevron.right.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) + .padding() + } + Spacer() + } + .foregroundStyle(symbolsColor) + ) + } +} diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index 04f802f8..6318cd1c 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -52,7 +52,7 @@ struct SettingTabView: View { NavigationLink("タブバーを編集", destination: EditingTabBarView(manager: $appStates.custardManager)) } Section(header: Text("カーソルバー")) { - BoolSettingView(.useBetaMoveCursorBar) + BoolSettingView(.useSliderStyleCursorBar) FallbackLink("フィードバックを募集します", destination: "https://forms.gle/vZ8Ftuu9BJBEi98h7", icon: .link) } // デバイスが触覚フィードバックをサポートしている場合のみ表示する From 90446a7df261827e7116dac925940d9f835e0a17 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 30 Sep 2023 10:00:50 +0900 Subject: [PATCH 078/124] Fix localization --- Resources/Localizable.xcstrings | 72 +++++++++------------------------ 1 file changed, 19 insertions(+), 53 deletions(-) diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 149bc27c..271e733e 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -4848,40 +4848,6 @@ } } }, - "より強力な学習を有効化 (試験版)" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Enable more strong learning (experimental)" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "" - } - } - } - }, - "より長い期間学習が保持されます。\n試験的機能のため、予告なく提供を終了する可能性があります。" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Histories can be remembered much longer. \nSince this is an experimental feature, this feature may be discontinued without notice." - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "" - } - } - } - }, "ライトモードで使用" : { "localizations" : { "en" : { @@ -6931,6 +6897,23 @@ } } }, + "操作性が向上した新しいカーソルバーを有効化します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enable new cursor bar which has been greatly improved usability." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, "改行キー" : { "localizations" : { "en" : { @@ -7187,30 +7170,13 @@ } } }, - "新しいカーソルバーを使う (試験版)" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Use new cursor bar (experimental)" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "" - } - } - } - }, - "新しいカーソルバーを有効化します。\n試験的機能のため、予告なく提供を終了する可能性があります。" : { + "新しいカーソルバーを使う" : { "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Enable new cursor bar. \nSince this is an experimental feature, this feature may be discontinued without notice." + "value" : "Use new cursor bar" } }, "ja" : { From f199485d1894b7cc7224af12b316e059d777d50c Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 30 Sep 2023 10:19:49 +0900 Subject: [PATCH 079/124] Improve operation fluency --- .../KeyboardBar/SliderStyleCursorBar.swift | 104 ++++++++++++------ 1 file changed, 70 insertions(+), 34 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift index c5531e36..f954086a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift @@ -13,43 +13,71 @@ import SwiftUtils @MainActor struct SliderStyleCursorBar: View { - private enum MoveCursorBarGestureState { + enum SwipeGestureState { case inactive - case moving(CGPoint, Int) // 右だったら+1、左だったら-1 + case start(l1: CGPoint, l2: CGPoint, l3: CGPoint) + case moving(l1: CGPoint, l2: CGPoint, l3: CGPoint, count: Double) } init() {} @EnvironmentObject private var variableStates: VariableStates - @State private var gestureState: MoveCursorBarGestureState = .inactive + @State private var swipeGestureState: SwipeGestureState = .inactive @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action - private var gesture: some Gesture { - DragGesture(minimumDistance: 0) + var swipeGesture: some Gesture { + DragGesture(minimumDistance: 0, coordinateSpace: .global) .onChanged {value in - switch self.gestureState { + switch swipeGestureState { case .inactive: - self.gestureState = .moving(value.location, 0) - case let .moving(previous, count): - let dx = (value.location.x - previous.x) - if dx.isZero { - break + swipeGestureState = .start(l1: value.location, l2: value.location, l3: value.location) + case let .start(l1, l2, _): + let d = value.startLocation.distance(to: value.location) + if d > 20 { + swipeGestureState = .moving(l1: value.location, l2: l1, l3: l2, count: 0) + } else { + swipeGestureState = .start(l1: value.location, l2: l1, l3: l2) + } + case let .moving(l1, l2, l3, count): + var direction = 0 + var count = count + // directionを多数決で決定する + if value.location.x - l1.x > 0 { + direction -= 1 + } else { + direction += 1 } - let newCount = count + Int(dx / abs(dx)) - if newCount > 1 { - self.gestureState = .moving(value.location, 0) - self.action.registerAction(.moveCursor(1), variableStates: variableStates) - } else if newCount < -1 { - self.gestureState = .moving(value.location, 0) - self.action.registerAction(.moveCursor(-1), variableStates: variableStates) + if l1.x - l2.x > 0 { + direction -= 1 } else { - self.gestureState = .moving(value.location, newCount) + direction += 1 + } + if l2.x - l3.x > 0 { + direction -= 1 + } else { + direction += 1 + } + // countの更新 + if direction > 0 && value.location.x < l3.x { + count += (Double(direction) / 3) * (l3.x - value.location.x) / 3 + } else if direction < 0 && value.location.x > l3.x { + count -= (Double(direction) / 3) * (l3.x - value.location.x) / 3 + } + let threshlod: Double = 12 + if count >= threshlod { + action.registerAction(.moveCursor(-1), variableStates: variableStates) + count -= threshlod } + if count <= -threshlod { + action.registerAction(.moveCursor(1), variableStates: variableStates) + count += threshlod + } + swipeGestureState = .moving(l1: value.location, l2: l1, l3: l2, count: count) } } - .onEnded {_ in - self.gestureState = .inactive + .onEnded {value in + swipeGestureState = .inactive } } @@ -69,28 +97,36 @@ struct SliderStyleCursorBar theme.resultTextColor.color } + @ViewBuilder private var moveLeftButton: some View { + Button { + self.action.registerAction(.moveCursor(-1), variableStates: variableStates) + } label: { + Image(systemName: "chevron.left.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) + .padding() + } + } + + @ViewBuilder private var moveRightButton: some View { + Button { + self.action.registerAction(.moveCursor(1), variableStates: variableStates) + } label: { + Image(systemName: "chevron.right.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) + .padding() + } + } + var body: some View { RadialGradient(gradient: Gradient(colors: [centerColor, edgeColor]), center: .center, startRadius: 1, endRadius: 200) .cornerRadius(20) - .gesture(gesture) + .gesture(swipeGesture) .overlay( HStack { Spacer() - Button { - self.action.registerAction(.moveCursor(-1), variableStates: variableStates) - } label: { - Image(systemName: "chevron.left.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) - .padding() - } + moveLeftButton Spacer() Image(systemName: "circle.fill").font(.system(size: 22, weight: symbolsFontWeight, design: .default)) Spacer() - Button { - self.action.registerAction(.moveCursor(1), variableStates: variableStates) - } label: { - Image(systemName: "chevron.right.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) - .padding() - } + moveRightButton Spacer() } .foregroundStyle(symbolsColor) From 5bc44b47ff2321ad8c986cacde741bddde90afda Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 30 Sep 2023 10:49:34 +0900 Subject: [PATCH 080/124] Improve design of slider style cursor bar --- .../KeyboardBar/SliderStyleCursorBar.swift | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift index f954086a..5ac12acf 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/SliderStyleCursorBar.swift @@ -97,12 +97,30 @@ struct SliderStyleCursorBar theme.resultTextColor.color } + private var buttonColors: [Color] { + [symbolsColor.opacity(0.8), symbolsColor.opacity(0.8), symbolsColor.opacity(0.4)] + } + private var symbolsFont: Font { + .system(size: 22, weight: symbolsFontWeight, design: .default) + } + @ViewBuilder private var moveLeftButton: some View { Button { self.action.registerAction(.moveCursor(-1), variableStates: variableStates) } label: { - Image(systemName: "chevron.left.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) + let interval: Double = 0.4 + TimelineView(.periodic(from: Date(), by: interval)) { timeline in + let target = Int(timeline.date.timeIntervalSince1970 / interval) + HStack(spacing: 0) { + ForEach(0..<3, id: \.self) { i in + Image(systemName: "chevron.compact.left") + .font(symbolsFont) + .foregroundStyle(buttonColors[(target + i) % 3]) + } + } + .compositingGroup() .padding() + } } } @@ -110,8 +128,19 @@ struct SliderStyleCursorBar Button { self.action.registerAction(.moveCursor(1), variableStates: variableStates) } label: { - Image(systemName: "chevron.right.2").font(.system(size: 18, weight: symbolsFontWeight, design: .default)) + let interval: Double = 0.4 + TimelineView(.periodic(from: Date(), by: interval)) { timeline in + let target = Int(timeline.date.timeIntervalSince1970 / interval) + HStack(spacing: 0) { + ForEach(0..<3, id: \.self) { i in + Image(systemName: "chevron.compact.right") + .font(symbolsFont) + .foregroundStyle(buttonColors[(target + 2 - i) % 3]) + } + } + .compositingGroup() .padding() + } } } @@ -124,12 +153,13 @@ struct SliderStyleCursorBar Spacer() moveLeftButton Spacer() - Image(systemName: "circle.fill").font(.system(size: 22, weight: symbolsFontWeight, design: .default)) + Image(systemName: "circle.fill") + .font(symbolsFont) + .foregroundStyle(symbolsColor) Spacer() moveRightButton Spacer() } - .foregroundStyle(symbolsColor) ) } } From 5e66dd13fddbced3eb71e3cc6d5b2d0bc382c43d Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 30 Sep 2023 11:50:58 +0900 Subject: [PATCH 081/124] Update Setting tab --- MainApp/Setting/SettingTab.swift | 7 ++---- Resources/Localizable.xcstrings | 42 ++++++++------------------------ 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index 6318cd1c..00bf26bd 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -43,7 +43,8 @@ struct SettingTabView: View { BoolSettingView(.enablePasteButton) } } - Section(header: Text("タブバー")) { + Section(header: Text("バー")) { + BoolSettingView(.useSliderStyleCursorBar) BoolSettingView(.displayTabBarButton) BoolSettingView(.enableClipboardHistoryManagerTab) if SemiStaticStates.shared.hasFullAccess { @@ -51,10 +52,6 @@ struct SettingTabView: View { } NavigationLink("タブバーを編集", destination: EditingTabBarView(manager: $appStates.custardManager)) } - Section(header: Text("カーソルバー")) { - BoolSettingView(.useSliderStyleCursorBar) - FallbackLink("フィードバックを募集します", destination: "https://forms.gle/vZ8Ftuu9BJBEi98h7", icon: .link) - } // デバイスが触覚フィードバックをサポートしている場合のみ表示する if SemiStaticStates.shared.hapticsAvailable { Section(header: Text("サウンドと振動")) { diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 271e733e..744d6a0b 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -1877,22 +1877,6 @@ } } }, - "カーソルバー" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Cursor bar" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "" - } - } - } - }, "カーソルバーの切り替え" : { "localizations" : { "en" : { @@ -4218,6 +4202,16 @@ } } }, + "バー" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bars" + } + } + } + }, "バージョン" : { "localizations" : { "en" : { @@ -4298,22 +4292,6 @@ } } }, - "フィードバックを募集します" : { - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Feedback wanted" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "" - } - } - } - }, "フォントはiOSで標準的に利用される「ヒラギノ明朝」を用いています。明朝体の字形は手書きする際の規範的な字形と必ずしも一致しません。ご了承ください。" : { "localizations" : { "en" : { From 6fcd701c8622a42b06865765124054ce579b9640 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 5 Oct 2023 14:06:05 +0900 Subject: [PATCH 082/124] =?UTF-8?q?fix:=20=E5=89=8A=E9=99=A4=E3=82=AD?= =?UTF-8?q?=E3=83=BC=E3=82=92=E9=95=B7=E6=8A=BC=E3=81=97=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=82=82=E5=89=8A=E9=99=A4=E3=81=8C=E7=99=BA=E7=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift | 2 +- .../View/QwertyKeyboard/KeyView/QwertyKeyView.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift index 829396b5..cf8420fe 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyFunctionalKeyModel.swift @@ -35,7 +35,7 @@ struct QwertyFunctionalKeyModel LongpressActionType { - .none + self.longPressActions } func label(width: CGFloat, states: VariableStates, color: Color?) -> KeyLabel { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index 2aa020a2..fc835b99 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -135,6 +135,7 @@ struct QwertyKeyView: View try await Task.sleep(nanoseconds: 0_400_000_000) } catch { debug(error) + return } // すでに処理が終了済みでなければ if !Task.isCancelled && self.pressState.isActive { From d631cfef1b3986fe343ac20626f60a52042d57a0 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 5 Oct 2023 14:30:01 +0900 Subject: [PATCH 083/124] =?UTF-8?q?feat:=20QwertyKeyView=E3=81=AE=E3=82=B5?= =?UTF-8?q?=E3=82=B8=E3=82=A7=E3=82=B9=E3=83=88=E3=81=AB=E8=96=84=E3=81=84?= =?UTF-8?q?=E3=82=B7=E3=83=A3=E3=83=89=E3=82=A6=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/QwertyKeyboard/KeyView/QwertyKeyView.swift | 8 ++++++++ .../QwertyKeyboard/KeyView/QwertyVariationsView.swift | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift index 2aa020a2..068e6ddc 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyKeyView.swift @@ -214,6 +214,10 @@ struct QwertyKeyView: View theme != Extension.ThemeExtension.default(layout: .qwerty) ? .black : nil } + private var shadowColor: Color { + suggestTextColor?.opacity(0.5) ?? .black.opacity(0.5) + } + private var selection: Int? { if case let .variations(selection) = pressState { return selection @@ -259,6 +263,8 @@ struct QwertyKeyView: View .padding(.bottom, height), alignment: self.model.variationsModel.direction.alignment ) + .compositingGroup() + .shadow(color: shadowColor, radius: 1, x: 0, y: 0) .allowsHitTesting(false) } else { QwertySuggestView.scaleToFrameSize( @@ -273,6 +279,8 @@ struct QwertyKeyView: View label(width: size.width, color: suggestTextColor) .padding(.bottom, height) ) + .compositingGroup() + .shadow(color: shadowColor, radius: 1, x: 0, y: 0) .allowsHitTesting(false) } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift index 876d427f..c55d9a64 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift @@ -40,6 +40,6 @@ struct QwertyVariationsView } @MainActor private func getLabel(_ labelType: KeyLabelType) -> KeyLabel { - KeyLabel(labelType, width: tabDesign.keyViewWidth, textColor: theme.suggestLabelTextColor?.color) + KeyLabel(labelType, width: tabDesign.keyViewWidth, textColor: theme.suggestLabelTextColor?.color ?? .black) } } From 912dbae7429432ad17920097ec373424c7ae931d Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 5 Oct 2023 15:38:56 +0900 Subject: [PATCH 084/124] =?UTF-8?q?[Feature]=20=E7=89=B9=E5=88=A5=E3=81=AA?= =?UTF-8?q?=E6=97=A5=E3=81=AB=E3=82=B9=E3=83=9A=E3=82=B7=E3=83=A3=E3=83=AB?= =?UTF-8?q?=E3=82=A2=E3=82=A4=E3=82=B3=E3=83=B3=E3=82=92=E8=A1=A8=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/KeyboardBar/EmojiTabResultBar.swift | 5 +-- .../View/KeyboardBar/KeyboardBarView.swift | 8 ++--- .../View/KeyboardBar/ResultBar.swift | 8 ++--- .../View/KeyboardBar/TabBarButton.swift | 32 ++++++++++++++++++ Resources/AzooKeyIcon-Regular.otf | Bin 6888 -> 8144 bytes 5 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/TabBarButton.swift diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift index 4e6653be..2796c351 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/EmojiTabResultBar.swift @@ -30,10 +30,7 @@ struct EmojiTabResultBar: V var body: some View { HStack { - KeyboardBarButton { - self.action.registerAction(.setTabBar(.on), variableStates: variableStates) - } - + TabBarButton() if !showResults { // 見た目だけ表示しておいて、実際はoverlayのボタンになっている InKeyboardSearchBar(text: $searchQuery, configuration: searchBarDesign) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift index eb6274cb..45c40db3 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift @@ -48,7 +48,7 @@ struct KeyboardBarView: Vie @MainActor struct KeyboardBarButton: View { enum LabelType { - case azooKeyIcon + case azooKeyIcon(AzooKeyIcon.Looks = .normal) case systemImage(String) } @Environment(Extension.Theme.self) private var theme @@ -56,7 +56,7 @@ struct KeyboardBarButton: V private var action: () -> Void private let label: LabelType - init(label: LabelType = .azooKeyIcon, action: @escaping () -> Void) { + init(label: LabelType, action: @escaping () -> Void) { self.label = label self.action = action } @@ -84,8 +84,8 @@ struct KeyboardBarButton: V .strokeAndFill(fillContent: buttonBackgroundColor, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth) .frame(width: circleSize, height: circleSize) switch label { - case .azooKeyIcon: - AzooKeyIcon(fixedSize: iconSize, color: .color(buttonLabelColor)) + case let .azooKeyIcon(looks): + AzooKeyIcon(fixedSize: iconSize, color: .color(buttonLabelColor), looks: looks) case let .systemImage(name): Image(systemName: name) .frame(width: iconSize, height: iconSize) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift index 3f6dfc5b..af35e3de 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ResultBar.swift @@ -45,11 +45,9 @@ struct ResultBar: View { } private var tabBarButton: some View { - KeyboardBarButton { - self.action.registerAction(.setTabBar(.toggle), variableStates: variableStates) - } - .zIndex(10) - .matchedGeometryEffect(id: "KeyboardBarButton", in: namespace) + TabBarButton() + .zIndex(10) + .matchedGeometryEffect(id: "KeyboardBarButton", in: namespace) } var body: some View { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/TabBarButton.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/TabBarButton.swift new file mode 100644 index 00000000..6517a13a --- /dev/null +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/TabBarButton.swift @@ -0,0 +1,32 @@ +// +// TabBarButton.swift +// +// +// Created by miwa on 2023/10/05. +// + +import SwiftUI + +struct TabBarButton: View { + @Environment(\.userActionManager) private var action + @EnvironmentObject private var variableStates: VariableStates + @State private var calendar = Calendar.current + + // クリスマスには専用アイコンを表示する + var isXmas: Bool { + let values = calendar.dateComponents([.month, .day], from: .now) + return values.month == 12 && values.day == 25 + } + + // 8/1には夏アイコンを表示する + var isSummerDay: Bool { + let values = calendar.dateComponents([.month, .day], from: .now) + return values.month == 8 && values.day == 1 + } + + var body: some View { + KeyboardBarButton(label: .azooKeyIcon(isXmas ? .santaClaus : isSummerDay ? .strawHat : .normal)) { + self.action.registerAction(.setTabBar(.toggle), variableStates: variableStates) + } + } +} diff --git a/Resources/AzooKeyIcon-Regular.otf b/Resources/AzooKeyIcon-Regular.otf index 4f301a340ad84edbfd1508549349b7c22679c2ae..767aba774f31bb28abc4adb9caecdf3321ed50f7 100644 GIT binary patch delta 2051 zcmZ8h3se(l7XF7MFjj?_VbDzCBn#^9S`mVxU=dKBqKL>tP(-6dg9gbW2qKaQSSTVX zjPeMmsAwx)&K40GpY>g<)fV+o5W80QA$!_-R!{2<{H*RD*wfv!bN+Ac{qEzxckaym zgZ|%ynBo!>o;a;jW2HZVUjN;JXf#NX1o^|(n0j=1oQO7pgb=hAo1aZPt#}R znhMHOX$>JG1kqXA0wa>GAS!YcaNefP(%sxYIG-et2E)e8VK_by0v7o2n#dZIcZ;bLrkw4)gU&yKJ!5GBMry9*i45vCcG{kKl`DPko;$~Q)(yiqCgmq4ByG)!tz%E@jMDN6E= zo4dmE_rCLkWAZCE=yJ6gIzz5@vo@g?P%2tYRZ`{D2UGk#9`M9Zg%O}Ny-74P@FA=9MmU;Hm|20RJr1EmAN{fp zViXVt{{7%(E3)N%s=~Xn@lRK<_)GdD9Mj2rWKgD+5Jx?}X!p1*8VZ9hcGc0f?RU5< z9o7T)c;gnshMa1;?r6=C!(6}S{NgI!_WoCEQaEG2Nt@1Z&M4KJlj(d*(eZY!^XS#v z7x_qSQciL{?UT9qy%5fLaNE&rJ}*y~7SHLL)}K%31D^rC2G%Md5hA_^KVTPjhhXnJ zD(s1EEaoux#oahndCBe^Bd0r@)$u2;p}JnE=a+sC;}T$lqOGB(uCbsc`=sia>1kp* zw|UFnbip+FjR(8}aZe8g0XUTDHru;LFu69_SQA!x7$^mrAx-vhbKj;`6GZYsqG zAyX;73LEVwA>$4t*b`3KpVu;Gb;v)5+w9X>2BB~ie_~a~1MZ9NLkD|#!zR5cE!#pj z9IrXn!u@5&mB1?g()$mS;<>E6;x#EegPdrzaowJcrWJIaW#>m7obAM|p6h&Y+VX92 zc{F1d(`cG5(03kZsN34QmH$JIHf0I7{?O_xDZKAbFgX!+C}1n3{Q!}w(KcZE-1B(R z177Jig1=&Y?k9Jfu;lfPXW#^qFCTV%X1TEJT<|5`s#Qzl!-BmdXVGxg#g^H+mNz)B z&CE$x{cD3udV9`UzRme;d#gyi4w6~NitZ1Pw#Wl_bl08=y-q8C z*4y{7hMc19yH!c8vGp-~@#;c66$e^zEX~l!$%LA5ECiExkk~{sPUNt%S-R>w4$+Jh ziOf41T6ce}xJatCpH$kh#mj$9Z-&%nP(i>hSWXrWhN(EQ zkRICMfzx(kC7x%+am{!+DK!-mn<1$gyd1Hn{|#ou6p|{3qesl_lkXnhg$Us3+XF^m z)ryhmDhXx|;F#A6IOrU>6wkqm_!v4Uyc@gzps?pSzbb|xjY2to0#vX}C^D-H`%<6G zK8-yt<6v!o8jG;kL2_P5up3Z#9PF+Ur$#YZ=HGv;%nukEfkHT<;IzB2hUtQeZLRf#`gL0rt8 z8{hTUJgV)95PXC&FB$uPe1q2?KN|J@n#qKQRv@ML7NoK@ZJX*&TCERy!PU}y{C>4V$XjE=4%+BJpEt%b&oYm5Jpn?1xYB37C36o=?NYUO@ jQ?Ft|rDD{acWmn^{zUPQv8mi>r45_PQh4Dq_q%@s9W_-u delta 847 zcmZ9IYe-Z<6vxkacehR5b-j8Q_d$EnmDEVrTfV|qsi{#asnJ8S>m#>vbIn!O5;PDp zvlf{z)q)a87=;9zBpTF*5Wh$n(bEro2$G=32bZ~buV}L-1PycMe}3njf&a|wqLr-v z>bkmWh=KuNz)^DWAa8o}YYad$2oQgyw6?Mw01$xr3sr4-ZT*2TQGQF0$m-e*!I@F# zry~`V&osM4_s{tcGJyIwWskE}Y{|1e9isV58re=-u+Etl>Aan?-Rbi5dkd;m*%a1j zq_{+{8w@oxg=aK07e!a={LPgddSMbkRqpQS@@&k2KwB-e&jZj|1I@ywXw2UqJ>3|S z9|VS3p%wU&y>H~7uDeZl7@jf%5#cIb-qCe^0@d>n4cnmvl3@a(5l{17@D-P$B((}u zn(;t8dZl786TpQUTipAN7aI>ZZmfCM>Wq<`!u5lbV;|o}bLP(>FwBy5o& zw!58TQ>#ZT>2UX6I@jj(@C_-=4XM1~5ccp*y*xg(EiD&8B7zeL-9qRZ0E^I&8VnKi zf7DDx)aU4SU4ky8e-xMY~zlh5boj9kc97Xdzs*K2J6k~SYs5@)k+n2 z+%crsmy5K;pMs6#kcE_xtdAsVW?;Jeu}!(sp@d#3Fr$5>lyZ2AvjnahD-a$|P>j;i zun|OZw|p@26Zt5I)4AfDO(#44ccLEl`G$R#vAcK2#{2wUo1WYzv+V6q3w^;08B0BQ znM=d@=0u%TGlR&qoXL=BDS$7Sa|~V5EGy5G%J67txAYB983p{+Txl333#`0CRGSTx dRF4ZRg?h7VvdTF@9j%`3Lc5C7%EQ From 154a2ac6f8a226266085d55ef5c039ae1e73ecc3 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 5 Oct 2023 15:40:39 +0900 Subject: [PATCH 085/124] =?UTF-8?q?[Fix]=20=E6=B7=B7=E5=85=A5=E3=81=97?= =?UTF-8?q?=E3=81=A6=E3=81=84=E3=81=9F=E3=83=87=E3=83=90=E3=83=83=E3=82=B0?= =?UTF-8?q?=E7=94=A8=E5=AE=9F=E8=A3=85=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift index 4f31d162..55011445 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickEnterKeyModel.swift @@ -24,7 +24,7 @@ struct FlickEnterKeyModel: } } - func longPressActions(variableStates _: VariableStates) -> LongpressActionType { .init(start: [.selectCandidate(.offset(1))]) } + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { .none } func flickKeys(variableStates: VariableStates) -> [FlickDirection: FlickedKeyModel] { [:] From 9af653dc7ae3ffc3c1e25a5dbb72fad0c4286662 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 12 Oct 2023 00:16:26 +0900 Subject: [PATCH 086/124] Update focus implementation to make the focus more clear --- MainApp/General/Focus.swift | 9 +++------ .../FlickCustomKeys/CustomKeySettingFlickKeyView.swift | 1 + .../QwertyCustomKeys/QwertyCustomKeysItemView.swift | 2 ++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/MainApp/General/Focus.swift b/MainApp/General/Focus.swift index adbb9a51..ef739781 100644 --- a/MainApp/General/Focus.swift +++ b/MainApp/General/Focus.swift @@ -18,17 +18,14 @@ private struct FocusViewModifier: ViewModifier { func body(content: Content) -> some View { let shadowColor = focused ? color : .clear - let shadowRadius: CGFloat = focused ? 0.5 : .zero + let shadowRadius: CGFloat = focused ? 3.0 : .zero return content - .shadow(color: shadowColor, radius: shadowRadius, x: 1) - .shadow(color: shadowColor, radius: shadowRadius, x: -1) - .shadow(color: shadowColor, radius: shadowRadius, y: 1) - .shadow(color: shadowColor, radius: shadowRadius, y: -1) + .shadow(color: shadowColor, radius: shadowRadius) } } extension View { - func focus(_ color: Color, focused: Bool) -> some View { + func focus(_ color: Color = .accentColor, focused: Bool) -> some View { self.modifier(FocusViewModifier(color: color, focused: focused)) } } diff --git a/MainApp/Setting/CustomKeys/FlickCustomKeys/CustomKeySettingFlickKeyView.swift b/MainApp/Setting/CustomKeys/FlickCustomKeys/CustomKeySettingFlickKeyView.swift index bbb13a8b..0ff3d358 100644 --- a/MainApp/Setting/CustomKeys/FlickCustomKeys/CustomKeySettingFlickKeyView.swift +++ b/MainApp/Setting/CustomKeys/FlickCustomKeys/CustomKeySettingFlickKeyView.swift @@ -39,6 +39,7 @@ struct CustomKeySettingFlickKeyView: View { RoundedRectangle(cornerRadius: 10) .stroke(strokeColor) .background(RoundedRectangle(cornerRadius: 10).fill(Color.background)) + .compositingGroup() .focus(.accentColor, focused: focused) .overlay(label()) .onTapGesture { diff --git a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift index 3b65800c..6acb887c 100644 --- a/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift +++ b/MainApp/Setting/CustomKeys/QwertyCustomKeys/QwertyCustomKeysItemView.swift @@ -165,6 +165,7 @@ struct QwertyCustomKeysSettingView: RoundedRectangle(cornerRadius: 10) .stroke(strokeColor) .background(RoundedRectangle(cornerRadius: 10).fill(Color.background)) + .compositingGroup() .focus(.accentColor, focused: isSelected && selection.longpressSelectIndex == -1) .focus(.systemGray, focused: isSelected && selection.longpressSelectIndex != -1) .overlay(Text(item.name)) @@ -179,6 +180,7 @@ struct QwertyCustomKeysSettingView: RoundedRectangle(cornerRadius: 10) .stroke(isSelected ? Color.accentColor : .primary) .background(RoundedRectangle(cornerRadius: 10).fill(Color.background)) + .compositingGroup() .focus(.accentColor, focused: isSelected) .overlay(Text(item.name)) } From f48ce34e1b9a01a79bc10610ca3aea301d414096 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 12 Oct 2023 01:17:18 +0900 Subject: [PATCH 087/124] Add special animation to acknowledgement page --- .../Sources/KeyboardViews/AzooKeyIcon.swift | 4 + .../OpenSourceSoftwaresLicenseView.swift | 109 +++++++++++++++++- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift b/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift index 8727933e..214f177c 100644 --- a/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift +++ b/AzooKeyCore/Sources/KeyboardViews/AzooKeyIcon.swift @@ -18,6 +18,7 @@ public struct AzooKeyIcon: View { case king case santaClaus case strawHat + case fire } public enum Color { case auto @@ -88,6 +89,9 @@ public struct AzooKeyIcon: View { Text("\u{EA22}") .foregroundStyle(.red) } + case .fire: + Text("δ") + .foregroundStyle(foregroundColor) } } diff --git a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift index 599beced..de18234d 100644 --- a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift +++ b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift @@ -193,7 +193,7 @@ struct OpenSourceSoftwaresLicenseView: View { } Section { HStack { - AzooKeyIcon(fontSize: 60) + FunnyAzooKeyIcon() Spacer() Text("azooKeyを使ってくれてありがとう!") } @@ -203,3 +203,110 @@ struct OpenSourceSoftwaresLicenseView: View { .navigationBarTitle(Text("オープンソースソフトウェア"), displayMode: .inline) } } + +private struct FunnyAzooKeyIcon: View { + init(stage: Stage = .normal) { + self._stage = .init(initialValue: stage) + } + + struct NormalAnimationValue { + // degrees + var angle: Double = -10 + } + struct KingAnimationValue { + // degrees + var yAngle: Double = -10 + var scale: Double = 1.0 + } + struct FireAnimationValue { + // degrees + var yAngle: Double = 0 + var scale: Double = 1.0 + } + enum Stage { + case normal + case king + case fire + } + @Namespace private var namespace + @State private var stage: Stage = .normal + + private var iconCore: some View { + AzooKeyIcon(fontSize: 60) + .matchedGeometryEffect(id: "icon", in: namespace) + } + + var body: some View { + if #available(iOS 17, *) { + switch stage { + case .normal: + iconCore + .keyframeAnimator(initialValue: NormalAnimationValue()) { content, value in + content + .rotationEffect(Angle(degrees: value.angle)) + } keyframes: { _ in + KeyframeTrack(\.angle) { + CubicKeyframe(10, duration: 0.5) + CubicKeyframe(-10, duration: 0.5) + } + } + .onTapGesture { + withAnimation { + self.stage = Bool.random() ? .king : .fire + } + } + case .king: + AzooKeyIcon(fontSize: 60, looks: .king) + .matchedGeometryEffect(id: "icon", in: namespace) + .keyframeAnimator(initialValue: KingAnimationValue()) { content, value in + content + .rotationEffect(Angle(degrees: value.yAngle)) + .scaleEffect(value.scale) + } keyframes: { _ in + KeyframeTrack(\.yAngle) { + CubicKeyframe(10, duration: 0.5) + CubicKeyframe(-10, duration: 0.5) + } + KeyframeTrack(\.scale) { + SpringKeyframe(1, duration: 0.2) + SpringKeyframe(1.4, duration: 0.6) + SpringKeyframe(1, duration: 0.2) + } + } + .onTapGesture { + withAnimation { + self.stage = .normal + } + } + case .fire: + AzooKeyIcon(fontSize: 60, looks: .fire) + .matchedGeometryEffect(id: "icon", in: namespace) + .keyframeAnimator(initialValue: FireAnimationValue()) { content, value in + content + .rotationEffect(Angle(degrees: value.yAngle)) + .scaleEffect(value.scale) + } keyframes: { _ in + KeyframeTrack(\.yAngle) { + SpringKeyframe(20, duration: 0.8) + CubicKeyframe(0, duration: 0.2) + } + } + .onTapGesture { + withAnimation { + self.stage = .normal + } + } + } + } else { + iconCore + } + } +} + +#Preview { + VStack { + FunnyAzooKeyIcon(stage: .normal) + FunnyAzooKeyIcon(stage: .king) + FunnyAzooKeyIcon(stage: .fire) + } +} From 8b5b4bb2da8e893ecd0c2e673c51a85fa5d5b34d Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 12 Oct 2023 02:05:28 +0900 Subject: [PATCH 088/124] Update tab abr editor usability --- MainApp/Customize/EditingTabBarView.swift | 127 +++++++++++++--------- Resources/Localizable.xcstrings | 40 +++++++ 2 files changed, 114 insertions(+), 53 deletions(-) diff --git a/MainApp/Customize/EditingTabBarView.swift b/MainApp/Customize/EditingTabBarView.swift index a41a8bb2..ba63e586 100644 --- a/MainApp/Customize/EditingTabBarView.swift +++ b/MainApp/Customize/EditingTabBarView.swift @@ -44,57 +44,89 @@ struct EditingTabBarView: View { self._manager = manager } + private static let anchorId = "BOTTOM_ANCHOR" var body: some View { - Form { - Text("タブバーを編集し、タブの並び替え、削除、追加を行ったり、文字の入力やカーソルの移動など様々な機能を追加することができます。") - Section { - Button(action: add) { - Label("アイテムを追加", systemImage: "plus") + ScrollViewReader { proxy in + Form { + Text("タブバーを編集し、タブの並び替え、削除、追加を行ったり、文字の入力やカーソルの移動など様々な機能を追加することができます。") + Section { + Button("アイテムを追加", systemImage: "plus") { + withAnimation(.interactiveSpring()) { + let item = EditingTabBarItem( + label: .text("アイテム"), + actions: [.moveTab(.system(.user_japanese))] + ) + self.items.append(item) + proxy.scrollTo(Self.anchorId, anchor: .bottom) + } + } } - } - Section(header: Text("アイテム")) { - DisclosuringList($items) { $item in - HStack { - Label("ラベル", systemImage: "rectangle.and.pencil.and.ellipsis") - Spacer() - TabNavigationViewItemLabelEditView("ラベルを設定", label: $item.label) + Section(header: Text("アイテム")) { + DisclosuringList($items) { $item in + HStack { + Label("ラベル", systemImage: "rectangle.and.pencil.and.ellipsis") + Spacer() + TabNavigationViewItemLabelEditView("ラベルを設定", label: $item.label) + } + NavigationLink(destination: CodableActionDataEditor($item.actions, availableCustards: manager.availableCustards)) { + Label("アクション", systemImage: "terminal") + Text(makeLabelText(item: item)) + .foregroundStyle(.gray) + } + } label: { item in + label(labelType: item.label) + .contextMenu { + Button(role: .destructive) { + items.removeAll(where: {$0.id == item.id}) + } label: { + Label("削除", systemImage: "trash") + } + } } - NavigationLink(destination: CodableActionDataEditor($item.actions, availableCustards: manager.availableCustards)) { - Label("アクション", systemImage: "terminal") - - Text(makeLabelText(item: item)) - .foregroundStyle(.gray) + .onDelete(perform: delete) + .onMove(perform: move) + } + Section(header: Text("便利なボタンを追加")) { + Button("片手モードをオン", systemImage: "aspectratio") { + withAnimation(.interactiveSpring()) { + self.items.append(EditingTabBarItem(label: .text("片手"), actions: [.enableResizingMode])) + } } - } label: { item in - label(labelType: item.label) - .contextMenu { - Button(role: .destructive) { - items.removeAll(where: {$0.id == item.id}) - } label: { - Label("削除", systemImage: "trash") - } + .id(Self.anchorId) // ココに付けると自動スクロールが機能する + Button("絵文字タブを表示", systemImage: "face.smiling") { + withAnimation(.interactiveSpring()) { + self.items.append(EditingTabBarItem(label: .text("絵文字"), actions: [.moveTab(.system(.emoji_tab))])) + } + } + Button("カーソルバーを表示", systemImage: "arrowtriangle.left.and.line.vertical.and.arrowtriangle.right") { + withAnimation(.interactiveSpring()) { + self.items.append(EditingTabBarItem(label: .text("カーソル移動"), actions: [.toggleCursorBar])) } + } + Button("キーボードを閉じる", systemImage: "keyboard.chevron.compact.down") { + withAnimation(.interactiveSpring()) { + self.items.append(EditingTabBarItem(label: .text("閉じる"), actions: [.dismissKeyboard])) + } + } } - .onDelete(perform: delete) - .onMove(perform: move) } - } - .onAppear { - if let tabBarData = try? manager.tabbar(identifier: 0), tabBarData.lastUpdateDate != self.lastUpdateDate { - self.items = tabBarData.items.indices.map {i in - EditingTabBarItem( - label: tabBarData.items[i].label, - actions: tabBarData.items[i].actions - ) + .onAppear { + if let tabBarData = try? manager.tabbar(identifier: 0), tabBarData.lastUpdateDate != self.lastUpdateDate { + self.items = tabBarData.items.indices.map {i in + EditingTabBarItem( + label: tabBarData.items[i].label, + actions: tabBarData.items[i].actions + ) + } } } + .onChange(of: items) {newValue in + self.save(newValue) + } + .navigationBarTitle(Text("タブバーの編集"), displayMode: .inline) + .navigationBarItems(trailing: editButton) + .environment(\.editMode, $editMode) } - .onChange(of: items) {newValue in - self.save(newValue) - } - .navigationBarTitle(Text("タブバーの編集"), displayMode: .inline) - .navigationBarItems(trailing: editButton) - .environment(\.editMode, $editMode) } @ViewBuilder private func label(labelType: TabBarItemLabelType) -> some View { @@ -149,7 +181,7 @@ struct EditingTabBarView: View { } label: { switch editMode { case .inactive: - Text("削除と順番") + Text("編集") case .active, .transient: Text("完了") @unknown default: @@ -158,17 +190,6 @@ struct EditingTabBarView: View { } } - private func add() { - withAnimation(Animation.interactiveSpring()) { - items.append( - EditingTabBarItem( - label: .text("アイテム"), - actions: [.moveTab(.system(.user_japanese))] - ) - ) - } - } - private func delete(at offsets: IndexSet) { items.remove(atOffsets: offsets) } diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 744d6a0b..7bfb0cbd 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -1925,6 +1925,16 @@ } } }, + "カーソルバーを表示" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show cursor bar" + } + } + } + }, "カーソルを移動する" : { "localizations" : { "en" : { @@ -5356,6 +5366,16 @@ } } }, + "便利なボタンを追加" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add useful buttons" + } + } + } + }, "便利な使い方" : { "localizations" : { "en" : { @@ -8522,6 +8542,16 @@ } } }, + "絵文字タブを表示" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show emoji tab" + } + } + } + }, "絵文字と顔文字" : { "localizations" : { "en" : { @@ -8602,6 +8632,16 @@ } } }, + "編集" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Edit" + } + } + } + }, "編集が終わったら完了ボタンを押してください。" : { "localizations" : { "en" : { From abf4716520bf9be5ad9e144495e68c7c5d6a4ba6 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 12 Oct 2023 12:54:12 +0900 Subject: [PATCH 089/124] Stop using weird twerk to show the azooKey logo --- MainApp/General/HeaderLogoView.swift | 6 +- MainApp/Tips/TipsView.swift | 85 ++++++++++++++-------------- 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/MainApp/General/HeaderLogoView.swift b/MainApp/General/HeaderLogoView.swift index 0fa2d0c6..cb859a27 100644 --- a/MainApp/General/HeaderLogoView.swift +++ b/MainApp/General/HeaderLogoView.swift @@ -33,7 +33,9 @@ struct HeaderLogoView: View { } } .foregroundStyle(iconColor) - .padding(.top, 5) - .padding(.bottom, -5) } } + +#Preview { + HeaderLogoView() +} diff --git a/MainApp/Tips/TipsView.swift b/MainApp/Tips/TipsView.swift index 6b4402c3..10a912aa 100644 --- a/MainApp/Tips/TipsView.swift +++ b/MainApp/Tips/TipsView.swift @@ -14,56 +14,59 @@ struct TipsTabView: View { @AppStorage("read_article_iOS15_service_termination") private var readArticle_iOS15_service_termination = false var body: some View { - VStack { - HeaderLogoView() - NavigationView { - Form { - Section(header: Text("キーボードを使えるようにする")) { - if !appStates.isKeyboardActivated { - Text("キーボードを有効化する") - .onTapGesture { - appStates.requireFirstOpenView = true - } - } - NavigationLink("入力方法を選ぶ", destination: SelctInputStyleTipsView()) + NavigationView { + Form { + Section(header: Text("キーボードを使えるようにする")) { + if !appStates.isKeyboardActivated { + Text("キーボードを有効化する") + .onTapGesture { + appStates.requireFirstOpenView = true + } } - if #unavailable(iOS 16) { - Section(header: Text("お知らせ")) { - HStack { - if !readArticle_iOS15_service_termination { - Image(systemName: "exclamationmark.circle.fill") - .foregroundStyle(.red) - } - NavigationLink("iOS15のサポートを終了します", destination: iOS15TerminationNewsView($readArticle_iOS15_service_termination)) + NavigationLink("入力方法を選ぶ", destination: SelctInputStyleTipsView()) + } + if #unavailable(iOS 16) { + Section(header: Text("お知らせ")) { + HStack { + if !readArticle_iOS15_service_termination { + Image(systemName: "exclamationmark.circle.fill") + .foregroundStyle(.red) } + NavigationLink("iOS15のサポートを終了します", destination: iOS15TerminationNewsView($readArticle_iOS15_service_termination)) } } + } - Section(header: Text("便利な使い方")) { - NavigationLink("片手モードを使う", destination: OneHandedModeTipsView()) - NavigationLink("カーソルを自由に移動する", destination: CursorMoveTipsView()) - NavigationLink("文頭まで一気に消す", destination: SmoothDeleteTipsView()) - NavigationLink("漢字を拡大表示する", destination: KanjiLargeTextTipsView()) - NavigationLink("大文字に固定する", destination: CapsLockTipsView()) - NavigationLink("タイムスタンプを使う", destination: TemplateSettingTipsView()) - NavigationLink("キーをカスタマイズする", destination: CustomKeyTipsView()) - NavigationLink("フルアクセスが必要な機能を使う", destination: FullAccessTipsView()) - if SemiStaticStates.shared.hasFullAccess { - NavigationLink("「ほかのAppからペースト」について", destination: PasteFromOtherAppsPermissionTipsView()) - } + Section(header: Text("便利な使い方")) { + NavigationLink("片手モードを使う", destination: OneHandedModeTipsView()) + NavigationLink("カーソルを自由に移動する", destination: CursorMoveTipsView()) + NavigationLink("文頭まで一気に消す", destination: SmoothDeleteTipsView()) + NavigationLink("漢字を拡大表示する", destination: KanjiLargeTextTipsView()) + NavigationLink("大文字に固定する", destination: CapsLockTipsView()) + NavigationLink("タイムスタンプを使う", destination: TemplateSettingTipsView()) + NavigationLink("キーをカスタマイズする", destination: CustomKeyTipsView()) + NavigationLink("フルアクセスが必要な機能を使う", destination: FullAccessTipsView()) + if SemiStaticStates.shared.hasFullAccess { + NavigationLink("「ほかのAppからペースト」について", destination: PasteFromOtherAppsPermissionTipsView()) } + } - Section(header: Text("困ったときは")) { - NavigationLink("インストール直後、特定のアプリでキーボードが開かない", destination: KeyboardBehaviorIssueAfterInstallTipsView()) - NavigationLink("特定のアプリケーションで入力がおかしくなる", destination: UseMarkedTextTipsView()) - NavigationLink("端末の文字サイズ設定が反映されない", destination: DynamicTypeSettingFailureTipsView()) - NavigationLink("絵文字や顔文字の変換候補を表示したい", destination: EmojiKaomojiTipsView()) - NavigationLink("バグの報告や機能のリクエストをしたい", destination: ContactView()) - } + Section(header: Text("困ったときは")) { + NavigationLink("インストール直後、特定のアプリでキーボードが開かない", destination: KeyboardBehaviorIssueAfterInstallTipsView()) + NavigationLink("特定のアプリケーションで入力がおかしくなる", destination: UseMarkedTextTipsView()) + NavigationLink("端末の文字サイズ設定が反映されない", destination: DynamicTypeSettingFailureTipsView()) + NavigationLink("絵文字や顔文字の変換候補を表示したい", destination: EmojiKaomojiTipsView()) + NavigationLink("バグの報告や機能のリクエストをしたい", destination: ContactView()) + } + } + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .principal) { + HeaderLogoView() + .padding(.vertical, 4) } - .navigationBarTitle(Text("使い方"), displayMode: .large) } - .navigationViewStyle(.stack) } + .navigationViewStyle(.stack) } } From 0f46370499f669395585e391c58c8bc5a1eee052 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 12 Oct 2023 15:37:28 +0900 Subject: [PATCH 090/124] Make tutorial more smart design in iPad --- MainApp/Customize/CustomizeTabWalkthrough.swift | 1 + MainApp/EnableAzooKeyView/EnableAzooKeyView.swift | 12 +++++++++--- .../EnableAzooKeyViewComponent.swift | 1 + MainApp/General/LargeButtonStyle.swift | 6 ++---- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/MainApp/Customize/CustomizeTabWalkthrough.swift b/MainApp/Customize/CustomizeTabWalkthrough.swift index 2b6925f9..0c4a3896 100644 --- a/MainApp/Customize/CustomizeTabWalkthrough.swift +++ b/MainApp/Customize/CustomizeTabWalkthrough.swift @@ -84,6 +84,7 @@ struct CustomizeTabWalkthroughView: View { } .buttonStyle(LargeButtonStyle(backgroundColor: .blue)) .foregroundStyle(.white) + .padding(.horizontal, 20) .padding(.top, 30) } .background(Color.background) diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift index 4269783c..be060316 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyView.swift @@ -62,9 +62,13 @@ struct EnableAzooKeyView: View { EnableAzooKeyViewHeader("追加する") EnableAzooKeyViewText("下にスクロールして「追加する」を押して", with: "plus.circle") EnableAzooKeyViewText("「キーボード」を押して", with: "keyboard") - EnableAzooKeyViewImage(.initSettingKeyboardImageHand) + CenterAlignedView { + EnableAzooKeyViewImage(.initSettingKeyboardImageHand) + } EnableAzooKeyViewText("azooKeyをオンにして", with: "square.and.line.vertical.and.square.fill") - EnableAzooKeyViewImage(.initSettingAzooKeySwitchImageHand) + CenterAlignedView { + EnableAzooKeyViewImage(.initSettingAzooKeySwitchImageHand) + } EnableAzooKeyViewText("このアプリを再び開いてください", with: "arrow.turn.down.left") CenterAlignedView { EnableAzooKeyViewButton("追加する", systemName: "plus.circle") { @@ -134,7 +138,9 @@ struct EnableAzooKeyView: View { appStates.requireFirstOpenView = false } if !showDoneMessage { - EnableAzooKeyViewImage(.initSettingGlobeTap) + CenterAlignedView { + EnableAzooKeyViewImage(.initSettingGlobeTap) + } } EnableAzooKeyViewText("azooKeyをお楽しみください!", with: "star.fill") if !showDoneMessage { diff --git a/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift b/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift index 0574c628..dc91d28e 100644 --- a/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift +++ b/MainApp/EnableAzooKeyView/EnableAzooKeyViewComponent.swift @@ -100,5 +100,6 @@ struct EnableAzooKeyViewImage: View { .resizable() .scaledToFit() .cornerRadius(2) + .frame(maxWidth: MainAppDesign.imageMaximumWidth) } } diff --git a/MainApp/General/LargeButtonStyle.swift b/MainApp/General/LargeButtonStyle.swift index db683860..f17380b3 100644 --- a/MainApp/General/LargeButtonStyle.swift +++ b/MainApp/General/LargeButtonStyle.swift @@ -10,19 +10,17 @@ import SwiftUI struct LargeButtonStyle: ButtonStyle { private let backgroundColor: Color - private let screenWidth: CGFloat @MainActor init(backgroundColor: Color) { self.backgroundColor = backgroundColor - self.screenWidth = UIScreen.main.bounds.width } @ViewBuilder func makeBody(configuration: Configuration) -> some View { configuration .label .font(.body.bold()) .padding() - .frame(width: screenWidth * 0.9) + .frame(maxWidth: .infinity) .background( - RoundedRectangle(cornerRadius: screenWidth / 4.8 * 0.17) + RoundedRectangle(cornerRadius: 12) .fill(backgroundColor) ) .opacity(configuration.isPressed ? 0.8 : 1) From 52af458a422495afff1bdb3bdb7c9ebdc4e17cc6 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 13 Oct 2023 11:09:31 +0900 Subject: [PATCH 091/124] Fix broken layout --- .../Customize/CustomizeTabWalkthrough.swift | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/MainApp/Customize/CustomizeTabWalkthrough.swift b/MainApp/Customize/CustomizeTabWalkthrough.swift index 0c4a3896..22b7c563 100644 --- a/MainApp/Customize/CustomizeTabWalkthrough.swift +++ b/MainApp/Customize/CustomizeTabWalkthrough.swift @@ -60,25 +60,26 @@ struct CustomizeTabWalkthroughView: View { Text("azooKeyを拡張する").font(.largeTitle.bold()) .padding() let imagesFont: Font = Font.system(size: length / 2.4, weight: .light, design: .default) - ForEach(items) {item in - HStack { - Image(systemName: item.image) - .font(imagesFont) - .frame(width: geometry.size.width / 7.0, height: geometry.size.width / 7.0) - .foregroundStyle(.blue) - VStack(alignment: .leading) { - Text(item.headline) - .font(.subheadline.bold()) - Text(item.body) - .foregroundStyle(.gray) - .font(.subheadline) + VStack(alignment: .leading, spacing: 20) { + ForEach(items) {item in + HStack { + Image(systemName: item.image) + .font(imagesFont) + .frame(width: geometry.size.width / 7.0, height: geometry.size.width / 7.0) + .foregroundStyle(.blue) + VStack(alignment: .leading) { + Text(item.headline) + .font(.subheadline.bold()) + Text(item.body) + .foregroundStyle(.gray) + .font(.subheadline) + } } + .padding(.horizontal, 20) + .lineLimit(nil) + .fixedSize(horizontal: false, vertical: true) } - .padding(.horizontal, 20) - .lineLimit(nil) - .fixedSize(horizontal: false, vertical: true) } - Button("始める") { isShowing = false } From 953a90c237165eb818a2f4c0905913b5fcc6efdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naoki=20Takahashi=20/=20=E9=9B=BB=E9=9B=BB=E7=8C=AB?= =?UTF-8?q?=E7=8C=AB?= <43579605+nyanko3141592@users.noreply.github.com> Date: Sun, 15 Oct 2023 20:04:59 +0900 Subject: [PATCH 092/124] =?UTF-8?q?=E9=81=B8=E6=8A=9E=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=82=8B=E3=83=86=E3=82=AD=E3=82=B9=E3=83=88=E3=81=8C?= =?UTF-8?q?=E3=81=82=E3=82=8B=E5=A0=B4=E5=90=88=E3=81=AB=E3=83=AA=E3=82=B6?= =?UTF-8?q?=E3=83=AB=E3=83=88=E3=83=90=E3=83=BC=E3=81=AE=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=E3=82=92=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard/Display/InputManager.swift | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index b1023150..6e20b81a 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -682,18 +682,24 @@ import UIKit /// - note: この関数をユーティリティとして用いてはいけない。 func userMovedCursor(count: Int) -> [ActionType] { debug("userによるカーソル移動を検知、今の位置は\(composingText.convertTargetCursorPosition)、動かしたオフセットは\(count)") - if composingText.isEmpty { + // 選択しているテキストがある場合はリザルトバーを表示する + if self.isSelected { + // リザルトバーを表示する + return [.setCursorBar(.off), .setTabBar(.off)] + } + // 入力テキストなし + if self.composingText.isEmpty { // 入力がない場合はreturnしておかないと、入力していない時にカーソルを動かせなくなってしまう。 return [.setCursorBar(.on)] } - let actualCount = composingText.moveCursorFromCursorPosition(count: count) - self.previousSystemOperation = self.displayedTextManager.updateComposingText(composingText: self.composingText, userMovedCount: count, adjustedMovedCount: actualCount) ? .moveCursor : nil - setResult() // ライブ変換有効 if liveConversionEnabled { return [.setCursorBar(.on)] } - return [] + let actualCount = composingText.moveCursorFromCursorPosition(count: count) + self.previousSystemOperation = self.displayedTextManager.updateComposingText(composingText: self.composingText, userMovedCount: count, adjustedMovedCount: actualCount) ? .moveCursor : nil + setResult() + return [.setCursorBar(.off), .setTabBar(.off)] } /// ユーザがキーボードを経由せずカットした場合の処理 From bbaa4a3ea5dff3c3bd0d23fe9e175d3357433d63 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 17 Oct 2023 16:04:11 +0900 Subject: [PATCH 093/124] =?UTF-8?q?=E9=81=B8=E6=8A=9E=E7=8A=B6=E6=85=8B?= =?UTF-8?q?=E3=81=8C=E3=81=82=E3=82=8B=E5=A0=B4=E5=90=88=E3=81=AF=E8=A7=A3?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard/Display/KeyboardActionManager.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 9d03b8e2..5a93fd69 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -523,6 +523,8 @@ import SwiftUtils if isSelected { debug("user operation id: 0", a_center) self.inputManager.userSelectedText(text: a_center) + // barStateの更新 + variableStates.barState = .none return } From 091fd3c88f9c4682711c039dd9cc66b61945cf37 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 17 Oct 2023 16:44:57 +0900 Subject: [PATCH 094/124] =?UTF-8?q?feat:=20=E6=93=8D=E4=BD=9C=E3=81=8C?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=A0=B4=E5=90=88=E3=81=AB=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E3=81=A7=E3=82=AB=E3=83=BC=E3=82=BD=E3=83=AB=E3=83=90=E3=83=BC?= =?UTF-8?q?=E3=82=92=E9=9D=9E=E8=A1=A8=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/KeyboardBar/KeyboardBarView.swift | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift index 45c40db3..0e7fcd99 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift @@ -15,6 +15,9 @@ struct KeyboardBarView: Vie @EnvironmentObject private var variableStates: VariableStates @Binding private var isResultViewExpanded: Bool @Environment(Extension.Theme.self) private var theme + // CursorBarは操作がない場合に非表示にする。これをハンドルするためのタスク + @State private var dismissTask: Task<(), any Error>? = nil + private var useReflectStyleCursorBar: Bool { Extension.SettingProvider.useSliderStyleCursorBar } @@ -26,10 +29,20 @@ struct KeyboardBarView: Vie var body: some View { switch variableStates.barState { case .cursor: - if useReflectStyleCursorBar { - ReflectStyleCursorBar() - } else { - SliderStyleCursorBar() + Group { + if useReflectStyleCursorBar { + ReflectStyleCursorBar() + } else { + SliderStyleCursorBar() + } + } + .onAppear { + // 表示したタイミングでdismissTaskを開始 + self.restartCursorBarDismissTask() + } + .onChange(of: variableStates.textChangedCount) { _ in + // カーソルが動くたびにrestart + self.restartCursorBarDismissTask() } case .tab: let tabBarData = (try? variableStates.tabManager.config.custardManager.tabbar(identifier: 0)) ?? .default @@ -43,6 +56,18 @@ struct KeyboardBarView: Vie } } } + + private func restartCursorBarDismissTask() { + self.dismissTask?.cancel() + self.dismissTask = Task { + // 10秒待つ + try await Task.sleep(nanoseconds: 10_000_000_000) + try Task.checkCancellation() + withAnimation { + variableStates.barState = .none + } + } + } } @MainActor From 404d0523c51a8abbe1d2b3ca72c8eeeb8938a196 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 17 Oct 2023 22:11:15 +0900 Subject: [PATCH 095/124] =?UTF-8?q?=E3=82=AB=E3=83=BC=E3=82=BD=E3=83=AB?= =?UTF-8?q?=E3=83=90=E3=83=BC=E3=81=AB=E8=A1=A8=E7=A4=BA=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E6=96=87=E5=AD=97=E3=81=8C=E6=9B=B4=E6=96=B0=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=81=AA=E3=81=8F=E3=81=AA=E3=82=8B=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift index 52aa5e74..a730e49a 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift @@ -10,7 +10,7 @@ import SwiftUI import SwiftUIUtils import SwiftUtils -struct SliderStyleCursorBarState { +struct SliderStyleCursorBarState: Equatable { private(set) var displayLeftIndex = 0 private(set) var displayRightIndex = 0 fileprivate var line: [String] = [] From 707104825cd69a2ce5e04e98e2137516a248f1a1 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Wed, 18 Oct 2023 09:57:11 +0900 Subject: [PATCH 096/124] =?UTF-8?q?TemporalMessageView=E3=81=8C=E6=B6=88?= =?UTF-8?q?=E3=81=88=E3=81=AA=E3=81=84=E3=81=93=E3=81=A8=E3=81=8C=E3=81=82?= =?UTF-8?q?=E3=82=8B=E5=95=8F=E9=A1=8C=E3=81=AB=E5=AF=BE=E5=87=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyboardViews/TemporalMessage.swift | 4 +-- .../View/Components/TemporalMessageView.swift | 34 +++++++++++++------ .../KeyboardViews/View/KeyboardView.swift | 10 +++--- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/TemporalMessage.swift b/AzooKeyCore/Sources/KeyboardViews/TemporalMessage.swift index cf24665d..3e0f883e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/TemporalMessage.swift +++ b/AzooKeyCore/Sources/KeyboardViews/TemporalMessage.swift @@ -7,7 +7,7 @@ import struct SwiftUI.LocalizedStringKey -public enum TemporalMessage { +public enum TemporalMessage: Sendable { case doneForgetCandidate case doneReportWrongConversion case failedReportWrongConversion @@ -23,7 +23,7 @@ public enum TemporalMessage { } } - public enum DismissCondition { + public enum DismissCondition: Sendable { case auto case ok } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift index e84072be..90342214 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/TemporalMessageView.swift @@ -10,11 +10,15 @@ import Foundation import SwiftUI struct TemporalMessageView: View { - let message: TemporalMessage - let onDismiss: () -> Void - @EnvironmentObject private var variableStates: VariableStates - @Environment(\.userActionManager) private var action + init(message: TemporalMessage, isPresented: Binding) { + self.message = message + self._isPresented = isPresented + } + + private let message: TemporalMessage + @Binding private var isPresented: Bool + @MainActor @ViewBuilder private var core: some View { switch message.dismissCondition { @@ -22,19 +26,17 @@ struct TemporalMessageView: View { Text(message.title) .bold() .foregroundStyle(.black) - .onAppear { - Task { - // 1.5秒待機してからdismissを実行する - try await Task.sleep(nanoseconds: 1_500_000_000) - self.onDismiss() - } + .task { + // 1.5秒待機してからdismissを実行する + try? await Task.sleep(nanoseconds: 1_500_000_000) + self.dismiss() } case .ok: VStack { Text(message.title) .bold() .foregroundStyle(.black) - Button("OK", action: onDismiss) + Button("OK", action: self.dismiss) } } } @@ -51,4 +53,14 @@ struct TemporalMessageView: View { Color.black.opacity(0.5) } } + + private func dismiss() { + withAnimation(.easeIn) { + self.isPresented = false + } + } +} + +#Preview { + TemporalMessageView(message: .doneReportWrongConversion, isPresented: .init(get: { true }, set: { _ in })) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift index 246d5d7f..59a03ad4 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardView.swift @@ -78,11 +78,11 @@ public struct KeyboardView: } } if showMessage, let message = variableStates.temporalMessage { - TemporalMessageView(message: message) { - withAnimation(.easeIn) { - variableStates.temporalMessage = nil - } - } + let isPresented = Binding( + get: { variableStates.temporalMessage != nil }, + set: { if !$0 {variableStates.temporalMessage = nil} } + ) + TemporalMessageView(message: message, isPresented: isPresented) } } .frame(height: Design.keyboardScreenHeight(upsideComponent: variableStates.upsideComponent, orientation: variableStates.keyboardOrientation)) From d197a019b4b23211aaa3f575253f63e0ddf2d542 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Wed, 18 Oct 2023 13:50:08 +0900 Subject: [PATCH 097/124] =?UTF-8?q?Concurrency=20related=20warnings?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AzooKeyCore/Sources/KeyboardThemes/ThemeColor.swift | 2 +- .../KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift | 3 +-- MainApp/Customize/ManageCustardView.swift | 2 -- MainApp/General/CancelableEditor.swift | 2 +- MainApp/General/DraggableView.swift | 3 ++- MainApp/Setting/Template/TemplateEditingView.swift | 3 +++ 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardThemes/ThemeColor.swift b/AzooKeyCore/Sources/KeyboardThemes/ThemeColor.swift index c63c5ce0..c3ef2be6 100644 --- a/AzooKeyCore/Sources/KeyboardThemes/ThemeColor.swift +++ b/AzooKeyCore/Sources/KeyboardThemes/ThemeColor.swift @@ -7,7 +7,7 @@ // import Foundation -@preconcurrency import SwiftUI +import SwiftUI public enum ThemeColor: Sendable { case color(Color) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift index be77d381..25c22481 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift @@ -6,6 +6,7 @@ // Copyright © 2023 ensan. All rights reserved. // +@preconcurrency import LinkPresentation import SwiftUI import SwiftUIUtils import SwiftUtils @@ -254,8 +255,6 @@ struct ClipboardHistoryTab: } } -import LinkPresentation - private struct RichLinkView: UIViewRepresentable { class UIViewType: LPLinkView { override var intrinsicContentSize: CGSize { CGSize(width: 0, height: super.intrinsicContentSize.height) } diff --git a/MainApp/Customize/ManageCustardView.swift b/MainApp/Customize/ManageCustardView.swift index e23fb87d..83f60a1d 100644 --- a/MainApp/Customize/ManageCustardView.swift +++ b/MainApp/Customize/ManageCustardView.swift @@ -113,7 +113,6 @@ private final class ImportedCustardData: ObservableObject { } } - @MainActor private func downloadAsync(from url: URL) async { do { self.processState = .getFile @@ -356,7 +355,6 @@ struct ManageCustardView: View { guard let url = URL(string: "https://azooKey.netlify.com/static/custard/all") else { return } - let request = URLRequest(url: url) Task { let result = try await URLSession.shared.data(from: url).0 let decoder = JSONDecoder() diff --git a/MainApp/General/CancelableEditor.swift b/MainApp/General/CancelableEditor.swift index 44684cc5..0613a640 100644 --- a/MainApp/General/CancelableEditor.swift +++ b/MainApp/General/CancelableEditor.swift @@ -10,6 +10,6 @@ import SwiftUI protocol CancelableEditor: View { associatedtype EditTarget - var base: EditTarget { get } + @MainActor var base: EditTarget { get } @MainActor func cancel() } diff --git a/MainApp/General/DraggableView.swift b/MainApp/General/DraggableView.swift index 6e924914..cac59d6e 100644 --- a/MainApp/General/DraggableView.swift +++ b/MainApp/General/DraggableView.swift @@ -44,7 +44,7 @@ struct DraggableView) { self._template = template if let template = template.wrappedValue.literal as? DateTemplateLiteral { @@ -346,6 +348,7 @@ struct DateTemplateLiteralSettingView: View { return f }() + @MainActor private func update() { DispatchQueue.main.async { if formatSelection == "カスタム"{ From 8da5db1de9284abc33e290fb80cc3d669caedc69 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 19 Oct 2023 00:56:24 +0900 Subject: [PATCH 098/124] =?UTF-8?q?drawingGroup()=E3=81=8C=E5=8E=9F?= =?UTF-8?q?=E5=9B=A0=E3=81=A0=E3=81=A3=E3=81=9F=E3=81=AE=E3=81=A7=E5=89=8A?= =?UTF-8?q?=E9=99=A4=E3=81=97=E3=80=81state=E3=81=AE=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E3=81=AE=E6=A7=8B=E9=80=A0=E3=82=92=E5=A4=89=E6=9B=B4=E3=81=97?= =?UTF-8?q?=E3=81=9F=E3=80=82=E5=90=88=E3=82=8F=E3=81=9B=E3=81=A6=E3=80=81?= =?UTF-8?q?View=E3=81=8C=E3=82=AC=E3=83=81=E3=83=A3=E3=82=AC=E3=83=81?= =?UTF-8?q?=E3=83=A3=E3=81=A8=E5=8B=95=E3=81=8F=E5=95=8F=E9=A1=8C=E3=82=92?= =?UTF-8?q?=E8=A7=A3=E6=B1=BA=E3=81=97=E3=80=81=E3=82=AB=E3=83=BC=E3=82=BD?= =?UTF-8?q?=E3=83=AB=E3=83=90=E3=83=BC=E3=81=AE=E8=87=AA=E5=8B=95=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=AE=E3=83=90=E3=82=B0=E3=82=92=E7=9B=B4=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyboardViews/VariableStates.swift | 19 +++--- .../KeyboardBar/ReflectStyleCursorBar.swift | 59 ++++++++++++++----- Keyboard/Display/InputManager.swift | 9 +++ Keyboard/Display/KeyboardActionManager.swift | 6 +- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift index 03a6806a..11caf36f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift +++ b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift @@ -162,19 +162,19 @@ public final class VariableStates: ObservableObject { @Published public var undoAction: UndoAction? - @Published var moveCursorBarState = SliderStyleCursorBarState() - - @Published private(set) var leftSideText: String = "" - @Published private(set) var centerText: String = "" - @Published private(set) var rightSideText: String = "" + struct SurroundingText: Equatable, Hashable, Sendable { + var leftSideText: String = "" + var centerText: String = "" + var rightSideText: String = "" + } + @Published private(set) var surroundingText = SurroundingText() @Published public var temporalMessage: TemporalMessage? public func setSurroundingText(leftSide: String, center: String, rightSide: String) { - self.leftSideText = leftSide - self.centerText = center - self.rightSideText = rightSide - self.moveCursorBarState.updateLine(leftText: leftSide + center, rightText: rightSide) + self.surroundingText.leftSideText = leftSide + self.surroundingText.centerText = center + self.surroundingText.rightSideText = rightSide } @MainActor public func setResizingMode(_ state: ResizingState) { @@ -197,7 +197,6 @@ public final class VariableStates: ObservableObject { @MainActor public func initialize() { self.tabManager.initialize(variableStates: self) - self.moveCursorBarState.clear() } @MainActor public func closeKeyboard() { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift index a730e49a..8d4d7baf 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift @@ -10,7 +10,7 @@ import SwiftUI import SwiftUIUtils import SwiftUtils -struct SliderStyleCursorBarState: Equatable { +private struct CursorBarState: Equatable, Hashable, Sendable { private(set) var displayLeftIndex = 0 private(set) var displayRightIndex = 0 fileprivate var line: [String] = [] @@ -25,10 +25,10 @@ struct SliderStyleCursorBarState: Equatable { } mutating func updateLine(leftText: String, rightText: String) { - debug("updateLine", leftText, rightText, itemCount, line) + debug("CursorBarState.updateLine", leftText, rightText, itemCount, line) var left = leftText.map {String($0)} - if left.first == "\n" { - left.removeFirst() + if let index = left.firstIndex(of: "\n"), index != left.endIndex - 1 { + left.removeFirst(index + 1) } self.line = left + rightText.map {String($0)} + ["⏎"] self.displayLeftIndex = left.count - itemCount / 2 @@ -43,6 +43,10 @@ struct SliderStyleCursorBarState: Equatable { } @MainActor mutating fileprivate func move(_ count: Int, actionManager: some UserActionManager, variableStates: VariableStates) { + if centerIndex + count < -1 || line.count < centerIndex + count { + debug("CursorBarState.move rejected", centerIndex, count, line) + return + } displayLeftIndex += count displayRightIndex += count actionManager.registerAction(.moveCursor(count), variableStates: variableStates) @@ -67,7 +71,6 @@ struct SliderStyleCursorBarState: Equatable { } } -@MainActor struct ReflectStyleCursorBar: View { init() {} @@ -75,23 +78,30 @@ struct ReflectStyleCursorBar= 15 { - variableStates.moveCursorBarState.move(1, actionManager: self.action, variableStates: variableStates) + cursorBarState.move(1, actionManager: self.action, variableStates: variableStates) count -= 15 } if count <= -15 { - variableStates.moveCursorBarState.move(-1, actionManager: self.action, variableStates: variableStates) + cursorBarState.move(-1, actionManager: self.action, variableStates: variableStates) count += 15 } swipeGestureState = .moving(l1: value.location, l2: l1, l3: l2, count: count) @@ -159,9 +169,9 @@ struct ReflectStyleCursorBar [ActionType] { + if self.composingText.isEmpty { + return [.setCursorBar(.on)] + } + self.stopComposition() + return [] + } + /// ユーザがキーボードを経由せずカットした場合の処理 func userCutText(text: String) { self.stopComposition() diff --git a/Keyboard/Display/KeyboardActionManager.swift b/Keyboard/Display/KeyboardActionManager.swift index 7f9dbae4..fdbc4ef8 100644 --- a/Keyboard/Display/KeyboardActionManager.swift +++ b/Keyboard/Display/KeyboardActionManager.swift @@ -524,7 +524,6 @@ import SwiftUtils /// 何かが変化した後に状態を比較し、どのような変化が起こったのか判断する関数。 override func notifySomethingDidChange(a_left: String, a_center: String, a_right: String, variableStates: VariableStates) { defer { - // moveCursorBarStateの更新 variableStates.setSurroundingText(leftSide: a_left, center: a_center, rightSide: a_right) // エンターキーの状態の更新 variableStates.setEnterKeyState(self.inputManager.getEnterKeyState()) @@ -669,9 +668,10 @@ import SwiftUtils return } - // 上記のどれにも引っかからず、なおかつテキスト全体が変更された場合 + // 上記のどれにも引っかからず、なおかつテキスト全体が変更された場合→ユーザがカーソルをジャンプした debug("user operation id: 10, \((a_left, a_center, a_right)), \((b_left, b_center, b_right))") - self.inputManager.stopComposition() + let actions = self.inputManager.userJumpedCursor() + self.registerActions(actions, variableStates: variableStates) } private func hideLearningMemory() { From 58ba1fe657272ea9bf2fc131830dc17c44e2b39a Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 19 Oct 2023 01:02:24 +0900 Subject: [PATCH 099/124] =?UTF-8?q?MainActor=E3=81=A7=E5=AE=9F=E8=A1=8C?= =?UTF-8?q?=E3=81=99=E3=82=8B=E5=87=A6=E7=90=86=E3=81=A8=E3=81=9D=E3=81=86?= =?UTF-8?q?=E3=81=A7=E3=81=AA=E3=81=84=E5=87=A6=E7=90=86=E3=82=92=E5=88=86?= =?UTF-8?q?=E5=88=A5=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyboardViews/KeyboardFeedback.swift | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift b/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift index e18bece5..94b212b1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift +++ b/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift @@ -7,22 +7,26 @@ // import func AudioToolbox.AudioServicesPlaySystemSound -import Foundation +import typealias AudioToolbox.SystemSoundID import class UIKit.UIImpactFeedbackGenerator /// フィードバックを返すためのツールセット -@MainActor public enum KeyboardFeedback { +public enum KeyboardFeedback { + @MainActor private static var enableSound: Bool { Extension.SettingProvider.enableSound } + @MainActor private static var requestedHaptics: Bool { Extension.SettingProvider.enableHaptics } + @MainActor private static var enableHaptics: Bool { SemiStaticStates.shared.hapticsAvailable && SemiStaticStates.shared.hasFullAccess && requestedHaptics } // FIXME: possibly too heavy - private static var generator: UIImpactFeedbackGenerator { UIImpactFeedbackGenerator(style: .light) } + @MainActor + private static var generator: UIImpactFeedbackGenerator { UIImpactFeedbackGenerator(style: .light) } // 使えそうな音 /* i @@ -42,53 +46,54 @@ import class UIKit.UIImpactFeedbackGenerator /// 入力を伴う操作を行う際にフィードバックを返します。 /// - Note: 押しはじめに鳴らす方が反応が良く感じます。 public static func click() { - if enableSound { - AudioServicesPlaySystemSound(1104) - } - if enableHaptics { - generator.impactOccurred(intensity: 0.7) - } + playSystemSound(1104) + impactOnMainActor(intensity: 0.7) } /// タブの移動、入力の確定、小仮名濁点化、カーソル移動などを伴う操作を行う際にフィードバックを返します。 /// - Note: 押しはじめに鳴らす方が反応が良く感じます。 public static func tabOrOtherKey() { - if enableSound { - AudioServicesPlaySystemSound(1156) - } - if enableHaptics { - generator.impactOccurred(intensity: 0.75) - } + playSystemSound(1156) + impactOnMainActor(intensity: 0.75) } /// 文字の削除などを伴う操作を行う際に音を鳴らします。 /// - Note: 押しはじめに鳴らす方が反応が良く感じます。 public static func delete() { - if enableSound { - AudioServicesPlaySystemSound(1155) - } - if enableHaptics { - generator.impactOccurred(intensity: 0.75) - } + playSystemSound(1155) + impactOnMainActor(intensity: 0.75) } /// 文字の一括削除の操作を行う際にフィードバックを返します。 public static func smoothDelete() { - if enableSound { - AudioServicesPlaySystemSound(1105) - } - if enableHaptics { - generator.impactOccurred(intensity: 0.8) - } + playSystemSound(1105) + impactOnMainActor(intensity: 0.8) } /// 操作のリセットを行うときにフィードバックを返します。 public static func reset() { - if enableSound { - AudioServicesPlaySystemSound(1533) + playSystemSound(1533) + impactOnMainActor(intensity: 1) + } + + /// systemSoundの再生のラッパー + /// - Note: `generator.impactOccurred`はMainActor上でのみ動作する + public static func impactOnMainActor(intensity: Double) { + Task { @MainActor in + if enableHaptics { + generator.impactOccurred(intensity: intensity) + } } - if enableHaptics { - generator.impactOccurred(intensity: 1) + } + + /// systemSoundの再生のラッパー + /// - Note: `AudioServicesPlaySystemSound`は非同期で呼び出さないと爆音が鳴ることがある + public static func playSystemSound(_ id: SystemSoundID) { + Task { + if await enableSound { + // 再生自体は非同期で実行される + AudioServicesPlaySystemSound(id) + } } } } From 113a115078b98a8b7190d0160382f902870145ed Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 19 Oct 2023 01:10:27 +0900 Subject: [PATCH 100/124] Avoid multiple initialization of UIImpactFeedbackGenerator --- AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift b/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift index 94b212b1..6148cf69 100644 --- a/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift +++ b/AzooKeyCore/Sources/KeyboardViews/KeyboardFeedback.swift @@ -10,6 +10,9 @@ import func AudioToolbox.AudioServicesPlaySystemSound import typealias AudioToolbox.SystemSoundID import class UIKit.UIImpactFeedbackGenerator +private enum UIImpactFeedbackGeneratorHolder { + @MainActor static let generator = UIImpactFeedbackGenerator(style: .light) +} /// フィードバックを返すためのツールセット public enum KeyboardFeedback { @MainActor @@ -24,9 +27,6 @@ public enum KeyboardFeedback Date: Thu, 19 Oct 2023 03:49:18 +0900 Subject: [PATCH 101/124] =?UTF-8?q?=E7=8F=BE=E7=8A=B6=E3=81=AE=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=82=92=E7=A7=BB=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移植元とのバージョン違いによるエラー --- .../SuggestView/FlickSuggestView.swift | 225 ++++++++++++++---- 1 file changed, 179 insertions(+), 46 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 8cb23cd4..6d98bcb9 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -18,70 +18,203 @@ struct FlickSuggestView: Vi private let suggestType: FlickSuggestType private let tabDesign: TabDependentDesign private let size: CGSize - + init(model: any FlickKeyModelProtocol, tabDesign: TabDependentDesign, size: CGSize, suggestType: FlickSuggestType) { self.model = model self.tabDesign = tabDesign self.size = size self.suggestType = suggestType } - - private func getSuggestView(for model: FlickedKeyModel, isHidden: Bool, isPointed: Bool = false) -> some View { - // 着せ替えが有効の場合、サジェストの背景色はwhiteにする。 + + private func getSuggestView(for _: FlickedKeyModel, isHidden: Bool, isPointed: Bool = false) -> some View { + // ポインテッド時の色を定義 var pointedColor: Color { - theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray4 + theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .white } + // ポインテッドでない時の色を定義 var unpointedColor: Color { theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray5 } - + + // 現在の状態に基づいて色を選択 let color = isPointed ? pointedColor : unpointedColor - return RoundedRectangle(cornerRadius: 5.0) - .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth) - .frame(width: size.width, height: size.height) - .overlay { - // ラベル - KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color) + let shape: any Shape + let paddings: [CGFloat] + let spacers: [CGFloat] + let sizeTimes: [CGFloat] + + switch direction { + case .top: + shape = RoundedPentagonTop() + paddings = [0, 0, 0.2, 0] + spacers = [0, 0, 0, 0.25] + sizeTimes = [1.2, 1.5] + case .left: + shape = RoundedPentagonLeft() + paddings = [0, 0, 0, 0.3] + spacers = [0, 0, 0.1, 0] + sizeTimes = [1.5, 1.2] + case .right: + shape = RoundedPentagonRight() + paddings = [0, 0.3, 0, 0] + spacers = [0, 0.1, 0, 0] + sizeTimes = [1.5, 1.2] + case .bottom: + shape = RoundedPentagonBottom() + paddings = [0.2, 0, 0, 0] + spacers = [0.25, 0, 0, 0] + sizeTimes = [1.2, 1.5] + } + + return VStack { + Spacer().frame(height: size.height * spacers[0]) + HStack { + Spacer().frame(width: size.width * spacers[1]) + AnyView(shape + .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth)) + .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) + .shadow(color: Color.gray, radius: 10, x: 5, y: 5) + .overlay(self.label(width: size.width, theme: theme, extension: Extension.self).padding(EdgeInsets(top: size.width * paddings[0], leading: size.width * paddings[1], bottom: size.width * paddings[2], trailing: size.width * paddings[3]))) + .allowsHitTesting(false) + .opacity(isHidden ? 0 : 1) + Spacer().frame(width: size.width * spacers[2]) } - .allowsHitTesting(false) - .opacity(isHidden ? 0 : 1) - } - - /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 - @ViewBuilder private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { - switch self.suggestType { - case .all: - if let model = self.model.flickKeys(variableStates: variableStates)[direction] { - getSuggestView(for: model, isHidden: false) - } else { - getSuggestView(for: .empty, isHidden: true) + } + + /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 + @ViewBuilder private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { + switch suggestType { + case .all: + if let model = model.flickKeys(variableStates: variableStates)[direction] { + getSuggestView(for: model, isHidden: false) + } else { + getSuggestView(for: .empty, isHidden: true) + } + case .flick(let targetDirection): + if targetDirection == direction, let model = model.flickKeys(variableStates: variableStates)[direction] { + getSuggestView(for: model, isHidden: false, isPointed: true) + } else { + getSuggestView(for: .empty, isHidden: true) + } } - case .flick(let targetDirection): - if targetDirection == direction, let model = self.model.flickKeys(variableStates: variableStates)[direction] { - getSuggestView(for: model, isHidden: false, isPointed: true) - } else { - getSuggestView(for: .empty, isHidden: true) + } + + var body: some View { + VStack(spacing: tabDesign.verticalSpacing) { + self.getSuggestViewIfNecessary(direction: .top) + HStack(spacing: tabDesign.horizontalSpacing) { + self.getSuggestViewIfNecessary(direction: .left) + RoundedRectangle(cornerRadius: 5.0) + .strokeAndFill( + fillContent: theme.specialKeyFillColor.color, + strokeContent: theme.borderColor.color, + lineWidth: theme.borderWidth + ) + .frame(width: size.width, height: size.height) + self.getSuggestViewIfNecessary(direction: .right) + } + self.getSuggestViewIfNecessary(direction: .bottom) } + .frame(width: size.width, height: size.height) + .allowsHitTesting(false) } } - - var body: some View { - VStack(spacing: tabDesign.verticalSpacing) { - self.getSuggestViewIfNecessary(direction: .top) - HStack(spacing: tabDesign.horizontalSpacing) { - self.getSuggestViewIfNecessary(direction: .left) - RoundedRectangle(cornerRadius: 5.0) - .strokeAndFill( - fillContent: theme.specialKeyFillColor.color, - strokeContent: theme.borderColor.color, - lineWidth: theme.borderWidth - ) - .frame(width: size.width, height: size.height) - self.getSuggestViewIfNecessary(direction: .right) +} + +public extension Path { + mutating func addRoundedPentagon(using points: [CGPoint], cornerRadius: CGFloat = 5) { + guard points.count == 5 else { return } + + for i in 0 ..< 5 { + let currentPoint = points[i] + let nextPoint = points[(i + 1) % 5] + let prevPoint = i == 0 ? points.last! : points[i - 1] + + let directionFromPrev = CGVector(dx: currentPoint.x - prevPoint.x, dy: currentPoint.y - prevPoint.y).normalized + let directionToNext = CGVector(dx: nextPoint.x - currentPoint.x, dy: nextPoint.y - currentPoint.y).normalized + + let offsetFromCurrent1 = CGVector(dx: directionFromPrev.dx * cornerRadius, dy: directionFromPrev.dy * cornerRadius) + let offsetFromCurrent2 = CGVector(dx: directionToNext.dx * cornerRadius, dy: directionToNext.dy * cornerRadius) + + if i == 0 { + move(to: CGPoint(x: currentPoint.x - offsetFromCurrent1.dx, y: currentPoint.y - offsetFromCurrent1.dy)) + } else { + addLine(to: CGPoint(x: currentPoint.x - offsetFromCurrent1.dx, y: currentPoint.y - offsetFromCurrent1.dy)) } - self.getSuggestViewIfNecessary(direction: .bottom) + + addQuadCurve(to: CGPoint(x: currentPoint.x + offsetFromCurrent2.dx, y: currentPoint.y + offsetFromCurrent2.dy), control: currentPoint) } - .frame(width: size.width, height: size.height) - .allowsHitTesting(false) + + closeSubpath() + } +} + +extension CGVector { + var length: CGFloat { + return sqrt(dx * dx + dy * dy) + } + + var normalized: CGVector { + return CGVector(dx: dx / length, dy: dy / length) + } +} + +struct RoundedPentagonBottom: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let points = [ + CGPoint(x: rect.width / 2, y: 0), + CGPoint(x: 0, y: rect.height / 3), + CGPoint(x: 0, y: rect.height), + CGPoint(x: rect.width, y: rect.height), + CGPoint(x: rect.width, y: rect.height / 3) + ] + path.addRoundedPentagon(using: points) + return path + } +} + +struct RoundedPentagonLeft: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let points = [ + CGPoint(x: 0, y: 0), + CGPoint(x: rect.width * 2 / 3, y: 0), + CGPoint(x: rect.width, y: rect.height / 2), + CGPoint(x: rect.width * 2 / 3, y: rect.height), + CGPoint(x: 0, y: rect.height) + ] + path.addRoundedPentagon(using: points) + return path + } +} + +struct RoundedPentagonRight: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let points = [ + CGPoint(x: rect.width / 3, y: 0), + CGPoint(x: 0, y: rect.height / 2), + CGPoint(x: rect.width / 3, y: rect.height), + CGPoint(x: rect.width, y: rect.height), + CGPoint(x: rect.width, y: 0) + ] + path.addRoundedPentagon(using: points) + return path + } +} + +struct RoundedPentagonTop: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let points = [ + CGPoint(x: rect.width / 2, y: rect.height), + CGPoint(x: rect.width, y: 2 * rect.height / 3), + CGPoint(x: rect.width, y: 0), + CGPoint(x: 0, y: 0), + CGPoint(x: 0, y: 2 * rect.height / 3) + ] + path.addRoundedPentagon(using: points) + return path } } From 0f02934c681042fc81043a0907d19eba7d27e333 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 19 Oct 2023 23:48:14 +0900 Subject: [PATCH 102/124] =?UTF-8?q?=E3=83=93=E3=83=AB=E3=83=89=E3=82=92?= =?UTF-8?q?=E9=80=9A=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SuggestView/FlickSuggestView.swift | 88 ++++++++++--------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 6d98bcb9..d1bffd32 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -26,7 +26,7 @@ struct FlickSuggestView: Vi self.suggestType = suggestType } - private func getSuggestView(for _: FlickedKeyModel, isHidden: Bool, isPointed: Bool = false) -> some View { + private func getSuggestView(for model: FlickedKeyModel, direction: FlickDirection, isHidden: Bool, isPointed: Bool = false) -> some View { // ポインテッド時の色を定義 var pointedColor: Color { theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .white @@ -72,53 +72,61 @@ struct FlickSuggestView: Vi Spacer().frame(width: size.width * spacers[1]) AnyView(shape .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth)) - .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) - .shadow(color: Color.gray, radius: 10, x: 5, y: 5) - .overlay(self.label(width: size.width, theme: theme, extension: Extension.self).padding(EdgeInsets(top: size.width * paddings[0], leading: size.width * paddings[1], bottom: size.width * paddings[2], trailing: size.width * paddings[3]))) - .allowsHitTesting(false) - .opacity(isHidden ? 0 : 1) + .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) + .shadow(color: Color.gray, radius: 10, x: 5, y: 5) + .overlay { + KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color) + .padding(EdgeInsets( + top: size.width * paddings[0], + leading: size.width * paddings[1], + bottom: size.width * paddings[2], + trailing: size.width * paddings[3] + )) + } + .allowsHitTesting(false) + .opacity(isHidden ? 0 : 1) Spacer().frame(width: size.width * spacers[2]) } } - - /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 - @ViewBuilder private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { - switch suggestType { - case .all: - if let model = model.flickKeys(variableStates: variableStates)[direction] { - getSuggestView(for: model, isHidden: false) - } else { - getSuggestView(for: .empty, isHidden: true) - } - case .flick(let targetDirection): - if targetDirection == direction, let model = model.flickKeys(variableStates: variableStates)[direction] { - getSuggestView(for: model, isHidden: false, isPointed: true) - } else { - getSuggestView(for: .empty, isHidden: true) - } + } + /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 + @ViewBuilder private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { + switch suggestType { + case .all: + if let model = self.model.flickKeys(variableStates: variableStates)[direction] { + getSuggestView(for: model, direction: direction, isHidden: false) + } else { + getSuggestView(for: .empty, direction: direction, isHidden: true) + } + case .flick(let targetDirection): + if targetDirection == direction, let model = self.model.flickKeys(variableStates: variableStates)[direction] { + getSuggestView(for: model, direction: direction, isHidden: false, isPointed: true) + } else { + getSuggestView(for: .empty, direction: direction, isHidden: true) } } - - var body: some View { - VStack(spacing: tabDesign.verticalSpacing) { - self.getSuggestViewIfNecessary(direction: .top) - HStack(spacing: tabDesign.horizontalSpacing) { - self.getSuggestViewIfNecessary(direction: .left) - RoundedRectangle(cornerRadius: 5.0) - .strokeAndFill( - fillContent: theme.specialKeyFillColor.color, - strokeContent: theme.borderColor.color, - lineWidth: theme.borderWidth - ) - .frame(width: size.width, height: size.height) - self.getSuggestViewIfNecessary(direction: .right) - } - self.getSuggestViewIfNecessary(direction: .bottom) + } + + var body: some View { + VStack(spacing: tabDesign.verticalSpacing) { + self.getSuggestViewIfNecessary(direction: .top) + HStack(spacing: tabDesign.horizontalSpacing) { + self.getSuggestViewIfNecessary(direction: .left) + RoundedRectangle(cornerRadius: 5.0) + .strokeAndFill( + fillContent: theme.specialKeyFillColor.color, + strokeContent: theme.borderColor.color, + lineWidth: theme.borderWidth + ) + .frame(width: size.width, height: size.height) + self.getSuggestViewIfNecessary(direction: .right) } - .frame(width: size.width, height: size.height) - .allowsHitTesting(false) + self.getSuggestViewIfNecessary(direction: .bottom) } + .frame(width: size.width, height: size.height) + .allowsHitTesting(false) } + } public extension Path { From a37f8cbdc4e20ece5c4edc31b797685e9461b79a Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 19 Oct 2023 23:49:10 +0900 Subject: [PATCH 103/124] adjust access control --- .../FlickKeyboard/SuggestView/FlickSuggestView.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index d1bffd32..1819607e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -129,7 +129,7 @@ struct FlickSuggestView: Vi } -public extension Path { +private extension Path { mutating func addRoundedPentagon(using points: [CGPoint], cornerRadius: CGFloat = 5) { guard points.count == 5 else { return } @@ -157,7 +157,7 @@ public extension Path { } } -extension CGVector { +private extension CGVector { var length: CGFloat { return sqrt(dx * dx + dy * dy) } @@ -167,7 +167,7 @@ extension CGVector { } } -struct RoundedPentagonBottom: Shape { +private struct RoundedPentagonBottom: Shape { func path(in rect: CGRect) -> Path { var path = Path() let points = [ @@ -182,7 +182,7 @@ struct RoundedPentagonBottom: Shape { } } -struct RoundedPentagonLeft: Shape { +private struct RoundedPentagonLeft: Shape { func path(in rect: CGRect) -> Path { var path = Path() let points = [ @@ -197,7 +197,7 @@ struct RoundedPentagonLeft: Shape { } } -struct RoundedPentagonRight: Shape { +private struct RoundedPentagonRight: Shape { func path(in rect: CGRect) -> Path { var path = Path() let points = [ @@ -212,7 +212,7 @@ struct RoundedPentagonRight: Shape { } } -struct RoundedPentagonTop: Shape { +private struct RoundedPentagonTop: Shape { func path(in rect: CGRect) -> Path { var path = Path() let points = [ From e10c07aa96e7be00e1d6691af43e80942609026f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Thu, 19 Oct 2023 23:53:51 +0900 Subject: [PATCH 104/124] Add missing space --- .../View/FlickKeyboard/SuggestView/FlickSuggestView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 1819607e..d06963fe 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -87,6 +87,7 @@ struct FlickSuggestView: Vi .opacity(isHidden ? 0 : 1) Spacer().frame(width: size.width * spacers[2]) } + Spacer().frame(height: size.height * spacers[3]) } } /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 From 65adfd5ce88f9f87f24fb922ff44cbbe77ff04f6 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 20 Oct 2023 00:20:41 +0900 Subject: [PATCH 105/124] Adjust colors --- .../SuggestView/FlickSuggestView.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index d06963fe..ad4022fe 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -14,6 +14,7 @@ import SwiftUI struct FlickSuggestView: View { @EnvironmentObject private var variableStates: VariableStates @Environment(Extension.Theme.self) private var theme + @Environment(\.colorScheme) private var colorScheme private let model: any FlickKeyModelProtocol private let suggestType: FlickSuggestType private let tabDesign: TabDependentDesign @@ -29,13 +30,19 @@ struct FlickSuggestView: Vi private func getSuggestView(for model: FlickedKeyModel, direction: FlickDirection, isHidden: Bool, isPointed: Bool = false) -> some View { // ポインテッド時の色を定義 var pointedColor: Color { - theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .white + theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray4 } // ポインテッドでない時の色を定義 var unpointedColor: Color { theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray5 } - + var shadowColor: Color { + if colorScheme == .dark || theme != Extension.ThemeExtension.default(layout: .flick) { + .clear + } else { + .gray + } + } // 現在の状態に基づいて色を選択 let color = isPointed ? pointedColor : unpointedColor let shape: any Shape @@ -73,7 +80,7 @@ struct FlickSuggestView: Vi AnyView(shape .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth)) .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) - .shadow(color: Color.gray, radius: 10, x: 5, y: 5) + .shadow(color: shadowColor, radius: 10, x: 5, y: 5) .overlay { KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color) .padding(EdgeInsets( From b8c5c944c69372a8bd82a4bba0f3ebcaad03326f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 20 Oct 2023 00:28:21 +0900 Subject: [PATCH 106/124] Adjust colors --- .../View/FlickKeyboard/SuggestView/FlickSuggestView.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index ad4022fe..32321d69 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -30,7 +30,11 @@ struct FlickSuggestView: Vi private func getSuggestView(for model: FlickedKeyModel, direction: FlickDirection, isHidden: Bool, isPointed: Bool = false) -> some View { // ポインテッド時の色を定義 var pointedColor: Color { - theme != Extension.ThemeExtension.default(layout: .flick) ? .white : .systemGray4 + if colorScheme == .light || theme != Extension.ThemeExtension.default(layout: .flick) { + .white + } else { + .systemGray4 + } } // ポインテッドでない時の色を定義 var unpointedColor: Color { From 20c3093dfd3c71a1d6c902526a1e457ff3af872f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 20 Oct 2023 10:30:08 +0900 Subject: [PATCH 107/124] adjust suggest positioning --- .../SuggestView/FlickSuggestView.swift | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 32321d69..9efd8b09 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -51,58 +51,45 @@ struct FlickSuggestView: Vi let color = isPointed ? pointedColor : unpointedColor let shape: any Shape let paddings: [CGFloat] - let spacers: [CGFloat] let sizeTimes: [CGFloat] switch direction { case .top: shape = RoundedPentagonTop() - paddings = [0, 0, 0.2, 0] - spacers = [0, 0, 0, 0.25] + paddings = [0, 0, 0.3, 0] sizeTimes = [1.2, 1.5] case .left: shape = RoundedPentagonLeft() paddings = [0, 0, 0, 0.3] - spacers = [0, 0, 0.1, 0] sizeTimes = [1.5, 1.2] case .right: shape = RoundedPentagonRight() paddings = [0, 0.3, 0, 0] - spacers = [0, 0.1, 0, 0] sizeTimes = [1.5, 1.2] case .bottom: shape = RoundedPentagonBottom() - paddings = [0.2, 0, 0, 0] - spacers = [0.25, 0, 0, 0] + paddings = [0.3, 0, 0, 0] sizeTimes = [1.2, 1.5] } - return VStack { - Spacer().frame(height: size.height * spacers[0]) - HStack { - Spacer().frame(width: size.width * spacers[1]) - AnyView(shape + return AnyView(shape .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth)) .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) - .shadow(color: shadowColor, radius: 10, x: 5, y: 5) + .shadow(color: shadowColor, radius: 10, y: 5) .overlay { KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color) .padding(EdgeInsets( - top: size.width * paddings[0], + top: size.height * paddings[0], leading: size.width * paddings[1], - bottom: size.width * paddings[2], + bottom: size.height * paddings[2], trailing: size.width * paddings[3] )) } .allowsHitTesting(false) .opacity(isHidden ? 0 : 1) - Spacer().frame(width: size.width * spacers[2]) - } - Spacer().frame(height: size.height * spacers[3]) - } } /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 - @ViewBuilder private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { + private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { switch suggestType { case .all: if let model = self.model.flickKeys(variableStates: variableStates)[direction] { @@ -122,8 +109,12 @@ struct FlickSuggestView: Vi var body: some View { VStack(spacing: tabDesign.verticalSpacing) { self.getSuggestViewIfNecessary(direction: .top) + .offset(y: size.height / 2) + .zIndex(1) HStack(spacing: tabDesign.horizontalSpacing) { self.getSuggestViewIfNecessary(direction: .left) + .offset(x: size.width / 2) + .zIndex(1) RoundedRectangle(cornerRadius: 5.0) .strokeAndFill( fillContent: theme.specialKeyFillColor.color, @@ -131,9 +122,14 @@ struct FlickSuggestView: Vi lineWidth: theme.borderWidth ) .frame(width: size.width, height: size.height) + .zIndex(0) self.getSuggestViewIfNecessary(direction: .right) + .offset(x: -size.width / 2) + .zIndex(1) } self.getSuggestViewIfNecessary(direction: .bottom) + .offset(y: -size.height / 2) + .zIndex(1) } .frame(width: size.width, height: size.height) .allowsHitTesting(false) From 5c1543bcba8f33c1ac9742790a984c1e1f23df8f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 20 Oct 2023 23:52:17 +0900 Subject: [PATCH 108/124] Complete better suggest implementation --- .../Sources/KeyboardViews/Design.swift | 3 + .../View/Components/KeyLabel.swift | 13 +- .../View/CustomKeybaord/CustomKeyboard.swift | 13 +- .../SuggestView/FlickSuggestView.swift | 156 +++++++++++++----- 4 files changed, 144 insertions(+), 41 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/Design.swift b/AzooKeyCore/Sources/KeyboardViews/Design.swift index eddb7661..d99844ad 100644 --- a/AzooKeyCore/Sources/KeyboardViews/Design.swift +++ b/AzooKeyCore/Sources/KeyboardViews/Design.swift @@ -265,6 +265,7 @@ public enum Design { enum LabelFontSizeStrategy { case max + case xlarge case large case medium case small @@ -272,6 +273,8 @@ public enum Design { var scale: CGFloat { switch self { + case .xlarge: + return 1.2 case .large, .max: return 1 case .medium: diff --git a/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift b/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift index 156b5c32..0e3ac007 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/Components/KeyLabel.swift @@ -22,8 +22,8 @@ public enum KeyLabelType { public struct KeyLabel: View { private let labelType: KeyLabelType private let width: CGFloat - private let textColor: Color? - private let textSize: Design.Fonts.LabelFontSizeStrategy + private var textColor: Color? + private var textSize: Design.Fonts.LabelFontSizeStrategy @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action @EnvironmentObject private var variableStates: VariableStates @@ -99,4 +99,13 @@ public struct KeyLabel: Vie }.allowsHitTesting(false) } } + + consuming func textColor(_ color: Color?) -> Self { + self.textColor = color + return self + } + consuming func textSize(_ textSize: Design.Fonts.LabelFontSizeStrategy) -> Self { + self.textSize = textSize + return self + } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index 3be6497f..cc73e68f 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -359,22 +359,31 @@ public struct CustardFlickKeysView(model: data.model, tabDesign: tabDesign, size: info.size, suggestType: suggestType) .zIndex(2) } } .position(x: info.position.x, y: info.position.y) + .blur(radius: needBlur ? 0.75 : 0) } } .zIndex(columnSuggestStates.isEmpty ? 0 : 1) + .blur(radius: needColumnWideBlur ? 0.75 : 0) } .frame(width: tabDesign.keysWidth, height: tabDesign.keysHeight) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 9efd8b09..45196e63 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -26,8 +26,16 @@ struct FlickSuggestView: Vi self.size = size self.suggestType = suggestType } - - private func getSuggestView(for model: FlickedKeyModel, direction: FlickDirection, isHidden: Bool, isPointed: Bool = false) -> some View { + + @ViewBuilder + private func keyLabel(for direction: FlickDirection, textColor: Color? = nil, textSize: Design.Fonts.LabelFontSizeStrategy = .xlarge) -> some View { + if let model = self.model.flickKeys(variableStates: variableStates)[direction] { + KeyLabel(model.labelType, width: size.width, textSize: textSize, textColor: textColor) + } else { + EmptyView() + } + } + private func getSuggestView(direction: FlickDirection, isHidden: Bool, isPointed: Bool) -> some View { // ポインテッド時の色を定義 var pointedColor: Color { if colorScheme == .light || theme != Extension.ThemeExtension.default(layout: .flick) { @@ -77,7 +85,7 @@ struct FlickSuggestView: Vi .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) .shadow(color: shadowColor, radius: 10, y: 5) .overlay { - KeyLabel(model.labelType, width: size.width, textColor: theme.suggestLabelTextColor?.color) + self.keyLabel(for: direction, textColor: theme.suggestLabelTextColor?.color) .padding(EdgeInsets( top: size.height * paddings[0], leading: size.width * paddings[1], @@ -89,50 +97,124 @@ struct FlickSuggestView: Vi .opacity(isHidden ? 0 : 1) } /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 - private func getSuggestViewIfNecessary(direction: FlickDirection) -> some View { - switch suggestType { - case .all: - if let model = self.model.flickKeys(variableStates: variableStates)[direction] { - getSuggestView(for: model, direction: direction, isHidden: false) - } else { - getSuggestView(for: .empty, direction: direction, isHidden: true) - } - case .flick(let targetDirection): - if targetDirection == direction, let model = self.model.flickKeys(variableStates: variableStates)[direction] { - getSuggestView(for: model, direction: direction, isHidden: false, isPointed: true) + @ViewBuilder + private func getPointedSuggestViewIfNecessary(direction: FlickDirection, targetDirection: FlickDirection) -> some View { + if targetDirection == direction { + getSuggestView(direction: direction, isHidden: false, isPointed: true) + } else { + getSuggestView(direction: direction, isHidden: true, isPointed: false) + } + } + + @ViewBuilder + private func roundedRectangleForAllSuggest(cornerRadius: CGFloat, direction: FlickDirection, sizeDiff: CGFloat = 2) -> some View { + var color: Color { + if colorScheme == .light || theme != Extension.ThemeExtension.default(layout: .flick) { + .white } else { - getSuggestView(for: .empty, direction: direction, isHidden: true) + .systemGray4 } } + let widthDiff: CGFloat = switch direction { + case .top, .bottom: tabDesign.horizontalSpacing + case .left, .right: tabDesign.horizontalSpacing / 2 + cornerRadius + sizeDiff + } + let heightDiff: CGFloat = switch direction { + case .top, .bottom: tabDesign.verticalSpacing / 2 + cornerRadius + sizeDiff + case .left, .right: tabDesign.verticalSpacing + } + let isHidden = !self.model.isFlickAble(to: direction, variableStates: variableStates) + RoundedRectangle(cornerRadius: cornerRadius) + .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth) + .frame(width: size.width + widthDiff, height: size.height + heightDiff) + .overlay { + let offsetX: CGFloat = switch direction { + case .bottom, .top: 0 + case .left: -cornerRadius + sizeDiff/2 + case .right: cornerRadius - sizeDiff/2 + } + let offsetY: CGFloat = switch direction { + case .left, .right: 0 + case .top: -cornerRadius + sizeDiff/2 + case .bottom: cornerRadius - sizeDiff/2 + } + self.keyLabel(for: direction, textColor: theme.suggestLabelTextColor?.color) + .offset(x: offsetX, y: offsetY) + } + .opacity(isHidden ? 0 : 1) } var body: some View { - VStack(spacing: tabDesign.verticalSpacing) { - self.getSuggestViewIfNecessary(direction: .top) - .offset(y: size.height / 2) - .zIndex(1) - HStack(spacing: tabDesign.horizontalSpacing) { - self.getSuggestViewIfNecessary(direction: .left) - .offset(x: size.width / 2) + switch self.suggestType { + case .all: + let cornerRadius = 5.0 + VStack(spacing: 0) { + roundedRectangleForAllSuggest(cornerRadius: cornerRadius, direction: .top) + .offset(y: cornerRadius) .zIndex(1) - RoundedRectangle(cornerRadius: 5.0) - .strokeAndFill( - fillContent: theme.specialKeyFillColor.color, - strokeContent: theme.borderColor.color, - lineWidth: theme.borderWidth - ) - .frame(width: size.width, height: size.height) - .zIndex(0) - self.getSuggestViewIfNecessary(direction: .right) - .offset(x: -size.width / 2) + HStack(spacing: 0) { + roundedRectangleForAllSuggest(cornerRadius: cornerRadius, direction: .left) + .offset(x: cornerRadius) + .zIndex(1) + Rectangle() + .strokeAndFill( + fillContent: .blue, + strokeContent: .gray, + lineWidth: 0.5 + ) + .frame( + width: size.width + tabDesign.horizontalSpacing, + height: size.height + tabDesign.verticalSpacing + ) + .zIndex(2) + .overlay { + (self.model.label(width: size.width, states: variableStates) as KeyLabel) + .textColor(.white) + .textSize(.xlarge) + } + roundedRectangleForAllSuggest(cornerRadius: cornerRadius, direction: .right) + .offset(x: -cornerRadius) + .zIndex(1) + } + .zIndex(2) + .frame(width: size.width + tabDesign.horizontalSpacing, height: size.height + tabDesign.verticalSpacing) + roundedRectangleForAllSuggest(cornerRadius: cornerRadius, direction: .bottom) + .offset(y: -cornerRadius) + .zIndex(1) + } + .compositingGroup() + .shadow(color: .gray, radius: 3) + .frame(width: size.width, height: size.height) + .allowsHitTesting(false) + case .flick(let targetDirection): + VStack(spacing: tabDesign.verticalSpacing) { + self.getPointedSuggestViewIfNecessary(direction: .top, targetDirection: targetDirection) + .offset(y: size.height / 2) + .zIndex(1) + HStack(spacing: tabDesign.horizontalSpacing) { + self.getPointedSuggestViewIfNecessary(direction: .left, targetDirection: targetDirection) + .offset(x: size.width / 2) + .zIndex(1) + RoundedRectangle(cornerRadius: 5.0) + .strokeAndFill( + fillContent: theme.specialKeyFillColor.color, + strokeContent: theme.borderColor.color, + lineWidth: theme.borderWidth + ) + .frame(width: size.width, height: size.height) + .zIndex(0) + self.getPointedSuggestViewIfNecessary(direction: .right, targetDirection: targetDirection) + .offset(x: -size.width / 2) + .zIndex(1) + } + .frame(width: size.width, height: size.height) + self.getPointedSuggestViewIfNecessary(direction: .bottom, targetDirection: targetDirection) + .offset(y: -size.height / 2) .zIndex(1) } - self.getSuggestViewIfNecessary(direction: .bottom) - .offset(y: -size.height / 2) - .zIndex(1) + .frame(width: size.width, height: size.height) + .allowsHitTesting(false) } - .frame(width: size.width, height: size.height) - .allowsHitTesting(false) } } From c4e30f5ba73322eade88c636ced8c81742addb17 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 20 Oct 2023 23:59:27 +0900 Subject: [PATCH 109/124] format --- .../SuggestView/FlickSuggestView.swift | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift index 45196e63..d4646ba7 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/SuggestView/FlickSuggestView.swift @@ -19,7 +19,7 @@ struct FlickSuggestView: Vi private let suggestType: FlickSuggestType private let tabDesign: TabDependentDesign private let size: CGSize - + init(model: any FlickKeyModelProtocol, tabDesign: TabDependentDesign, size: CGSize, suggestType: FlickSuggestType) { self.model = model self.tabDesign = tabDesign @@ -60,7 +60,7 @@ struct FlickSuggestView: Vi let shape: any Shape let paddings: [CGFloat] let sizeTimes: [CGFloat] - + switch direction { case .top: shape = RoundedPentagonTop() @@ -79,22 +79,21 @@ struct FlickSuggestView: Vi paddings = [0.3, 0, 0, 0] sizeTimes = [1.2, 1.5] } - - return AnyView(shape - .strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth)) - .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) - .shadow(color: shadowColor, radius: 10, y: 5) - .overlay { - self.keyLabel(for: direction, textColor: theme.suggestLabelTextColor?.color) - .padding(EdgeInsets( - top: size.height * paddings[0], - leading: size.width * paddings[1], - bottom: size.height * paddings[2], - trailing: size.width * paddings[3] - )) - } - .allowsHitTesting(false) - .opacity(isHidden ? 0 : 1) + + return AnyView(shape.strokeAndFill(fillContent: color, strokeContent: theme.borderColor.color, lineWidth: theme.borderWidth)) + .frame(width: size.width * sizeTimes[0], height: size.height * sizeTimes[1]) + .shadow(color: shadowColor, radius: 10, y: 5) + .overlay { + self.keyLabel(for: direction, textColor: theme.suggestLabelTextColor?.color) + .padding(EdgeInsets( + top: size.height * paddings[0], + leading: size.width * paddings[1], + bottom: size.height * paddings[2], + trailing: size.width * paddings[3] + )) + } + .allowsHitTesting(false) + .opacity(isHidden ? 0 : 1) } /// その方向にViewの表示が必要な場合はサジェストのViewを、不要な場合は透明なViewを返す。 @ViewBuilder @@ -130,20 +129,20 @@ struct FlickSuggestView: Vi .overlay { let offsetX: CGFloat = switch direction { case .bottom, .top: 0 - case .left: -cornerRadius + sizeDiff/2 - case .right: cornerRadius - sizeDiff/2 + case .left: -cornerRadius + sizeDiff / 2 + case .right: cornerRadius - sizeDiff / 2 } let offsetY: CGFloat = switch direction { case .left, .right: 0 - case .top: -cornerRadius + sizeDiff/2 - case .bottom: cornerRadius - sizeDiff/2 + case .top: -cornerRadius + sizeDiff / 2 + case .bottom: cornerRadius - sizeDiff / 2 } self.keyLabel(for: direction, textColor: theme.suggestLabelTextColor?.color) .offset(x: offsetX, y: offsetY) } .opacity(isHidden ? 0 : 1) } - + var body: some View { switch self.suggestType { case .all: @@ -216,47 +215,47 @@ struct FlickSuggestView: Vi .allowsHitTesting(false) } } - + } - + private extension Path { mutating func addRoundedPentagon(using points: [CGPoint], cornerRadius: CGFloat = 5) { guard points.count == 5 else { return } - + for i in 0 ..< 5 { let currentPoint = points[i] let nextPoint = points[(i + 1) % 5] let prevPoint = i == 0 ? points.last! : points[i - 1] - + let directionFromPrev = CGVector(dx: currentPoint.x - prevPoint.x, dy: currentPoint.y - prevPoint.y).normalized let directionToNext = CGVector(dx: nextPoint.x - currentPoint.x, dy: nextPoint.y - currentPoint.y).normalized - + let offsetFromCurrent1 = CGVector(dx: directionFromPrev.dx * cornerRadius, dy: directionFromPrev.dy * cornerRadius) let offsetFromCurrent2 = CGVector(dx: directionToNext.dx * cornerRadius, dy: directionToNext.dy * cornerRadius) - + if i == 0 { move(to: CGPoint(x: currentPoint.x - offsetFromCurrent1.dx, y: currentPoint.y - offsetFromCurrent1.dy)) } else { addLine(to: CGPoint(x: currentPoint.x - offsetFromCurrent1.dx, y: currentPoint.y - offsetFromCurrent1.dy)) } - + addQuadCurve(to: CGPoint(x: currentPoint.x + offsetFromCurrent2.dx, y: currentPoint.y + offsetFromCurrent2.dy), control: currentPoint) } - + closeSubpath() } } - + private extension CGVector { var length: CGFloat { - return sqrt(dx * dx + dy * dy) + sqrt(dx * dx + dy * dy) } - + var normalized: CGVector { - return CGVector(dx: dx / length, dy: dy / length) + CGVector(dx: dx / length, dy: dy / length) } } - + private struct RoundedPentagonBottom: Shape { func path(in rect: CGRect) -> Path { var path = Path() @@ -271,7 +270,7 @@ private struct RoundedPentagonBottom: Shape { return path } } - + private struct RoundedPentagonLeft: Shape { func path(in rect: CGRect) -> Path { var path = Path() @@ -286,7 +285,7 @@ private struct RoundedPentagonLeft: Shape { return path } } - + private struct RoundedPentagonRight: Shape { func path(in rect: CGRect) -> Path { var path = Path() @@ -301,7 +300,7 @@ private struct RoundedPentagonRight: Shape { return path } } - + private struct RoundedPentagonTop: Shape { func path(in rect: CGRect) -> Path { var path = Path() From 6c4585af6b841e5d6c2cede4eaf6c240b685e79d Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 21 Oct 2023 00:02:21 +0900 Subject: [PATCH 110/124] Make blur available only in default keyboard, due to performance issue --- .../KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift | 7 ++++--- .../View/FlickKeyboard/FlickKeyboardView.swift | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index cc73e68f..c858f9c1 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -337,10 +337,11 @@ struct CustomKeyboardView: public struct CustardFlickKeysView: View { @State private var suggestState = FlickSuggestState() - public init(models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)], tabDesign: TabDependentDesign, layout: CustardInterfaceLayoutGridValue, @ViewBuilder generator: @escaping (FlickKeyView, Int, Int) -> (Content)) { + public init(models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)], tabDesign: TabDependentDesign, layout: CustardInterfaceLayoutGridValue, blur: Bool = false, @ViewBuilder generator: @escaping (FlickKeyView, Int, Int) -> (Content)) { self.models = models self.tabDesign = tabDesign self.layout = layout + self.blur = blur self.contentGenerator = generator } @@ -348,6 +349,7 @@ public struct CustardFlickKeysView (position: CGPoint, size: CGSize) { let width = tabDesign.keyViewWidth(widthCount: width) @@ -360,8 +362,7 @@ public struct CustardFlickKeysView: V var body: some View { let layout = CustardInterfaceLayoutGridValue(rowCount: Int(tabDesign.horizontalKeyCount), columnCount: Int(tabDesign.verticalKeyCount)) - CustardFlickKeysView(models: models, tabDesign: tabDesign, layout: layout) {(view: FlickKeyView, _, _) in + CustardFlickKeysView(models: models, tabDesign: tabDesign, layout: layout, blur: true) {(view: FlickKeyView, _, _) in view } } From 28aa21b485f78a7844129292f91b441e89a41acd Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 22 Oct 2023 00:25:13 +0900 Subject: [PATCH 111/124] add dismiss delay to flick suggests --- .../View/FlickKeyboard/KeyView/FlickKeyView.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift index 2920f698..80ccc77b 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickKeyView.swift @@ -32,6 +32,7 @@ public struct FlickKeyView: @State private var pressState: KeyPressState = .inactive @Binding private var suggestState: FlickSuggestState + @State private var suggestDismissTask: Task? // TODO: 消せるはず @State private var startLocation: CGPoint? @@ -97,6 +98,8 @@ public struct FlickKeyView: self.setSuggestState(nil) // 一つの方向でサジェストされた状態を登録する。 pressState = .oneDirectionSuggested(d, Date()) + // もしサジェストを非表示にするタスクが走っていたら、キャンセルする + self.suggestDismissTask?.cancel() // 長押しされなかったと判断して終了する。 self.action.registerLongPressActionEnd(self.model.longPressActions(variableStates: variableStates)) // 長フリックを予約する @@ -164,8 +167,13 @@ public struct FlickKeyView: // タップの終了時 .onEnded {_ in // サジェストを解除する - self.setSuggestState(nil) - + // 少しdelayを入れることで表示がはっきりして、「フリックした感」が強まる + self.suggestDismissTask = Task { + // 0.1秒だともたつき感、0.05秒だと短すぎ、という感じ + try await Task.sleep(nanoseconds: 0_070_000_000) + try Task.checkCancellation() + self.setSuggestState(nil) + } // 押しはじめて、そのあと動きがなかった場合ここに来る。 if case let .started(date) = pressState { // もし0.4秒以上経っていたら From 16b2b06f159c7808fb246b7040d9eb3296c6d75b Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 22 Oct 2023 16:34:36 +0900 Subject: [PATCH 112/124] Add shift key setting --- .../AzooKeyUtils/AzooKeyKeyboardViewExtension.swift | 2 +- .../KeyboardSetting/BoolKeyboardSetting.swift | 11 +++++++++++ MainApp/Setting/SettingTab.swift | 10 ++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift index db80f08b..608f5d30 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift @@ -95,7 +95,7 @@ public enum AzooKeyKeyboardViewExtension: ApplicationSpecificKeyboardViewExtensi } public static var useShiftKey: Bool { - false + UseShiftKey.value } public static var canResetLearningForCandidate: Bool { diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift index e9238240..83ea01d2 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift @@ -179,6 +179,17 @@ public extension KeyboardSettingKey where Self == UseSliderStyleCursorBar { static var useSliderStyleCursorBar: Self { .init() } } +public struct UseShiftKey: BoolKeyboardSettingKey { + public static let title: LocalizedStringKey = "シフトキーを使う" + public static let explanation: LocalizedStringKey = "QwertyキーボードでAaキーの代わりにシフトキーを利用します。" + public static let defaultValue = false + public static let key: String = "use_shift_key" +} + +public extension KeyboardSettingKey where Self == UseShiftKey { + static var useShiftKey: Self { .init() } +} + public struct HideResetButtonInOneHandedMode: BoolKeyboardSettingKey { public static let title: LocalizedStringKey = "片手モードで解除ボタンを表示しない" public static let explanation: LocalizedStringKey = "片手モードの際に表示される解除ボタンを非表示にします。片手モードの調整はタブバーのボタンから行えます。" diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index 00bf26bd..2c3520aa 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -23,6 +23,13 @@ struct SettingTabView: View { return false } + private func canQwertyLayout(_ layout: LanguageLayout) -> Bool { + if layout == .qwerty { + return true + } + return false + } + var body: some View { NavigationView { Form { @@ -73,6 +80,9 @@ struct SettingTabView: View { if self.canFlickLayout(appStates.japaneseLayout) { FlickSensitivitySettingView(.flickSensitivity) } + if self.canQwertyLayout(appStates.englishLayout) { + BoolSettingView(.useShiftKey) + } } } Group { From c022f705fd3211fb264ae9d3e14bba9fcb775c02 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 22 Oct 2023 16:35:07 +0900 Subject: [PATCH 113/124] update info --- MainApp/UpdateInformationView.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MainApp/UpdateInformationView.swift b/MainApp/UpdateInformationView.swift index d2437a2a..6a7ce511 100644 --- a/MainApp/UpdateInformationView.swift +++ b/MainApp/UpdateInformationView.swift @@ -24,7 +24,7 @@ struct UpdateInformationView: View { } ParagraphView("予測変換を大幅に強化しました。") { "確定したあとに続けて打つ文字を予測するようになりました" - "より妥当な候補が表示されるようになりました" + "より妥当な予測候補が表示されるようになりました" } ParagraphView("機能を改善しました。") { "再変換を大幅に強化しました。" @@ -33,6 +33,11 @@ struct UpdateInformationView: View { "カーソルを動かした際、カーソルバーを表示するようにしました" "カスタムキーで「次候補」と「A/a」の特殊キーを選べるようになりました" } + ParagraphView("デザインを改善しました") { + "サジェストをよりはっきりと表示するようにしました" + "カーソルバーのデザインを改善しました" + "iPadでのデザインを改善しました" + } ParagraphView("複数の不具合を修正しました。") ParagraphView("その他辞書の改善を行いました。") } From b12a953eb14b00b18b2feca39322c16e704c840f Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 22 Oct 2023 23:45:03 +0900 Subject: [PATCH 114/124] Update theme tab design --- MainApp/Theme/ThemeTab.swift | 128 ++++++++++++++++---------------- Resources/Localizable.xcstrings | 30 ++++++++ 2 files changed, 96 insertions(+), 62 deletions(-) diff --git a/MainApp/Theme/ThemeTab.swift b/MainApp/Theme/ThemeTab.swift index 1db67ef7..3355222c 100644 --- a/MainApp/Theme/ThemeTab.swift +++ b/MainApp/Theme/ThemeTab.swift @@ -31,9 +31,8 @@ struct ThemeTabView: View { } @MainActor - private func circle(geometry: GeometryProxy, systemName: String, color: Color) -> some View { - let width = min(min(geometry.size.width / 1.5, 180), geometry.size.height / 2.5) // 高さに2つ入るサイズを超えないように設定 - return Circle() + private func circle(width: CGFloat, systemName: String, color: Color) -> some View { + Circle() .fill(color) .frame(width: width, height: width) .overlay( @@ -43,45 +42,6 @@ struct ThemeTabView: View { ) } - @MainActor - private func selectButton(_ index: Int) -> some View { - GeometryReader {geometry in - if manager.selectedIndex == manager.selectedIndexInDarkMode { - CenterAlignedView { - VStack { - Spacer() - circle(geometry: geometry, systemName: "checkmark", color: manager.selectedIndex == index ? Color.blue : Color.systemGray4) - .matchedGeometryEffect(id: "ThemeLightButton\(index)", in: namespace) - .matchedGeometryEffect(id: "ThemeDarkButton\(index)", in: namespace) - Spacer() - } - .onTapGesture { - manager.select(at: index) - } - } - } else { - CenterAlignedView { - VStack { - Spacer() - circle(geometry: geometry, systemName: "sun.max.fill", color: manager.selectedIndex == index ? Color.blue : Color.systemGray4) - .matchedGeometryEffect(id: "ThemeLightButton\(index)", in: namespace) - .onTapGesture { - manager.selectForLightMode(at: index) - } - Spacer(minLength: 10) - circle(geometry: geometry, systemName: "moon.fill", color: manager.selectedIndexInDarkMode == index ? Color.blue : Color.systemGray4) - .matchedGeometryEffect(id: "ThemeDarkButton\(index)", in: namespace) - .onTapGesture { - manager.selectForDarkMode(at: index) - } - Spacer() - } - } - } - } - .animation(.easeIn(duration: 0.2), value: manager.selectedIndex == manager.selectedIndexInDarkMode) - } - private var tab: Tab.ExistentialTab { switch appStates.japaneseLayout { case .flick: @@ -99,9 +59,62 @@ struct ThemeTabView: View { ForEach(manager.indices.reversed(), id: \.self) { index in if let theme = theme(at: index) { HStack { - KeyboardPreview(theme: theme, scale: 0.6, defaultTab: tab) - .disabled(true) - selectButton(index) + ZStack { + KeyboardPreview(theme: theme, scale: 0.6, defaultTab: tab) + .disabled(true) + .overlay { + if manager.selectedIndex == index || manager.selectedIndexInDarkMode == index { + Color.black.opacity(0.3) + } + } + .onTapGesture { + if manager.selectedIndex != index && manager.selectedIndexInDarkMode != index { + self.manager.select(at: index) + } + } + if manager.selectedIndex == manager.selectedIndexInDarkMode, + manager.selectedIndex == index { + circle(width: 80, systemName: "checkmark", color: .blue) + .matchedGeometryEffect(id: "selected_theme_checkmark", in: namespace) + } else if manager.selectedIndex == index { + circle(width: 80, systemName: "sun.max.fill", color: .blue) + .matchedGeometryEffect(id: "selected_theme_light", in: namespace) + } else if manager.selectedIndexInDarkMode == index { + circle(width: 80, systemName: "moon.fill", color: .blue) + .matchedGeometryEffect(id: "selected_theme_dark", in: namespace) + } + } + Spacer() + VStack { + if manager.selectedIndex == manager.selectedIndexInDarkMode { + if manager.selectedIndex != index { + Button("選択", systemImage: "checkmark") { + manager.select(at: index) + } + } + } else { + if manager.selectedIndex != index { + Button("ライトモード", systemImage: "sun.max.fill") { + manager.selectForLightMode(at: index) + } + } + if manager.selectedIndexInDarkMode != index { + Button("ダークモード", systemImage: "moon.fill") { + manager.selectForDarkMode(at: index) + } + } + } + if index != 0 { + Button("編集", systemImage: "slider.horizontal.3") { + editViewIndex = index + editViewEnabled = true + } + } + } + .labelStyle(.iconOnly) + .buttonStyle(LargeButtonStyle(backgroundColor: .systemGray5)) + Spacer() + // 編集用 if editViewIndex == index { NavigationLink(destination: ThemeEditView(index: editViewIndex, manager: $manager), isActive: $editViewEnabled) { EmptyView() @@ -110,36 +123,27 @@ struct ThemeTabView: View { } .contextMenu { if self.manager.selectedIndex == self.manager.selectedIndexInDarkMode { - Button { + Button("ライトモードで使用", systemImage: "sun.max.fill") { manager.selectForLightMode(at: index) - } label: { - Image(systemName: "sun.max.fill") - Text("ライトモードで使用") } - Button { + Button("ダークモードで使用", systemImage: "moon.fill") { manager.selectForDarkMode(at: index) - } label: { - Image(systemName: "moon.fill") - Text("ダークモードで使用") } } - Button { + Button("編集する", systemImage: "slider.horizontal.3") { editViewIndex = index editViewEnabled = true - } label: { - Image(systemName: "pencil") - Text("編集する") - }.disabled(index == 0) - Button(role: .destructive) { + } + .disabled(index == 0) + Button("削除する", systemImage: "trash", role: .destructive) { manager.remove(index: index) - } label: { - Label("削除する", systemImage: "trash") - .foregroundStyle(.red) } .disabled(index == 0) } } } + .animation(.easeIn(duration: 0.15), value: manager.selectedIndex) + .animation(.easeIn(duration: 0.15), value: manager.selectedIndexInDarkMode) } var body: some View { diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 7bfb0cbd..268f425b 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -3582,6 +3582,16 @@ } } }, + "ダークモード" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dark mode" + } + } + } + }, "ダークモードで使用" : { "localizations" : { "en" : { @@ -4836,6 +4846,16 @@ } } }, + "ライトモード" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Light mode" + } + } + } + }, "ライトモードで使用" : { "localizations" : { "en" : { @@ -9623,6 +9643,16 @@ } } }, + "選択" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select" + } + } + } + }, "長押し" : { "extractionState" : "manual", "localizations" : { From 5566b2075596a8273e5aaefa632d20a2ccea5025 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 23 Oct 2023 10:34:08 +0900 Subject: [PATCH 115/124] Remove dependency on keyboard layout in vertical spacing calculation --- .../Sources/KeyboardViews/Design.swift | 25 +++++++------------ .../View/CustomKeybaord/CustomKeyboard.swift | 6 ++--- .../FlickKeyboard/FlickKeyboardView.swift | 2 +- .../QwertyKeyboard/QwertyKeyboardView.swift | 2 +- .../SpecialTabs/ClipboardHistoryTab.swift | 4 +-- .../View/SpecialTabs/EmojiTab.swift | 2 +- .../Customize/EditingTenkeyCustardView.swift | 2 +- 7 files changed, 18 insertions(+), 25 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/Design.swift b/AzooKeyCore/Sources/KeyboardViews/Design.swift index d99844ad..ee15c5f0 100644 --- a/AzooKeyCore/Sources/KeyboardViews/Design.swift +++ b/AzooKeyCore/Sources/KeyboardViews/Design.swift @@ -15,25 +15,22 @@ import SwiftUIUtils public struct TabDependentDesign { let horizontalKeyCount: CGFloat let verticalKeyCount: CGFloat - let layout: KeyboardLayout let orientation: KeyboardOrientation private var interfaceWidth: CGFloat private var interfaceHeight: CGFloat - public init(width: Int, height: Int, interfaceSize: CGSize, layout: KeyboardLayout, orientation: KeyboardOrientation) { + public init(width: Int, height: Int, interfaceSize: CGSize, orientation: KeyboardOrientation) { self.horizontalKeyCount = CGFloat(width) self.verticalKeyCount = CGFloat(height) - self.layout = layout self.orientation = orientation self.interfaceWidth = interfaceSize.width self.interfaceHeight = interfaceSize.height } - public init(width: CGFloat, height: CGFloat, interfaceSize: CGSize, layout: KeyboardLayout, orientation: KeyboardOrientation) { + public init(width: CGFloat, height: CGFloat, interfaceSize: CGSize, orientation: KeyboardOrientation) { self.horizontalKeyCount = width self.verticalKeyCount = height - self.layout = layout self.orientation = orientation self.interfaceWidth = interfaceSize.width self.interfaceHeight = interfaceSize.height @@ -42,10 +39,10 @@ public struct TabDependentDesign { /// screenWidthとhorizontalKeyCountに依存 var keyViewWidth: CGFloat { let coefficient: CGFloat - switch (layout, orientation) { - case (_, .vertical): + switch orientation { + case .vertical: coefficient = 5 / (5.1 + horizontalKeyCount / 10) - case (_, .horizontal): + case .horizontal: coefficient = 10 / (10.2 + horizontalKeyCount * 0.28) } return interfaceWidth / horizontalKeyCount * coefficient @@ -72,15 +69,11 @@ public struct TabDependentDesign { } var verticalSpacing: CGFloat { - switch (layout, orientation) { - case (.flick, .vertical): - return interfaceWidth * 3 / 140 - case (.flick, .horizontal): + switch orientation { + case .vertical: + return interfaceWidth / 50 + case .horizontal: return interfaceWidth / 107 - case (.qwerty, .vertical): - return interfaceWidth / 36.6 - case (.qwerty, .horizontal): - return interfaceWidth / 65 } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift index c858f9c1..df65eead 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/CustomKeyboard.swift @@ -49,13 +49,13 @@ fileprivate extension CustardInterface { func tabDesign(interfaceSize: CGSize, keyboardOrientation: KeyboardOrientation) -> TabDependentDesign { switch self.keyLayout { case let .gridFit(value): - return TabDependentDesign(width: value.rowCount, height: value.columnCount, interfaceSize: interfaceSize, layout: keyStyle.keyboardLayout, orientation: keyboardOrientation) + return TabDependentDesign(width: value.rowCount, height: value.columnCount, interfaceSize: interfaceSize, orientation: keyboardOrientation) case let .gridScroll(value): switch value.direction { case .vertical: - return TabDependentDesign(width: CGFloat(Int(value.rowCount)), height: CGFloat(value.columnCount), interfaceSize: interfaceSize, layout: .flick, orientation: keyboardOrientation) + return TabDependentDesign(width: CGFloat(Int(value.rowCount)), height: CGFloat(value.columnCount), interfaceSize: interfaceSize, orientation: keyboardOrientation) case .horizontal: - return TabDependentDesign(width: CGFloat(value.rowCount), height: CGFloat(Int(value.columnCount)), interfaceSize: interfaceSize, layout: .flick, orientation: keyboardOrientation) + return TabDependentDesign(width: CGFloat(value.rowCount), height: CGFloat(Int(value.columnCount)), interfaceSize: interfaceSize, orientation: keyboardOrientation) } } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift index 05685bc9..049b76bb 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/FlickKeyboardView.swift @@ -16,7 +16,7 @@ struct FlickKeyboardView: V private let tabDesign: TabDependentDesign private let models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)] init(keyModels: [[any FlickKeyModelProtocol]], interfaceSize: CGSize, keyboardOrientation: KeyboardOrientation) { - self.tabDesign = TabDependentDesign(width: 5, height: 4, interfaceSize: interfaceSize, layout: .flick, orientation: keyboardOrientation) + self.tabDesign = TabDependentDesign(width: 5, height: 4, interfaceSize: interfaceSize, orientation: keyboardOrientation) var models: [KeyPosition: (model: any FlickKeyModelProtocol, width: Int, height: Int)] = [:] for h in keyModels.indices { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyKeyboardView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyKeyboardView.swift index 6797e2a2..7a2a2ab0 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyKeyboardView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/QwertyKeyboardView.swift @@ -15,7 +15,7 @@ struct QwertyKeyboardView: init(keyModels: [[any QwertyKeyModelProtocol]], interfaceSize: CGSize, keyboardOrientation: KeyboardOrientation) { self.keyModels = keyModels - self.tabDesign = TabDependentDesign(width: 10, height: 4, interfaceSize: interfaceSize, layout: .qwerty, orientation: keyboardOrientation) + self.tabDesign = TabDependentDesign(width: 10, height: 4, interfaceSize: interfaceSize, orientation: keyboardOrientation) } private var verticalIndices: Range { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift index 25c22481..a2219807 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/ClipboardHistoryTab.swift @@ -209,7 +209,7 @@ struct ClipboardHistoryTab: VStack { listView HStack { - let design = TabDependentDesign(width: 2, height: 7, interfaceSize: variableStates.interfaceSize, layout: .flick, orientation: .vertical) + let design = TabDependentDesign(width: 2, height: 7, interfaceSize: variableStates.interfaceSize, orientation: .vertical) enterKey(design) deleteKey(design) } @@ -218,7 +218,7 @@ struct ClipboardHistoryTab: HStack { listView VStack { - let design = TabDependentDesign(width: 8, height: 2, interfaceSize: variableStates.interfaceSize, layout: .flick, orientation: .horizontal) + let design = TabDependentDesign(width: 8, height: 2, interfaceSize: variableStates.interfaceSize, orientation: .horizontal) deleteKey(design) enterKey(design) } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift index 0ddc8dd8..3d9226ca 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/SpecialTabs/EmojiTab.swift @@ -154,7 +154,7 @@ struct EmojiTab: View { /// 参考用 private var keysHeight: CGFloat { - TabDependentDesign(width: 1, height: 1, interfaceSize: variableStates.interfaceSize, layout: .qwerty, orientation: variableStates.keyboardOrientation).keysHeight + TabDependentDesign(width: 1, height: 1, interfaceSize: variableStates.interfaceSize, orientation: variableStates.keyboardOrientation).keysHeight } private var scrollViewHeight: CGFloat { diff --git a/MainApp/Customize/EditingTenkeyCustardView.swift b/MainApp/Customize/EditingTenkeyCustardView.swift index 9cc65e9c..c49d913d 100644 --- a/MainApp/Customize/EditingTenkeyCustardView.swift +++ b/MainApp/Customize/EditingTenkeyCustardView.swift @@ -150,7 +150,7 @@ struct EditingTenkeyCustardView: CancelableEditor { } Toggle("自動的にタブバーに追加", isOn: $editingItem.addTabBarAutomatically) } - CustardFlickKeysView(models: models, tabDesign: .init(width: layout.rowCount, height: layout.columnCount, interfaceSize: interfaceSize, layout: .flick, orientation: MainAppDesign.keyboardOrientation), layout: layout) {(view: FlickKeyView, x: Int, y: Int) in + CustardFlickKeysView(models: models, tabDesign: .init(width: layout.rowCount, height: layout.columnCount, interfaceSize: interfaceSize, orientation: MainAppDesign.keyboardOrientation), layout: layout) {(view: FlickKeyView, x: Int, y: Int) in if editingItem.emptyKeys.contains(.gridFit(x: x, y: y)) { if !isCovered(at: (x, y)) { Button { From 29af69350ce2e8042954db488aee7dca1552da17 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 23 Oct 2023 11:16:51 +0900 Subject: [PATCH 116/124] Improve feedback and animation --- .../KeyboardBar/ReflectStyleCursorBar.swift | 61 ++++++++++++------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift index 8d4d7baf..d42da070 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift @@ -73,11 +73,11 @@ private struct CursorBarState: Equatable, Hashable, Sendable { struct ReflectStyleCursorBar: View { init() {} - + @EnvironmentObject private var variableStates: VariableStates @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action - + private enum SwipeGestureState { case inactive case tap(l1: CGPoint, l2: CGPoint, l3: CGPoint) @@ -85,22 +85,23 @@ struct ReflectStyleCursorBar? + @MainActor private var fontSize: CGFloat { Design.fonts.resultViewFontSize(userPrefrerence: Extension.SettingProvider.resultViewFontSize) } - + @MainActor fileprivate var itemWidth: CGFloat { fontSize * 1.3 } - + @MainActor fileprivate var viewWidth: CGFloat { variableStates.interfaceSize.width * 0.85 } - + @MainActor var swipeGesture: some Gesture { DragGesture(minimumDistance: 0, coordinateSpace: .global) @@ -180,35 +181,34 @@ struct ReflectStyleCursorBar Font { .system(size: size, weight: symbolsFontWeight, design: .default) } - + @MainActor private var textView: some View { HStack(spacing: .zero) { @@ -232,30 +232,32 @@ struct ReflectStyleCursorBar 20 { // 20以上動いたらダメ + self.longPressTask?.cancel() debug("touch failed") } } touchUpCallBack: { gestureState in - self.action.registerLongPressActionEnd(.init(start: [], repeat: [.moveCursor(-1)])) + // self.action.registerLongPressActionEnd(.init(start: [], repeat: [.moveCursor(-1)])) + self.longPressTask?.cancel() if gestureState.time < 0.4 { withAnimation(.linear(duration: 0.15)) { cursorBarState.move(-1, actionManager: self.action, variableStates: variableStates) } + KeyboardFeedback.tabOrOtherKey() } } ) @@ -271,24 +273,26 @@ struct ReflectStyleCursorBar 20 { // 20以上動いたらダメ + self.longPressTask?.cancel() debug("touch failed") } } touchUpCallBack: { gestureState in - self.action.registerLongPressActionEnd(.init(start: [], repeat: [.moveCursor(1)])) + self.longPressTask?.cancel() if gestureState.time < 0.4 { withAnimation(.linear(duration: 0.15)) { cursorBarState.move(1, actionManager: self.action, variableStates: variableStates) } + KeyboardFeedback.tabOrOtherKey() } } ) } } } - + var body: some View { background .overlay(foregroundButtons) @@ -303,5 +307,20 @@ struct ReflectStyleCursorBar.tabOrOtherKey() + try await Task.sleep(nanoseconds: 0_100_000_000) + } + } + } } From ae2f58509686f5bb26268c5e214e4da7592f5ad8 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Mon, 23 Oct 2023 16:07:31 +0900 Subject: [PATCH 117/124] Add localization --- Resources/Localizable.xcstrings | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Resources/Localizable.xcstrings b/Resources/Localizable.xcstrings index 7bfb0cbd..ce0bb778 100644 --- a/Resources/Localizable.xcstrings +++ b/Resources/Localizable.xcstrings @@ -1443,6 +1443,17 @@ } } }, + "QwertyキーボードでAaキーの代わりにシフトキーを利用します。" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use shift key instead of Aa key in qwerty keyboards." + } + } + } + }, "unicode変換" : { "extractionState" : "manual", "localizations" : { @@ -3438,6 +3449,17 @@ } } }, + "シフトキーを使う" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use shift key" + } + } + } + }, "ショートカットを実行" : { "localizations" : { "en" : { From f772b3c0d52d10bab73ea0fb0748bd7cb5af97ae Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 24 Oct 2023 16:20:21 +0900 Subject: [PATCH 118/124] =?UTF-8?q?Qwerty=E3=81=AE=E3=82=B5=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=82=B9=E3=83=88=E3=81=AB=E3=82=A2=E3=83=8B=E3=83=A1?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KeyView/QwertyVariationsView.swift | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift index c55d9a64..c950e4fc 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyVariationsView.swift @@ -13,6 +13,7 @@ struct QwertyVariationsView private let model: VariationsModel private let selection: Int? @Environment(Extension.Theme.self) private var theme + @Namespace private var namespace private let tabDesign: TabDependentDesign init(model: VariationsModel, selection: Int?, tabDesign: TabDependentDesign) { @@ -29,17 +30,21 @@ struct QwertyVariationsView HStack(spacing: tabDesign.horizontalSpacing) { ForEach(model.variations.indices, id: \.self) {(index: Int) in ZStack { - Rectangle() - .foregroundStyle(index == selection ? Color.blue : suggestColor) - .frame(width: tabDesign.keyViewWidth, height: tabDesign.keyViewHeight * 0.9, alignment: .center) - .cornerRadius(10.0) - getLabel(model.variations[index].label) + if index == selection { + Rectangle() + .foregroundStyle(.blue) + .cornerRadius(10.0) + .matchedGeometryEffect(id: "focus", in: namespace) + } + getLabel(model.variations[index].label, textColor: index == selection ? .white : theme.suggestLabelTextColor?.color ?? .black) } + .frame(width: tabDesign.keyViewWidth, height: tabDesign.keyViewHeight * 0.9, alignment: .center) } } + .animation(.easeOut(duration: 0.075), value: selection) } - @MainActor private func getLabel(_ labelType: KeyLabelType) -> KeyLabel { - KeyLabel(labelType, width: tabDesign.keyViewWidth, textColor: theme.suggestLabelTextColor?.color ?? .black) + @MainActor private func getLabel(_ labelType: KeyLabelType, textColor: Color) -> KeyLabel { + KeyLabel(labelType, width: tabDesign.keyViewWidth, textColor: textColor) } } From ad1ce7bf842053ff31a777ebd497b1a9d171c8d9 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Fri, 27 Oct 2023 16:06:04 +0900 Subject: [PATCH 119/124] =?UTF-8?q?TabManager=E3=81=B8=E3=81=AE=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=82=BB=E3=82=B9=E3=81=A7BAD=5FACCESS=E3=81=8C?= =?UTF-8?q?=E7=99=BA=E7=94=9F=E3=81=97=E3=81=A6=E3=81=84=E3=82=8B=E5=95=8F?= =?UTF-8?q?=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/KeyboardViews/VariableStates.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift index 11caf36f..f736afab 100644 --- a/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift +++ b/AzooKeyCore/Sources/KeyboardViews/VariableStates.swift @@ -109,16 +109,16 @@ public final class VariableStates: ObservableObject { } } } - private(set) public var inputStyle: InputStyle = .direct - private(set) public var tabManager: TabManager - public var keyboardInternalSettingManager: KeyboardInternalSettingManager + @MainActor private(set) public var inputStyle: InputStyle = .direct + @Published private(set) public var tabManager: TabManager + @Published public var keyboardInternalSettingManager: KeyboardInternalSettingManager @Published public var clipboardHistoryManager: ClipboardHistoryManager @Published public var keyboardLanguage: KeyboardLanguage = .ja_JP @Published private(set) public var keyboardOrientation: KeyboardOrientation = .vertical @Published private(set) public var keyboardLayout: KeyboardLayout = .flick - private(set) public var keyboardType: UIKeyboardType = .default + @MainActor private(set) public var keyboardType: UIKeyboardType = .default /// `ResultModel`の変数 @Published public var resultModel = ResultModel() @@ -131,7 +131,7 @@ public final class VariableStates: ObservableObject { @Published public var interfacePosition: CGPoint = .zero /// 外部では利用しないが、`enterKeyState`の更新時に必要になる - private(set) public var returnKeyType: UIReturnKeyType = .default + @MainActor private(set) public var returnKeyType: UIReturnKeyType = .default @Published private(set) var enterKeyState: EnterKeyState = .return(.default) @Published public var barState: BarState = .none @@ -244,7 +244,7 @@ public final class VariableStates: ObservableObject { } } - public func setEnterKeyState(_ state: RoughEnterKeyState) { + @MainActor public func setEnterKeyState(_ state: RoughEnterKeyState) { switch state { case .return: self.enterKeyState = .return(returnKeyType) @@ -266,7 +266,7 @@ public final class VariableStates: ObservableObject { self.setTab(tab, temporary: temporary) } - public func setUIReturnKeyType(type: UIReturnKeyType) { + @MainActor public func setUIReturnKeyType(type: UIReturnKeyType) { self.returnKeyType = type if case let .return(prev) = self.enterKeyState, prev != type { self.setEnterKeyState(.return) @@ -287,7 +287,7 @@ public final class VariableStates: ObservableObject { self.updateResizingState() } - public func setInputStyle(_ style: InputStyle) { + @MainActor public func setInputStyle(_ style: InputStyle) { self.inputStyle = style } From 3d5efefaade2a846b58a25d73ca75a2addb02bc1 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sat, 28 Oct 2023 11:25:52 +0900 Subject: [PATCH 120/124] =?UTF-8?q?=E3=82=BF=E3=83=96=E3=83=90=E3=83=BC?= =?UTF-8?q?=E3=81=AE=E8=87=AA=E5=8B=95=E9=9D=9E=E8=A1=A8=E7=A4=BA=E3=82=92?= =?UTF-8?q?=E9=9A=A0=E3=81=97=E6=A9=9F=E8=83=BD=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AzooKeyKeyboardViewExtension.swift | 8 ++++++-- .../KeyboardSetting/BoolKeyboardSetting.swift | 17 ++++++++++++++--- ...ionSpecificKeyboardViewSettingProvider.swift | 11 +++++++++-- .../View/KeyboardBar/KeyboardBarView.swift | 10 +++++++++- Keyboard/Display/InputManager.swift | 9 +++++---- MainApp/Setting/SettingTab.swift | 2 +- 6 files changed, 44 insertions(+), 13 deletions(-) diff --git a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift index 608f5d30..39d77a4c 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/AzooKeyKeyboardViewExtension.swift @@ -90,14 +90,18 @@ public enum AzooKeyKeyboardViewExtension: ApplicationSpecificKeyboardViewExtensi HideResetButtonInOneHandedMode.value } - public static var useSliderStyleCursorBar: Bool { - UseSliderStyleCursorBar.value + public static var useReflectStyleCursorBar: Bool { + UseReflectStyleCursorBar.value } public static var useShiftKey: Bool { UseShiftKey.value } + public static var displayCursorBarAutomatically: Bool { + DisplayCursorBarAutomatically.value + } + public static var canResetLearningForCandidate: Bool { LearningTypeSetting.value.needUsingMemory } diff --git a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift index 83ea01d2..d1794bb2 100644 --- a/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift +++ b/AzooKeyCore/Sources/AzooKeyUtils/KeyboardSetting/BoolKeyboardSetting.swift @@ -167,7 +167,7 @@ public extension KeyboardSettingKey where Self == DisplayTabBarButton { static var displayTabBarButton: Self { .init() } } -public struct UseSliderStyleCursorBar: BoolKeyboardSettingKey { +public struct UseReflectStyleCursorBar: BoolKeyboardSettingKey { public static let title: LocalizedStringKey = "新しいカーソルバーを使う" public static let explanation: LocalizedStringKey = "操作性が向上した新しいカーソルバーを有効化します。" public static let defaultValue = false @@ -175,8 +175,19 @@ public struct UseSliderStyleCursorBar: BoolKeyboardSettingKey { public static let key: String = "use_move_cursor_bar_beta" } -public extension KeyboardSettingKey where Self == UseSliderStyleCursorBar { - static var useSliderStyleCursorBar: Self { .init() } +public extension KeyboardSettingKey where Self == UseReflectStyleCursorBar { + static var useReflectStyleCursorBar: Self { .init() } +} + +public struct DisplayCursorBarAutomatically: BoolKeyboardSettingKey { + public static let title: LocalizedStringKey = "カーソルバーを自動表示" + public static let explanation: LocalizedStringKey = "カーソル移動の際にカーソルバーを自動表示します" + public static let defaultValue = false + public static let key: String = "display_cursor_bar_automatically" +} + +public extension KeyboardSettingKey where Self == DisplayCursorBarAutomatically { + static var displayCursorBarAutomatically: Self { .init() } } public struct UseShiftKey: BoolKeyboardSettingKey { diff --git a/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift b/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift index 5c4aaf0b..11ed50a4 100644 --- a/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift +++ b/AzooKeyCore/Sources/KeyboardViews/ApplicationSpecificKeyboardViewSettingProvider.swift @@ -28,11 +28,18 @@ import Foundation static var enableSound: Bool { get } static var enableHaptics: Bool { get } static var enablePasteButton: Bool { get } - static var displayTabBarButton: Bool { get } static var hideResetButtonInOneHandedMode: Bool { get } - static var useSliderStyleCursorBar: Bool { get } static var useShiftKey: Bool { get } + /// タブバーボタンを表示する + /// - note: このオプションは一度削除を決めたが、ユーザから強い要望があったので維持することにした。 + static var displayTabBarButton: Bool { get } + /// 反射スタイルのカーソルバーを利用する + static var useReflectStyleCursorBar: Bool { get } + /// カーソルバーを自動表示する(実験的機能) + /// - note: この機能は実験的に導入しているが、仕様に議論がある。[#346](https://github.com/ensan-hcl/azooKey/issues/346)も参照。 + static var displayCursorBarAutomatically: Bool { get } + static var canResetLearningForCandidate: Bool { get } static func get(_: CustomizableFlickKey) -> KeyFlickSetting.SettingData diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift index 0e7fcd99..c7f4d417 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift @@ -19,7 +19,11 @@ struct KeyboardBarView: Vie @State private var dismissTask: Task<(), any Error>? = nil private var useReflectStyleCursorBar: Bool { - Extension.SettingProvider.useSliderStyleCursorBar + Extension.SettingProvider.useReflectStyleCursorBar + } + + private var displayCursorBarAutomatically: Bool { + Extension.SettingProvider.displayCursorBarAutomatically } init(isResultViewExpanded: Binding) { @@ -58,6 +62,10 @@ struct KeyboardBarView: Vie } private func restartCursorBarDismissTask() { + // 自動非表示はdisplayCursorBarAutomaticallyが有効の場合のみにする。 + guard self.displayCursorBarAutomatically else { + return + } self.dismissTask?.cancel() self.dismissTask = Task { // 10秒待つ diff --git a/Keyboard/Display/InputManager.swift b/Keyboard/Display/InputManager.swift index 3866ba6a..5ab388ab 100644 --- a/Keyboard/Display/InputManager.swift +++ b/Keyboard/Display/InputManager.swift @@ -791,14 +791,14 @@ import UIKit // リザルトバーを表示する return [.setCursorBar(.off), .setTabBar(.off)] } + @KeyboardSetting(.displayCursorBarAutomatically) var displayCursorBarAutomatically // 入力テキストなし if self.composingText.isEmpty { - // 入力がない場合はreturnしておかないと、入力していない時にカーソルを動かせなくなってしまう。 - return [.setCursorBar(.on)] + return displayCursorBarAutomatically ? [.setCursorBar(.on)] : [] } // ライブ変換有効 if liveConversionEnabled { - return [.setCursorBar(.on)] + return displayCursorBarAutomatically ? [.setCursorBar(.on)] : [] } let actualCount = composingText.moveCursorFromCursorPosition(count: count) self.previousSystemOperation = self.displayedTextManager.updateComposingText(composingText: self.composingText, userMovedCount: count, adjustedMovedCount: actualCount) ? .moveCursor : nil @@ -809,7 +809,8 @@ import UIKit /// ユーザが行を跨いでカーソルを動かした場合に利用する func userJumpedCursor() -> [ActionType] { if self.composingText.isEmpty { - return [.setCursorBar(.on)] + @KeyboardSetting(.displayCursorBarAutomatically) var displayCursorBarAutomatically + return displayCursorBarAutomatically ? [.setCursorBar(.on)] : [] } self.stopComposition() return [] diff --git a/MainApp/Setting/SettingTab.swift b/MainApp/Setting/SettingTab.swift index 2c3520aa..bccc8ae4 100644 --- a/MainApp/Setting/SettingTab.swift +++ b/MainApp/Setting/SettingTab.swift @@ -51,7 +51,7 @@ struct SettingTabView: View { } } Section(header: Text("バー")) { - BoolSettingView(.useSliderStyleCursorBar) + BoolSettingView(.useReflectStyleCursorBar) BoolSettingView(.displayTabBarButton) BoolSettingView(.enableClipboardHistoryManagerTab) if SemiStaticStates.shared.hasFullAccess { From 92ba0a34e5c62061c1b54d3edc44e1260731d6b3 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 29 Oct 2023 15:29:30 +0900 Subject: [PATCH 121/124] Update info --- MainApp/UpdateInformationView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MainApp/UpdateInformationView.swift b/MainApp/UpdateInformationView.swift index 6a7ce511..ad5d3e8d 100644 --- a/MainApp/UpdateInformationView.swift +++ b/MainApp/UpdateInformationView.swift @@ -16,7 +16,7 @@ struct UpdateInformationView: View { Group { // version 2.2系 Group { - VersionView("2.2", releaseDate: "2023年10月xx日") { + VersionView("2.2", releaseDate: "2023年11月xx日") { if #unavailable(iOS 16) { ParagraphView("お知らせ。") { "バージョン2.3以降でiOS15のサポートを終了します。iOS16以上で引き続きご利用いただけます。ご不便をおかけしますが、よろしくお願いいたします" @@ -30,13 +30,13 @@ struct UpdateInformationView: View { "再変換を大幅に強化しました。" "「連絡先」に登録されている氏名を読み込んで変換に利用できるようになりました" "テキストを選択した際に表示していた「編集」機能を廃止しました" - "カーソルを動かした際、カーソルバーを表示するようにしました" + "英語のQwertyキーボードでシフトキーが利用できるようになりました" "カスタムキーで「次候補」と「A/a」の特殊キーを選べるようになりました" } ParagraphView("デザインを改善しました") { "サジェストをよりはっきりと表示するようにしました" "カーソルバーのデザインを改善しました" - "iPadでのデザインを改善しました" + "iPadでのアプリのデザインを改善しました" } ParagraphView("複数の不具合を修正しました。") ParagraphView("その他辞書の改善を行いました。") From 66f2e4f7e184130ff36ebd6bdebb9c7e36a2266a Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Sun, 29 Oct 2023 15:35:20 +0900 Subject: [PATCH 122/124] apply swiftlint --fix and swiftlint --format --- .../SimpleKeyView/SimpleKeyModel.swift | 5 ++- .../KeyView/FlickChangeKeyboardKeyModel.swift | 2 +- .../View/KeyboardBar/KeyboardBarView.swift | 2 +- .../KeyboardBar/ReflectStyleCursorBar.swift | 31 +++++++++---------- .../KeyboardBar/SliderStyleCursorBar.swift | 2 +- .../KeyView/QwertyNextCandidateKeyModel.swift | 8 ++--- .../Customize/CodableActionDataEditor.swift | 2 +- .../OpenSourceSoftwaresLicenseView.swift | 2 +- 8 files changed, 26 insertions(+), 28 deletions(-) diff --git a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift index 1314062a..0b748c7c 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/CustomKeybaord/SimpleKeyView/SimpleKeyModel.swift @@ -89,7 +89,7 @@ struct SimpleKeyModel: Simp func pressActions(variableStates: VariableStates) -> [ActionType] { pressActions } - + func longPressActions(variableStates: VariableStates) -> LongpressActionType { longPressActions } @@ -132,7 +132,7 @@ struct SimpleEnterKeyModel: struct SimpleNextCandidateKeyModel: SimpleKeyModelProtocol { var unpressedKeyColorType: SimpleUnpressedKeyColorType = .normal - + func pressActions(variableStates: VariableStates) -> [ActionType] { if variableStates.resultModel.results.isEmpty { [.input(" ")] @@ -168,7 +168,6 @@ struct SimpleNextCandidateKeyModel: SimpleKeyModelProtocol { func pressActions(variableStates: VariableStates) -> [ActionType] { if SemiStaticStates.shared.needsInputModeSwitchKey { diff --git a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift index e17f1be8..48581d84 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/FlickKeyboard/KeyView/FlickChangeKeyboardKeyModel.swift @@ -34,7 +34,7 @@ struct FlickChangeKeyboardModel LongpressActionType { + func longPressActions(variableStates _: VariableStates) -> LongpressActionType { .none } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift index c7f4d417..e2cf1584 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/KeyboardBarView.swift @@ -16,7 +16,7 @@ struct KeyboardBarView: Vie @Binding private var isResultViewExpanded: Bool @Environment(Extension.Theme.self) private var theme // CursorBarは操作がない場合に非表示にする。これをハンドルするためのタスク - @State private var dismissTask: Task<(), any Error>? = nil + @State private var dismissTask: Task<(), any Error>? private var useReflectStyleCursorBar: Bool { Extension.SettingProvider.useReflectStyleCursorBar diff --git a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift index d42da070..85080ef8 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/KeyboardBar/ReflectStyleCursorBar.swift @@ -73,11 +73,11 @@ private struct CursorBarState: Equatable, Hashable, Sendable { struct ReflectStyleCursorBar: View { init() {} - + @EnvironmentObject private var variableStates: VariableStates @Environment(Extension.Theme.self) private var theme @Environment(\.userActionManager) private var action - + private enum SwipeGestureState { case inactive case tap(l1: CGPoint, l2: CGPoint, l3: CGPoint) @@ -86,22 +86,22 @@ struct ReflectStyleCursorBar? - + @MainActor private var fontSize: CGFloat { Design.fonts.resultViewFontSize(userPrefrerence: Extension.SettingProvider.resultViewFontSize) } - + @MainActor fileprivate var itemWidth: CGFloat { fontSize * 1.3 } - + @MainActor fileprivate var viewWidth: CGFloat { variableStates.interfaceSize.width * 0.85 } - + @MainActor var swipeGesture: some Gesture { DragGesture(minimumDistance: 0, coordinateSpace: .global) @@ -181,34 +181,34 @@ struct ReflectStyleCursorBar Font { .system(size: size, weight: symbolsFontWeight, design: .default) } - + @MainActor private var textView: some View { HStack(spacing: .zero) { @@ -232,7 +232,7 @@ struct ReflectStyleCursorBar swipeGestureState = .moving(l1: value.location, l2: l1, l3: l2, count: count) } } - .onEnded {value in + .onEnded {_ in swipeGestureState = .inactive } } diff --git a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift index 606a394e..12e8955e 100644 --- a/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift +++ b/AzooKeyCore/Sources/KeyboardViews/View/QwertyKeyboard/KeyView/QwertyNextCandidateKeyModel.swift @@ -13,13 +13,13 @@ import SwiftUI struct QwertyNextCandidateKeyModel: QwertyKeyModelProtocol { let keySizeType: QwertyKeySizeType = .space - + let needSuggestView: Bool = false - + let variationsModel: VariationsModel = .init([]) - + let unpressedKeyColorType: QwertyUnpressedKeyColorType = .normal - + static var shared: Self { QwertyNextCandidateKeyModel() } func pressActions(variableStates: VariableStates) -> [ActionType] { diff --git a/MainApp/Customize/CodableActionDataEditor.swift b/MainApp/Customize/CodableActionDataEditor.swift index 637f405d..8067b2b3 100644 --- a/MainApp/Customize/CodableActionDataEditor.swift +++ b/MainApp/Customize/CodableActionDataEditor.swift @@ -31,7 +31,7 @@ extension CodableActionData { case .paste: return "ペーストする" case .moveTab: return "タブの移動" case .replaceLastCharacters: return "文字を置換" - case let .selectCandidate(selection): + case let .selectCandidate(selection): return switch selection { case .first: "最初の候補を選択" case .last: "最後の候補を選択" diff --git a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift index de18234d..504995f3 100644 --- a/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift +++ b/MainApp/Setting/OpenSourceSoftwaresLicenseView.swift @@ -208,7 +208,7 @@ private struct FunnyAzooKeyIcon: View { init(stage: Stage = .normal) { self._stage = .init(initialValue: stage) } - + struct NormalAnimationValue { // degrees var angle: Double = -10 From 8aab6e363048b05eddd9cea4f37ea28235cd8968 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 31 Oct 2023 17:19:49 +0900 Subject: [PATCH 123/124] =?UTF-8?q?Slack=E3=81=A7=E7=B5=B5=E6=96=87?= =?UTF-8?q?=E5=AD=97=E3=81=8C=E4=BA=8C=E9=87=8D=E3=81=AB=E5=85=A5=E5=8A=9B?= =?UTF-8?q?=E3=81=95=E3=82=8C=E5=BE=97=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard/Display/DisplayedTextManager.swift | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Keyboard/Display/DisplayedTextManager.swift b/Keyboard/Display/DisplayedTextManager.swift index 8e8060e2..229357fc 100644 --- a/Keyboard/Display/DisplayedTextManager.swift +++ b/Keyboard/Display/DisplayedTextManager.swift @@ -280,7 +280,17 @@ import UIKit // (挿入): 愛[|してる] // (挿入): 愛[|してる] // (移動): 愛[してる|] - // 選択中でない場合、削除する + // (例3): [愛してる|] (「愛してる」をライブ変換しており、そのまま確定) + // (何もしない) + defer { + self.composingText = composingText + self.displayedLiveConversionText = nil + } + // 例3のケース + if composingText.isEmpty && completedPrefix == self.displayedLiveConversionText { + return + } + // 選択中でない場合、必要なだけ削除を実行する if !isSelected { let count = self.displayedLiveConversionText?.count ?? self.composingText.convertTargetCursorPosition self.deleteBackward(count: count) @@ -289,8 +299,6 @@ import UIKit let cursorPosition = self.composingText.convertTargetCursorPosition - delta self.insertText(completedPrefix + String(self.composingText.convertTargetBeforeCursor.suffix(cursorPosition))) self.moveCursor(count: composingText.convertTargetCursorPosition - cursorPosition) - self.composingText = composingText - self.displayedLiveConversionText = nil } } } From 25f2ec04083cd90b7c497074e8ee8d2eae527981 Mon Sep 17 00:00:00 2001 From: ensan-hcl Date: Tue, 31 Oct 2023 17:42:49 +0900 Subject: [PATCH 124/124] Version 2.2 will be released 11/3 --- MainApp/UpdateInformationView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MainApp/UpdateInformationView.swift b/MainApp/UpdateInformationView.swift index ad5d3e8d..f54e7634 100644 --- a/MainApp/UpdateInformationView.swift +++ b/MainApp/UpdateInformationView.swift @@ -16,7 +16,7 @@ struct UpdateInformationView: View { Group { // version 2.2系 Group { - VersionView("2.2", releaseDate: "2023年11月xx日") { + VersionView("2.2", releaseDate: "2023年11月3日") { if #unavailable(iOS 16) { ParagraphView("お知らせ。") { "バージョン2.3以降でiOS15のサポートを終了します。iOS16以上で引き続きご利用いただけます。ご不便をおかけしますが、よろしくお願いいたします"