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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

All notable changes to GeoShift are documented here.

## 1.5.2 — 2026-07-21

### Added

- A compact English/Russian language switch in the main window header.
- Apple emoji flags in both the main-window and Settings language controls.

### Changed

- The default window height now fits the collapsed interface instead of leaving
a large empty area below Diagnostics.
- Expanded diagnostics remain bounded inside their own scrolling log panel, and
the main window can still be resized vertically.

## 1.5.1 — 2026-07-21

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<p align="center">
<a href="https://github.com/Lemelson/GeoShift/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Lemelson/GeoShift/actions/workflows/ci.yml/badge.svg"></a>
<img alt="Version 1.5.1" src="https://img.shields.io/badge/version-1.5.1-2563eb">
<img alt="Version 1.5.2" src="https://img.shields.io/badge/version-1.5.2-2563eb">
<img alt="macOS 14+" src="https://img.shields.io/badge/macOS-14%2B-black">
<img alt="Swift 6.2" src="https://img.shields.io/badge/Swift-6.2-f05138">
<a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-green"></a>
Expand Down
9 changes: 9 additions & 0 deletions Sources/GeoShift/AppLanguage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ enum AppLanguage: String, CaseIterable, Identifiable, Sendable {
}
}

var selectionLabel: String {
switch self {
case .english:
"🇬🇧 \(displayName)"
case .russian:
"🇷🇺 \(displayName)"
}
}

var locale: Locale {
Locale(identifier: rawValue)
}
Expand Down
3 changes: 3 additions & 0 deletions Sources/GeoShift/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ struct ContentView: View {
.sheet(isPresented: $isSettingsPresented) {
SettingsView(controller: controller)
}
.onChange(of: localization.language) {
controller.languageDidChange()
}
}

private func showCityPicker() {
Expand Down
2 changes: 1 addition & 1 deletion Sources/GeoShift/GeoShiftApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct GeoShiftApp: App {
controller.startMonitoring()
}
}
.defaultSize(width: 760, height: 820)
.defaultSize(width: 760, height: 680)
.windowResizability(.contentMinSize)
}
}
14 changes: 9 additions & 5 deletions Sources/GeoShift/HeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ struct HeaderView: View {

Spacer()

Button(
localization.text("header.settings"),
systemImage: "gearshape",
action: settingsAction
)
HStack {
LanguagePicker(controlSize: .small)

Button(
localization.text("header.settings"),
systemImage: "gearshape",
action: settingsAction
)
}
}
}
}
24 changes: 24 additions & 0 deletions Sources/GeoShift/LanguagePicker.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import SwiftUI

struct LanguagePicker: View {
var controlSize: ControlSize = .regular
@Environment(LocalizationStore.self) private var localization

var body: some View {
@Bindable var localization = localization

Picker(
localization.text("settings.language"),
selection: $localization.language
) {
ForEach(AppLanguage.allCases) { language in
Text(language.selectionLabel).tag(language)
}
}
.pickerStyle(.segmented)
.labelsHidden()
.controlSize(controlSize)
.fixedSize()
.accessibilityLabel(localization.text("settings.language"))
}
}
15 changes: 2 additions & 13 deletions Sources/GeoShift/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,12 @@ struct SettingsView: View {
@Environment(LocalizationStore.self) private var localization

var body: some View {
@Bindable var localization = localization

NavigationStack {
Form {
Section(localization.text("settings.languageSection")) {
Picker(
localization.text("settings.language"),
selection: $localization.language
) {
ForEach(AppLanguage.allCases) { language in
Text(language.displayName).tag(language)
}
LabeledContent(localization.text("settings.language")) {
LanguagePicker()
}
.pickerStyle(.segmented)
}

Section(localization.text("settings.timings")) {
Expand Down Expand Up @@ -78,9 +70,6 @@ struct SettingsView: View {
.onChange(of: controller.locationRefreshSeconds) {
controller.applySettings()
}
.onChange(of: localization.language) {
controller.languageDidChange()
}
}

private func durationOption(_ seconds: Int) -> some View {
Expand Down
2 changes: 2 additions & 0 deletions Tests/GeoShiftTests/LocalizationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ struct LocalizationTests {
localization.language = .english
#expect(localization.text("header.subtitle") == "Control iPhone GPS simulation from your Mac")
#expect(localization.text("settings.language") == "App language")
#expect(AppLanguage.english.selectionLabel == "🇬🇧 English")

localization.language = .russian
#expect(localization.text("header.subtitle").contains("симуляцией GPS"))
#expect(localization.text("settings.language") == "Язык приложения")
#expect(AppLanguage.russian.selectionLabel == "🇷🇺 Русский")
#expect(KeeperError.commandFailed("The command timed out after 5 seconds.")
.description(using: localization) == "Команда завершилась с ошибкой.")
}
Expand Down
4 changes: 2 additions & 2 deletions version.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
MARKETING_VERSION=1.5.1
BUILD_NUMBER=8
MARKETING_VERSION=1.5.2
BUILD_NUMBER=9
Loading