Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## Unreleased

### 🇨🇳 中文

#### 修复

- 取消启动时的静默更新检查,确保只有用户主动点击“检查更新…”时才会访问 GitHub。
- 修复恢复已忽略 App 时丢失原输入法策略的问题,并为菜单栏图标补充当前 App 状态的 VoiceOver 描述。

### 🇺🇸 English

#### Fixes

- Removed the silent update check at startup so TypeSwitch contacts GitHub for updates only after the user clicks `Check for Updates…`.
- Fixed restored ignored apps losing their previous input method strategy, and added VoiceOver descriptions for the current app state in the menu bar icon.

## v0.9.0

### 🇨🇳 中文
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ brew upgrade typeswitch
3. Use `Running · Unconfigured` to assign rules to running apps that do not have one yet.
4. Use `Running · Configured` and `All Configured Apps` to review and change existing app rules.
5. For each app, choose `Default` to inherit the fallback, `Last Switch`, or a specific input method.
6. Choose `Ignore This App` to stop automatic switching and hide the app from the regular lists. Restore one or all apps from `Ignored Apps`.
6. Choose `Ignore This App` to stop automatic switching and hide the app from the regular lists. Restore one or all apps from `Ignored Apps` to recover their previous rules.
7. Use `Default Rule for Unconfigured Apps` to set the fallback behavior for apps without their own rule.
8. Check `Missing Apps` and `Switches` when you want to clean missing rules or review successful switches.

## 🔒 Privacy and Permissions

- App rules, the Default Rule for Unconfigured Apps, and switch statistics are stored locally.
- TypeSwitch has no server-side component in this repository.
- `GitHub Repository` and `Check for Updates…` contact GitHub only when you use them.
- TypeSwitch does not check for updates or contact GitHub at startup. `GitHub Repository` and `Check for Updates…` contact GitHub only after you click them.
- Input method switching uses macOS system input sources.
- Launch at Login uses macOS Login Items, with a LaunchAgent fallback when needed.

Expand Down
4 changes: 2 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ brew upgrade typeswitch
3. 用“运行中 · 未配置”为还没有规则的运行中 App 设置规则。
4. 用“运行中 · 已配置”和“全部已配置 App”查看并修改已有 App 规则。
5. 为每个 App 选择“默认”以继承兜底规则,或选择“记住上次切换”及指定输入法。
6. 选择“忽略此 App”可停止自动切换并将其从普通列表隐藏;可在“已忽略 App”中单项恢复或恢复全部。
6. 选择“忽略此 App”可停止自动切换并将其从普通列表隐藏;可在“已忽略 App”中单项恢复或恢复全部,并还原忽略前的规则。
7. 用“未配置 App 的默认规则”设置没有单独规则的 App 的默认行为。
8. 按需查看“找不到的 App”和“切换统计”,清理缺失规则或查看成功切换次数。

## 🔒 隐私与权限

- App 规则、未配置 App 的默认规则和切换统计都存储在本地。
- 本仓库中没有服务端组件。
- 菜单中的“GitHub 仓库”和“检查更新…”只会在你主动使用时访问 GitHub。
- TypeSwitch 启动时不会检查更新或访问 GitHub。只有在你主动点击“GitHub 仓库”或“检查更新…”后才会访问 GitHub。
- 输入法切换使用 macOS 系统输入源。
- “登录时打开”使用 macOS 登录项;必要时会回退到 LaunchAgent。

Expand Down
4 changes: 3 additions & 1 deletion TypeSwitch/Resources/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// 菜单
"menu.quit" = "退出 TypeSwitch";
"menu.github_repository" = "GitHub 仓库";
"menu.accessibility_configured" = "TypeSwitch,当前 App 已配置";
"menu.accessibility_unconfigured" = "TypeSwitch,当前 App 未配置";
"menu.accessibility_ignored" = "TypeSwitch,当前 App 已忽略";

// 通用
"common.cancel" = "取消";
Expand All @@ -10,7 +13,6 @@
"settings.general.auto_launch_requires_approval" = "请前往“系统设置”>“通用”>“登录项”允许 TypeSwitch。";
"settings.general.open_login_items" = "打开登录项设置";
"settings.general.check_for_updates" = "检查更新…";
"settings.general.update_available" = "发现新版本…";
"settings.fallback.default_input_method" = "未配置 App 的默认规则";

// 应用列表
Expand Down
4 changes: 3 additions & 1 deletion TypeSwitch/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Menu
"menu.quit" = "Quit TypeSwitch";
"menu.github_repository" = "GitHub Repository";
"menu.accessibility_configured" = "TypeSwitch, current app configured";
"menu.accessibility_unconfigured" = "TypeSwitch, current app unconfigured";
"menu.accessibility_ignored" = "TypeSwitch, current app ignored";

// Common
"common.cancel" = "Cancel";
Expand All @@ -10,7 +13,6 @@
"settings.general.auto_launch_requires_approval" = "Approve TypeSwitch in System Settings > General > Login Items.";
"settings.general.open_login_items" = "Open Login Items Settings";
"settings.general.check_for_updates" = "Check for Updates…";
"settings.general.update_available" = "New Version Available…";
"settings.fallback.default_input_method" = "Default Rule for Unconfigured Apps";

// App List
Expand Down
4 changes: 3 additions & 1 deletion TypeSwitch/Resources/zh-Hans.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// 菜单
"menu.quit" = "退出 TypeSwitch";
"menu.github_repository" = "GitHub 仓库";
"menu.accessibility_configured" = "TypeSwitch,当前 App 已配置";
"menu.accessibility_unconfigured" = "TypeSwitch,当前 App 未配置";
"menu.accessibility_ignored" = "TypeSwitch,当前 App 已忽略";

// 通用
"common.cancel" = "取消";
Expand All @@ -10,7 +13,6 @@
"settings.general.auto_launch_requires_approval" = "请前往“系统设置”>“通用”>“登录项”允许 TypeSwitch。";
"settings.general.open_login_items" = "打开登录项设置";
"settings.general.check_for_updates" = "检查更新…";
"settings.general.update_available" = "发现新版本…";
"settings.fallback.default_input_method" = "未配置 App 的默认规则";

// 应用列表
Expand Down
4 changes: 3 additions & 1 deletion TypeSwitch/Resources/zh-Hant.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// 選單
"menu.quit" = "結束 TypeSwitch";
"menu.github_repository" = "GitHub 儲存庫";
"menu.accessibility_configured" = "TypeSwitch,目前 App 已設定";
"menu.accessibility_unconfigured" = "TypeSwitch,目前 App 未設定";
"menu.accessibility_ignored" = "TypeSwitch,目前 App 已忽略";

// 通用
"common.cancel" = "取消";
Expand All @@ -10,7 +13,6 @@
"settings.general.auto_launch_requires_approval" = "請前往「系統設定」>「一般」>「登入項目」允許 TypeSwitch。";
"settings.general.open_login_items" = "開啟登入項目設定";
"settings.general.check_for_updates" = "檢查更新…";
"settings.general.update_available" = "發現新版本…";
"settings.fallback.default_input_method" = "未設定 App 的預設規則";

// 應用程式列表
Expand Down
15 changes: 15 additions & 0 deletions TypeSwitch/Sources/App/AppFeature+MenuState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ extension AppFeature.State {
: "keyboard"
}

var menuBarAccessibilityLabel: String {
guard let currentFrontmostBundleId else {
return "TypeSwitch"
}

switch strategy(for: currentFrontmostBundleId) {
case .none:
return TypeSwitchStrings.Menu.accessibilityUnconfigured
case .fixed, .followLast:
return TypeSwitchStrings.Menu.accessibilityConfigured
case .ignored:
return TypeSwitchStrings.Menu.accessibilityIgnored
}
}

var fallbackStrategy: InputMethodStrategy {
switch fallbackRuleStore.strategy {
case .followLast, .ignored:
Expand Down
8 changes: 6 additions & 2 deletions TypeSwitch/Sources/App/AppFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ struct AppFeature {
var updatedRule = currentRule
updatedRule.lastKnownPath = appInfo.path ?? currentRule.lastKnownPath
updatedRule.lastKnownName = appInfo.name
updatedRule.strategyBeforeIgnoring = currentRule.strategy
updatedRule.strategy = .ignored
updatedRule.updatedAt = updateDate
store.rules[appInfo.bundleId] = updatedRule
Expand Down Expand Up @@ -327,7 +328,8 @@ struct AppFeature {
guard var rule = store.rules[bundleId], rule.strategy == .ignored else {
continue
}
rule.strategy = .none
rule.strategy = rule.strategyBeforeIgnoring ?? .none
rule.strategyBeforeIgnoring = nil
rule.updatedAt = updateDate
store.rules[bundleId] = rule
}
Expand All @@ -340,7 +342,8 @@ struct AppFeature {
guard var rule = store.rules[bundleId], rule.strategy == .ignored else {
return
}
rule.strategy = .none
rule.strategy = rule.strategyBeforeIgnoring ?? .none
rule.strategyBeforeIgnoring = nil
rule.updatedAt = updateDate
store.rules[bundleId] = rule
}
Expand Down Expand Up @@ -389,6 +392,7 @@ struct AppFeature {

var updatedRule = currentRule
updatedRule.strategy = strategy
updatedRule.strategyBeforeIgnoring = nil
updatedRule.updatedAt = updateDate
store.rules[bundleId] = updatedRule
}
Expand Down
11 changes: 2 additions & 9 deletions TypeSwitch/Sources/App/TypeSwitchApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ struct TypeSwitchApp: App {
let readmeBackdropWindow: NSWindow?
let readmeColorScheme: ColorScheme?
let store: StoreOf<AppFeature>
let updateMonitor: SparkleUpdateMonitor
let updaterController: SPUStandardUpdaterController

init() {
Expand All @@ -34,14 +33,12 @@ struct TypeSwitchApp: App {
AppFeature()
}
let startsUpdater = startsLiveServices && !isTesting
let updateMonitor = SparkleUpdateMonitor()
let updaterController = SPUStandardUpdaterController(
startingUpdater: startsUpdater,
updaterDelegate: updateMonitor,
updaterDelegate: nil,
userDriverDelegate: nil
)
self.store = store
self.updateMonitor = updateMonitor
self.updaterController = updaterController
self.menuTrackingObservers = [
NotificationCenter.default.addObserver(
Expand Down Expand Up @@ -76,16 +73,12 @@ struct TypeSwitchApp: App {
if startsLiveServices {
store.send(.task)
}
if startsUpdater {
updateMonitor.startSilentCheck(using: updaterController.updater)
}
}

var body: some Scene {
MenuBarExtra {
MenuBarView(
store: store,
updateMonitor: updateMonitor,
updaterController: updaterController
)
.preferredColorScheme(readmeColorScheme)
Expand All @@ -101,6 +94,6 @@ private struct MenuBarIconView: View {

var body: some View {
Image(systemName: store.menuBarIconSystemName)
.accessibilityLabel("TypeSwitch")
.accessibilityLabel(store.menuBarAccessibilityLabel)
}
}
1 change: 1 addition & 0 deletions TypeSwitch/Sources/Core/Models/AppRuleRecord.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ struct AppRuleRecord: Identifiable, Codable, Hashable, Sendable {
var lastKnownPath: String?
var lastKnownName: String
var strategy: InputMethodStrategy
var strategyBeforeIgnoring: InputMethodStrategy? = nil
var createdAt: Date
var updatedAt: Date

Expand Down
75 changes: 0 additions & 75 deletions TypeSwitch/Sources/Services/Updates/SparkleUpdateMonitor.swift

This file was deleted.

6 changes: 2 additions & 4 deletions TypeSwitch/Sources/UI/Views/MenuBar/AppInfoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ import SwiftUI

/// 应用信息视图,显示项目链接和退出入口
struct AppInfoView: View {
@ObservedObject var updateMonitor: SparkleUpdateMonitor
let updaterController: SPUStandardUpdaterController

var body: some View {
Group {
Button {
updateMonitor.showUpdate(using: updaterController.updater)
updaterController.checkForUpdates(nil)
} label: {
Label(
updateMonitor.menuTitle,
TypeSwitchStrings.Settings.General.checkForUpdates,
systemImage: "arrow.triangle.2.circlepath"
)
}
.disabled(!updateMonitor.isMenuActionEnabled)

Button {
AppInfoService.openGitHubRepository()
Expand Down
7 changes: 1 addition & 6 deletions TypeSwitch/Sources/UI/Views/MenuBar/MenuBarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import SwiftUI
/// 菜单栏主视图
struct MenuBarView: View {
let store: StoreOf<AppFeature>
let updateMonitor: SparkleUpdateMonitor
let updaterController: SPUStandardUpdaterController

var body: some View {
Expand All @@ -32,10 +31,7 @@ struct MenuBarView: View {

Divider()

AppInfoView(
updateMonitor: updateMonitor,
updaterController: updaterController
)
AppInfoView(updaterController: updaterController)
}
.labelStyle(.titleAndIcon)
}
Expand Down Expand Up @@ -73,7 +69,6 @@ private struct CurrentAppView: View {
store: Store(initialState: AppFeature.State()) {
AppFeature()
},
updateMonitor: SparkleUpdateMonitor(),
updaterController: SPUStandardUpdaterController(
startingUpdater: false,
updaterDelegate: nil,
Expand Down
Loading
Loading