fix iOS build blockers and add project scaffold
This commit is contained in:
@@ -13,6 +13,7 @@ This is the canonical working plan and progress log for the project. Use this fi
|
|||||||
- Backend smoke coverage was added for `server_time` and audit logging.
|
- Backend smoke coverage was added for `server_time` and audit logging.
|
||||||
- iOS now follows the backend-backed flow, syncs clock from `/health`, flushes analytics, and uses localized language labels instead of hardcoded `EN` and `SV`.
|
- iOS now follows the backend-backed flow, syncs clock from `/health`, flushes analytics, and uses localized language labels instead of hardcoded `EN` and `SV`.
|
||||||
- iOS source was updated for the backend-backed session and round flow, including the real preview cue points and localized session strings.
|
- iOS source was updated for the backend-backed session and round flow, including the real preview cue points and localized session strings.
|
||||||
|
- iOS settings now uses localized copy instead of a scaffold placeholder, and the screen is wired into the root scroll flow.
|
||||||
- Android debug build passes with `./gradlew :app:assembleDebug`.
|
- Android debug build passes with `./gradlew :app:assembleDebug`.
|
||||||
- Backend tests pass with `cargo test`.
|
- Backend tests pass with `cargo test`.
|
||||||
- Backend localization bundles now have a contract test, and the localization catalog matches the shipped English and Swedish keys.
|
- Backend localization bundles now have a contract test, and the localization catalog matches the shipped English and Swedish keys.
|
||||||
@@ -20,11 +21,13 @@ This is the canonical working plan and progress log for the project. Use this fi
|
|||||||
- Backend bet coverage now includes a direct regression for late-lock rejection.
|
- Backend bet coverage now includes a direct regression for late-lock rejection.
|
||||||
- Backend bet coverage now includes invalid-session and invalid-market rejection regressions, plus settlement override coverage.
|
- Backend bet coverage now includes invalid-session and invalid-market rejection regressions, plus settlement override coverage.
|
||||||
- Backend analytics coverage now includes a representative key user flow batch.
|
- Backend analytics coverage now includes a representative key user flow batch.
|
||||||
|
- iOS project scaffolding now exists as `mobile/ios-app/HermesApp.xcodeproj` with a shared scheme and XCTest target.
|
||||||
|
- iOS sources and tests typecheck against the iPhone simulator SDK, and a standalone localization/error-mapping harness passes.
|
||||||
|
|
||||||
### Still Open
|
### Still Open
|
||||||
|
|
||||||
- Continue through the remaining plan phases and finish any leftover localization and polish work.
|
- Continue through the remaining plan phases and finish any leftover localization and polish work.
|
||||||
- Add iOS build validation once an Xcode project is available in `mobile/ios-app`.
|
- Run Xcode build/test validation once the local Xcode license is accepted; `xcodebuild` is currently blocked by the license gate in this environment.
|
||||||
- Keep expanding tests around session, odds, settlement, and analytics behavior.
|
- Keep expanding tests around session, odds, settlement, and analytics behavior.
|
||||||
|
|
||||||
## 1. Purpose
|
## 1. Purpose
|
||||||
@@ -1310,6 +1313,8 @@ Must support flags for:
|
|||||||
|
|
||||||
The AI agent must work in this order.
|
The AI agent must work in this order.
|
||||||
|
|
||||||
|
After each major completed change set, create a git commit and push it before starting the next major change.
|
||||||
|
|
||||||
### Phase 1: Documents
|
### Phase 1: Documents
|
||||||
|
|
||||||
1. Write root README
|
1. Write root README
|
||||||
|
|||||||
@@ -30,7 +30,9 @@
|
|||||||
"result.outcome": "Outcome",
|
"result.outcome": "Outcome",
|
||||||
"result.next_round": "Next round",
|
"result.next_round": "Next round",
|
||||||
"settings.title": "Settings",
|
"settings.title": "Settings",
|
||||||
|
"settings.subtitle": "Language, haptics and analytics preferences.",
|
||||||
"settings.language": "Language",
|
"settings.language": "Language",
|
||||||
|
"settings.enabled": "Enabled",
|
||||||
"settings.haptics": "Haptics",
|
"settings.haptics": "Haptics",
|
||||||
"settings.analytics": "Analytics",
|
"settings.analytics": "Analytics",
|
||||||
"errors.generic": "Please try again.",
|
"errors.generic": "Please try again.",
|
||||||
|
|||||||
@@ -30,7 +30,9 @@
|
|||||||
"result.outcome": "Utfall",
|
"result.outcome": "Utfall",
|
||||||
"result.next_round": "Nästa runda",
|
"result.next_round": "Nästa runda",
|
||||||
"settings.title": "Inställningar",
|
"settings.title": "Inställningar",
|
||||||
|
"settings.subtitle": "Språk-, haptik- och analysinställningar.",
|
||||||
"settings.language": "Språk",
|
"settings.language": "Språk",
|
||||||
|
"settings.enabled": "Aktiverad",
|
||||||
"settings.haptics": "Haptik",
|
"settings.haptics": "Haptik",
|
||||||
"settings.analytics": "Analys",
|
"settings.analytics": "Analys",
|
||||||
"errors.generic": "Försök igen.",
|
"errors.generic": "Försök igen.",
|
||||||
|
|||||||
@@ -43,7 +43,9 @@
|
|||||||
| `result.outcome` | Result outcome label |
|
| `result.outcome` | Result outcome label |
|
||||||
| `result.next_round` | Next round CTA |
|
| `result.next_round` | Next round CTA |
|
||||||
| `settings.title` | Settings title |
|
| `settings.title` | Settings title |
|
||||||
|
| `settings.subtitle` | Settings subtitle |
|
||||||
| `settings.language` | Language setting |
|
| `settings.language` | Language setting |
|
||||||
|
| `settings.enabled` | Enabled status |
|
||||||
| `settings.haptics` | Haptics setting |
|
| `settings.haptics` | Haptics setting |
|
||||||
| `settings.analytics` | Analytics setting |
|
| `settings.analytics` | Analytics setting |
|
||||||
| `errors.generic` | Generic error copy |
|
| `errors.generic` | Generic error copy |
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
@MainActor
|
||||||
func hermesUserFacingErrorMessage(localization: LocalizationStore, localeCode: String, error: Error?) -> String? {
|
func hermesUserFacingErrorMessage(localization: LocalizationStore, localeCode: String, error: Error?) -> String? {
|
||||||
guard let error else {
|
guard let error else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ struct RootView: View {
|
|||||||
VStack(alignment: .leading, spacing: 24) {
|
VStack(alignment: .leading, spacing: 24) {
|
||||||
header
|
header
|
||||||
OnboardingView(onStartSession: { onStartSession(localization.localeCode) })
|
OnboardingView(onStartSession: { onStartSession(localization.localeCode) })
|
||||||
FeedView(onWatchPreview: {}, onRetry: { onStartSession(localization.localeCode) })
|
FeedView(onRetry: { onStartSession(localization.localeCode) })
|
||||||
RoundView(onRetry: { onStartSession(localization.localeCode) })
|
RoundView(onRetry: { onStartSession(localization.localeCode) })
|
||||||
SessionView(onRetry: { onStartSession(localization.localeCode) })
|
SessionView(onRetry: { onStartSession(localization.localeCode) })
|
||||||
|
SettingsView()
|
||||||
}
|
}
|
||||||
.padding(.horizontal, HermesTheme.screenPadding)
|
.padding(.horizontal, HermesTheme.screenPadding)
|
||||||
.padding(.vertical, 24)
|
.padding(.vertical, 24)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Combine
|
import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
@MainActor
|
||||||
protocol AnalyticsTracking {
|
protocol AnalyticsTracking {
|
||||||
func track(_ event: String, attributes: [String: String])
|
func track(_ event: String, attributes: [String: String])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ final class LocalizationStore: ObservableObject {
|
|||||||
private static let supportedLocaleCodes = ["en", "sv"]
|
private static let supportedLocaleCodes = ["en", "sv"]
|
||||||
private static let fallbackLocaleCode = "en"
|
private static let fallbackLocaleCode = "en"
|
||||||
|
|
||||||
init(bundle: Bundle = .main, localeCode: String = Locale.preferredLanguages.first.map { String($0.prefix(2)) } ?? "en") {
|
init(bundle: Bundle? = nil, localeCode: String = Locale.preferredLanguages.first.map { String($0.prefix(2)) } ?? "en") {
|
||||||
self.bundle = bundle
|
self.bundle = bundle ?? Self.defaultBundle
|
||||||
self.localeCode = Self.normalize(localeCode)
|
self.localeCode = Self.normalize(localeCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,4 +64,12 @@ final class LocalizationStore: ObservableObject {
|
|||||||
|
|
||||||
return localeCode
|
return localeCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static var defaultBundle: Bundle {
|
||||||
|
#if SWIFT_PACKAGE
|
||||||
|
.module
|
||||||
|
#else
|
||||||
|
.main
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,8 @@ struct HermesAPIClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func submitAnalyticsBatch(_ payload: HermesAnalyticsBatchRequest) async throws {
|
func submitAnalyticsBatch(_ payload: HermesAnalyticsBatchRequest) async throws {
|
||||||
try await perform(path: "api/v1/analytics/batch", method: "POST", body: payload)
|
let encodedBody = try encoder.encode(payload)
|
||||||
|
_ = try await perform(path: "api/v1/analytics/batch", method: "POST", body: encodedBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func send<Response: Decodable>(path: String, method: String = "GET") async throws -> Response {
|
private func send<Response: Decodable>(path: String, method: String = "GET") async throws -> Response {
|
||||||
|
|||||||
@@ -113,14 +113,6 @@ struct HermesRound: Codable {
|
|||||||
var settlement: HermesSettlement
|
var settlement: HermesSettlement
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HermesRound: Codable {
|
|
||||||
var event: HermesEvent
|
|
||||||
var media: HermesEventMedia
|
|
||||||
var market: HermesMarket
|
|
||||||
var oddsVersion: HermesOddsVersion
|
|
||||||
var settlement: HermesSettlement
|
|
||||||
}
|
|
||||||
|
|
||||||
struct HermesBetIntentRequest: Codable {
|
struct HermesBetIntentRequest: Codable {
|
||||||
var sessionId: UUID
|
var sessionId: UUID
|
||||||
var eventId: UUID
|
var eventId: UUID
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ struct FeedView: View {
|
|||||||
.font(.title2.weight(.bold))
|
.font(.title2.weight(.bold))
|
||||||
.foregroundStyle(HermesTheme.textPrimary)
|
.foregroundStyle(HermesTheme.textPrimary)
|
||||||
|
|
||||||
Text(round.map { localization.string(for: "feed.hero_subtitle") } ?? localization.string(for: "feed.hero_subtitle"))
|
Text(localization.string(for: "feed.hero_subtitle"))
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
.foregroundStyle(HermesTheme.textSecondary)
|
.foregroundStyle(HermesTheme.textSecondary)
|
||||||
.frame(maxWidth: 260, alignment: .leading)
|
.frame(maxWidth: 260, alignment: .leading)
|
||||||
|
|||||||
@@ -23,51 +23,50 @@ struct SessionView: View {
|
|||||||
statusText = localization.string(for: "session.status_loading")
|
statusText = localization.string(for: "session.status_loading")
|
||||||
}
|
}
|
||||||
|
|
||||||
return HermesCard {
|
return VStack(alignment: .leading, spacing: HermesTheme.sectionSpacing) {
|
||||||
VStack(alignment: .leading, spacing: HermesTheme.sectionSpacing) {
|
HermesSectionHeader(
|
||||||
HermesSectionHeader(
|
title: localization.string(for: "session.title"),
|
||||||
title: localization.string(for: "session.title"),
|
subtitle: localization.string(for: "session.subtitle")
|
||||||
subtitle: localization.string(for: "session.subtitle")
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if session == nil {
|
if session == nil {
|
||||||
if let bannerMessage {
|
if let bannerMessage {
|
||||||
sessionErrorState(
|
sessionErrorState(
|
||||||
message: bannerMessage,
|
message: bannerMessage,
|
||||||
retryText: localization.string(for: "common.retry"),
|
retryText: localization.string(for: "common.retry"),
|
||||||
onRetry: onRetry
|
onRetry: onRetry
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
sessionLoadingState(
|
sessionLoadingState(
|
||||||
title: statusText,
|
title: statusText,
|
||||||
subtitle: localization.string(for: "session.note")
|
subtitle: localization.string(for: "session.note")
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sessionStatusBadge(text: statusText, warning: bannerMessage != nil)
|
|
||||||
|
|
||||||
if let bannerMessage {
|
|
||||||
sessionBanner(message: bannerMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionRow(label: localization.string(for: "session.id_label"), value: session?.sessionId.uuidString ?? "--")
|
|
||||||
sessionRow(label: localization.string(for: "session.user_id_label"), value: session?.userId.uuidString ?? "--")
|
|
||||||
sessionRow(
|
|
||||||
label: localization.string(for: "session.locale_label"),
|
|
||||||
value: localization.localeName(for: session?.localeCode ?? localization.localeCode)
|
|
||||||
)
|
)
|
||||||
sessionRow(label: localization.string(for: "session.started_label"), value: session.map { Self.compactDateFormatter.string(from: $0.startedAt) } ?? "--")
|
|
||||||
sessionRow(label: localization.string(for: "session.variant_label"), value: session?.experimentVariant ?? "--")
|
|
||||||
sessionRow(label: localization.string(for: "session.app_version_label"), value: session?.appVersion ?? "--")
|
|
||||||
sessionRow(label: localization.string(for: "session.device_model_label"), value: session?.deviceModel ?? "--")
|
|
||||||
sessionRow(label: localization.string(for: "session.os_version_label"), value: session?.osVersion ?? "--")
|
|
||||||
|
|
||||||
Text(localization.string(for: "session.note"))
|
|
||||||
.font(.callout)
|
|
||||||
.foregroundStyle(HermesTheme.textSecondary)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sessionStatusBadge(text: statusText, warning: bannerMessage != nil)
|
||||||
|
|
||||||
|
if let bannerMessage {
|
||||||
|
sessionBanner(message: bannerMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionRow(label: localization.string(for: "session.id_label"), value: session?.sessionId.uuidString ?? "--")
|
||||||
|
sessionRow(label: localization.string(for: "session.user_id_label"), value: session?.userId.uuidString ?? "--")
|
||||||
|
sessionRow(
|
||||||
|
label: localization.string(for: "session.locale_label"),
|
||||||
|
value: localization.localeName(for: session?.localeCode ?? localization.localeCode)
|
||||||
|
)
|
||||||
|
sessionRow(label: localization.string(for: "session.started_label"), value: session.map { Self.compactDateFormatter.string(from: $0.startedAt) } ?? "--")
|
||||||
|
sessionRow(label: localization.string(for: "session.variant_label"), value: session?.experimentVariant ?? "--")
|
||||||
|
sessionRow(label: localization.string(for: "session.app_version_label"), value: session?.appVersion ?? "--")
|
||||||
|
sessionRow(label: localization.string(for: "session.device_model_label"), value: session?.deviceModel ?? "--")
|
||||||
|
sessionRow(label: localization.string(for: "session.os_version_label"), value: session?.osVersion ?? "--")
|
||||||
|
|
||||||
|
Text(localization.string(for: "session.note"))
|
||||||
|
.font(.callout)
|
||||||
|
.foregroundStyle(HermesTheme.textSecondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hermesCard()
|
||||||
.onAppear {
|
.onAppear {
|
||||||
analytics.track("screen_viewed", attributes: ["screen_name": "session"])
|
analytics.track("screen_viewed", attributes: ["screen_name": "session"])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,45 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
|
@EnvironmentObject private var localization: LocalizationStore
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text("Settings scaffold")
|
VStack(alignment: .leading, spacing: HermesTheme.sectionSpacing) {
|
||||||
|
HermesSectionHeader(
|
||||||
|
title: localization.string(for: "settings.title"),
|
||||||
|
subtitle: localization.string(for: "settings.subtitle")
|
||||||
|
)
|
||||||
|
|
||||||
|
VStack(spacing: 12) {
|
||||||
|
settingRow(
|
||||||
|
label: localization.string(for: "settings.language"),
|
||||||
|
value: localization.localeName(for: localization.localeCode)
|
||||||
|
)
|
||||||
|
|
||||||
|
settingRow(
|
||||||
|
label: localization.string(for: "settings.haptics"),
|
||||||
|
value: localization.string(for: "settings.enabled")
|
||||||
|
)
|
||||||
|
|
||||||
|
settingRow(
|
||||||
|
label: localization.string(for: "settings.analytics"),
|
||||||
|
value: localization.string(for: "settings.enabled")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hermesCard()
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func settingRow(label: String, value: String) -> some View {
|
||||||
|
HStack {
|
||||||
|
Text(label)
|
||||||
|
.font(.callout)
|
||||||
|
.foregroundStyle(HermesTheme.textSecondary)
|
||||||
|
Spacer(minLength: 12)
|
||||||
|
Text(value)
|
||||||
|
.font(.callout.weight(.semibold))
|
||||||
|
.foregroundStyle(HermesTheme.textPrimary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,303 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {};
|
||||||
|
objectVersion = 56;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
3E1C98162835584FF4929E35 = {isa = PBXBuildFile; fileRef = AFDCE723CFA31DF2A91DA374; };
|
||||||
|
706106BBB737DEF1952FED6F = {isa = PBXBuildFile; fileRef = 3686935FA33F0278440C2137; };
|
||||||
|
594A855A0BE13416458DA3A6 = {isa = PBXBuildFile; fileRef = DA1E3F27959B70E2FA168E86; };
|
||||||
|
D3B7534C86065FFF51A5C55D = {isa = PBXBuildFile; fileRef = 6DE0108803DE783A7D5D528C; };
|
||||||
|
2D43EFE45D26F6A8E55BF3AC = {isa = PBXBuildFile; fileRef = 895DC0E4CCA3A72E5897D850; };
|
||||||
|
F9006995CFE1CCF0D38AD3AA = {isa = PBXBuildFile; fileRef = A24F440D4AC95A5E5A294BB5; };
|
||||||
|
913CFC8BADBC80B024D2C856 = {isa = PBXBuildFile; fileRef = E727CD23C8DFCD3FFA972118; };
|
||||||
|
AD46D096136FB1F118855D68 = {isa = PBXBuildFile; fileRef = 09BEEF1EACD1683731EA8B13; };
|
||||||
|
B3C9966AC80EBB9B64A07C99 = {isa = PBXBuildFile; fileRef = 618EEBF90A2888756D2A0D3D; };
|
||||||
|
BFC8A4A81EE80733E4AA7323 = {isa = PBXBuildFile; fileRef = 3C969AD72CFEAAFD87172BC5; };
|
||||||
|
2C7F98F2653480078868DBF4 = {isa = PBXBuildFile; fileRef = 06986680EEC52DA119F3C422; };
|
||||||
|
5384DC2D3DC830A67B2A1054 = {isa = PBXBuildFile; fileRef = 154F342749182EA88D7D3EA2; };
|
||||||
|
1E2027DC632793AF7E962016 = {isa = PBXBuildFile; fileRef = 2927929745A862DD7DB483BE; };
|
||||||
|
C1DB325D4807CDE56F820173 = {isa = PBXBuildFile; fileRef = 738C6476A9F7A2BBCA018EC7; };
|
||||||
|
1A95F35F994CB9F20DF09556 = {isa = PBXBuildFile; fileRef = A6E7323ECDEAA449DD2925F0; };
|
||||||
|
9BA60A645924EEE65B60E9C1 = {isa = PBXBuildFile; fileRef = 29BBCB2FC555E6C905C380A7; };
|
||||||
|
F2FA36C9D20CD77F0045E16E = {isa = PBXBuildFile; fileRef = D34D3C5C813EAB2AD265F9CE; };
|
||||||
|
72B9487B80FFA7D58F0CF66A = {isa = PBXBuildFile; fileRef = 16E0F69DFE5FC784FB2BBECA; };
|
||||||
|
739163E3DBD5F43A84C49818 = {isa = PBXBuildFile; fileRef = 78ADAFCECDB66900EB275E3D; };
|
||||||
|
A99DDCF27A5B1368CCA1EFB5 = {isa = PBXBuildFile; fileRef = B9C59E00C07DD533A7DC8126; };
|
||||||
|
C8B084764EFF305D4AD0ADDF = {isa = PBXBuildFile; fileRef = 55B391E8147E161F76672032; };
|
||||||
|
FCF2BB724CCC6B6974C426F8 = {isa = PBXBuildFile; fileRef = 36A67B6FF0A52868D30E3AFF; };
|
||||||
|
7E17EFEA80A73B8C3179D66C = {isa = PBXBuildFile; fileRef = 5E777846BC9ED35ED93034AA; };
|
||||||
|
9FE2C1B4C0DA9FE3AEF298AF = {isa = PBXBuildFile; fileRef = 9710CA4A388CBE265276E667; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
CCF863E2FFE2061635563672 = {isa = PBXContainerItemProxy; containerPortal = 63E87276D8BD98B1C9DA3FF1; proxyType = 1; remoteGlobalIDString = E9FB55C6F47F1FFA66FE0D94; remoteInfo = HermesApp; };
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
AFDCE723CFA31DF2A91DA374 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/HermesApp.swift; sourceTree = "<group>"; };
|
||||||
|
3686935FA33F0278440C2137 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/HermesErrorMapper.swift; sourceTree = "<group>"; };
|
||||||
|
DA1E3F27959B70E2FA168E86 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/HermesRepository.swift; sourceTree = "<group>"; };
|
||||||
|
6DE0108803DE783A7D5D528C = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App/RootView.swift; sourceTree = "<group>"; };
|
||||||
|
895DC0E4CCA3A72E5897D850 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Analytics/AnalyticsClient.swift; sourceTree = "<group>"; };
|
||||||
|
A24F440D4AC95A5E5A294BB5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/DesignSystem/Theme.swift; sourceTree = "<group>"; };
|
||||||
|
E727CD23C8DFCD3FFA972118 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Gestures/GestureHandlers.swift; sourceTree = "<group>"; };
|
||||||
|
09BEEF1EACD1683731EA8B13 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Haptics/HapticsController.swift; sourceTree = "<group>"; };
|
||||||
|
618EEBF90A2888756D2A0D3D = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Localization/LocalizationStore.swift; sourceTree = "<group>"; };
|
||||||
|
3C969AD72CFEAAFD87172BC5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Media/HermesVideoPlayerView.swift; sourceTree = "<group>"; };
|
||||||
|
06986680EEC52DA119F3C422 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Media/PlayerCoordinator.swift; sourceTree = "<group>"; };
|
||||||
|
154F342749182EA88D7D3EA2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Networking/APIClient.swift; sourceTree = "<group>"; };
|
||||||
|
2927929745A862DD7DB483BE = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Core/Networking/APIModels.swift; sourceTree = "<group>"; };
|
||||||
|
738C6476A9F7A2BBCA018EC7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Feed/FeedView.swift; sourceTree = "<group>"; };
|
||||||
|
A6E7323ECDEAA449DD2925F0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Onboarding/OnboardingView.swift; sourceTree = "<group>"; };
|
||||||
|
29BBCB2FC555E6C905C380A7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Result/ResultView.swift; sourceTree = "<group>"; };
|
||||||
|
D34D3C5C813EAB2AD265F9CE = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Reveal/RevealView.swift; sourceTree = "<group>"; };
|
||||||
|
16E0F69DFE5FC784FB2BBECA = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Round/RoundView.swift; sourceTree = "<group>"; };
|
||||||
|
78ADAFCECDB66900EB275E3D = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Selection/SelectionView.swift; sourceTree = "<group>"; };
|
||||||
|
B9C59E00C07DD533A7DC8126 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Session/SessionView.swift; sourceTree = "<group>"; };
|
||||||
|
55B391E8147E161F76672032 = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features/Settings/SettingsView.swift; sourceTree = "<group>"; };
|
||||||
|
36A67B6FF0A52868D30E3AFF = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests/HermesAppTests/LocalizationStoreTests.swift; sourceTree = "<group>"; };
|
||||||
|
5E777846BC9ED35ED93034AA = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Resources/Localization/en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
9710CA4A388CBE265276E667 = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Resources/Localization/sv.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
3A8D22D1A79B415AD4892F84 = {isa = PBXFileReference; explicitFileType = wrapper.application; path = HermesApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
C1368E6B7C6BAAA50C8B38A8 = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = HermesAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
5151B46607EBC8890D8DFCC2 = {isa = PBXGroup; children = (
|
||||||
|
3A8D22D1A79B415AD4892F84,
|
||||||
|
C1368E6B7C6BAAA50C8B38A8,
|
||||||
|
); sourceTree = "<group>"; };
|
||||||
|
1C48CE29E4E135EE62951B22 = {isa = PBXGroup; children = (
|
||||||
|
AFDCE723CFA31DF2A91DA374,
|
||||||
|
3686935FA33F0278440C2137,
|
||||||
|
DA1E3F27959B70E2FA168E86,
|
||||||
|
6DE0108803DE783A7D5D528C,
|
||||||
|
); path = App; sourceTree = "<group>"; };
|
||||||
|
410188F9DC6E499FEC68BCF6 = {isa = PBXGroup; children = (
|
||||||
|
895DC0E4CCA3A72E5897D850,
|
||||||
|
A24F440D4AC95A5E5A294BB5,
|
||||||
|
E727CD23C8DFCD3FFA972118,
|
||||||
|
09BEEF1EACD1683731EA8B13,
|
||||||
|
618EEBF90A2888756D2A0D3D,
|
||||||
|
3C969AD72CFEAAFD87172BC5,
|
||||||
|
06986680EEC52DA119F3C422,
|
||||||
|
154F342749182EA88D7D3EA2,
|
||||||
|
2927929745A862DD7DB483BE,
|
||||||
|
); path = Core; sourceTree = "<group>"; };
|
||||||
|
1F26A8704D8CDB03D5D3D4BB = {isa = PBXGroup; children = (
|
||||||
|
738C6476A9F7A2BBCA018EC7,
|
||||||
|
A6E7323ECDEAA449DD2925F0,
|
||||||
|
29BBCB2FC555E6C905C380A7,
|
||||||
|
D34D3C5C813EAB2AD265F9CE,
|
||||||
|
16E0F69DFE5FC784FB2BBECA,
|
||||||
|
78ADAFCECDB66900EB275E3D,
|
||||||
|
B9C59E00C07DD533A7DC8126,
|
||||||
|
55B391E8147E161F76672032,
|
||||||
|
); path = Features; sourceTree = "<group>"; };
|
||||||
|
A024F06580C79B7582C3806A = {isa = PBXGroup; children = (
|
||||||
|
5E777846BC9ED35ED93034AA,
|
||||||
|
9710CA4A388CBE265276E667,
|
||||||
|
); path = Resources; sourceTree = "<group>"; };
|
||||||
|
156052F04525D0F710673CF0 = {isa = PBXGroup; children = (
|
||||||
|
36A67B6FF0A52868D30E3AFF,
|
||||||
|
); path = Tests; sourceTree = "<group>"; };
|
||||||
|
E461FA3D1EC1D072C116F41B = {isa = PBXGroup; children = (
|
||||||
|
1C48CE29E4E135EE62951B22,
|
||||||
|
410188F9DC6E499FEC68BCF6,
|
||||||
|
1F26A8704D8CDB03D5D3D4BB,
|
||||||
|
A024F06580C79B7582C3806A,
|
||||||
|
156052F04525D0F710673CF0,
|
||||||
|
5151B46607EBC8890D8DFCC2,
|
||||||
|
); sourceTree = "<group>"; };
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
E9FB55C6F47F1FFA66FE0D94 = {isa = PBXNativeTarget; buildConfigurationList = 6999223B144664B5601B7EE0; buildPhases = (
|
||||||
|
B70F6135A878AF9C52651F99,
|
||||||
|
42F0FBEA30B4CA87317E015D,
|
||||||
|
DFA634CB8CCD163EA3930D97,
|
||||||
|
); buildRules = (); dependencies = (); name = HermesApp; productName = HermesApp; productReference = 3A8D22D1A79B415AD4892F84; productType = "com.apple.product-type.application"; };
|
||||||
|
32127D1229D93E1AD0281CF5 = {isa = PBXNativeTarget; buildConfigurationList = 82A4B6F3DEB17576E838F4C6; buildPhases = (
|
||||||
|
0A58D7436E03725AA2604F91,
|
||||||
|
4F6B784AA6FDB9607A3034BB,
|
||||||
|
); buildRules = (); dependencies = (
|
||||||
|
54AF1B5F109B8B15F06D32EB,
|
||||||
|
); name = HermesAppTests; productName = HermesAppTests; productReference = C1368E6B7C6BAAA50C8B38A8; productType = "com.apple.product-type.bundle.unit-test"; };
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
63E87276D8BD98B1C9DA3FF1 = {isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1600; LastUpgradeCheck = 1600; }; buildConfigurationList = FCBE72429C0B1B8B87DC8CC9; compatibilityVersion = "Xcode 16.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = (
|
||||||
|
en,
|
||||||
|
sv,
|
||||||
|
); mainGroup = E461FA3D1EC1D072C116F41B; packageReferences = (); productRefGroup = 5151B46607EBC8890D8DFCC2; projectDirPath = ""; projectRoot = ""; targets = (
|
||||||
|
E9FB55C6F47F1FFA66FE0D94,
|
||||||
|
32127D1229D93E1AD0281CF5,
|
||||||
|
); };
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
54AF1B5F109B8B15F06D32EB = {isa = PBXTargetDependency; target = E9FB55C6F47F1FFA66FE0D94; targetProxy = CCF863E2FFE2061635563672; };
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
B70F6135A878AF9C52651F99 = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };
|
||||||
|
0A58D7436E03725AA2604F91 = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
42F0FBEA30B4CA87317E015D = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (
|
||||||
|
3E1C98162835584FF4929E35,
|
||||||
|
706106BBB737DEF1952FED6F,
|
||||||
|
594A855A0BE13416458DA3A6,
|
||||||
|
D3B7534C86065FFF51A5C55D,
|
||||||
|
2D43EFE45D26F6A8E55BF3AC,
|
||||||
|
F9006995CFE1CCF0D38AD3AA,
|
||||||
|
913CFC8BADBC80B024D2C856,
|
||||||
|
AD46D096136FB1F118855D68,
|
||||||
|
B3C9966AC80EBB9B64A07C99,
|
||||||
|
BFC8A4A81EE80733E4AA7323,
|
||||||
|
2C7F98F2653480078868DBF4,
|
||||||
|
5384DC2D3DC830A67B2A1054,
|
||||||
|
1E2027DC632793AF7E962016,
|
||||||
|
C1DB325D4807CDE56F820173,
|
||||||
|
1A95F35F994CB9F20DF09556,
|
||||||
|
9BA60A645924EEE65B60E9C1,
|
||||||
|
F2FA36C9D20CD77F0045E16E,
|
||||||
|
72B9487B80FFA7D58F0CF66A,
|
||||||
|
739163E3DBD5F43A84C49818,
|
||||||
|
A99DDCF27A5B1368CCA1EFB5,
|
||||||
|
C8B084764EFF305D4AD0ADDF,
|
||||||
|
); runOnlyForDeploymentPostprocessing = 0; };
|
||||||
|
4F6B784AA6FDB9607A3034BB = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (
|
||||||
|
FCF2BB724CCC6B6974C426F8,
|
||||||
|
); runOnlyForDeploymentPostprocessing = 0; };
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
DFA634CB8CCD163EA3930D97 = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (
|
||||||
|
7E17EFEA80A73B8C3179D66C,
|
||||||
|
9FE2C1B4C0DA9FE3AEF298AF,
|
||||||
|
); runOnlyForDeploymentPostprocessing = 0; };
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
C761B7D49C3C32C5F60E8010 = {isa = XCBuildConfiguration; buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
DEVELOPMENT_REGION = en;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
}; name = Debug; };
|
||||||
|
ACCCD85F61979F8ECCA377BC = {isa = XCBuildConfiguration; buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
DEVELOPMENT_REGION = en;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
}; name = Release; };
|
||||||
|
A393E557BBA174C592175785 = {isa = XCBuildConfiguration; buildSettings = {
|
||||||
|
CODE_SIGNING_ALLOWED = NO;
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hermes.app;
|
||||||
|
PRODUCT_NAME = HermesApp;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = -Onone;
|
||||||
|
}; name = Debug; };
|
||||||
|
4848DE5FB3FF960B8E5B63DC = {isa = XCBuildConfiguration; buildSettings = {
|
||||||
|
CODE_SIGNING_ALLOWED = NO;
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hermes.app;
|
||||||
|
PRODUCT_NAME = HermesApp;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = -O;
|
||||||
|
}; name = Release; };
|
||||||
|
0D633BD545D878A6647A1EBE = {isa = XCBuildConfiguration; buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGNING_ALLOWED = NO;
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_TESTING_SEARCH_PATHS = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hermes.appTests;
|
||||||
|
PRODUCT_NAME = HermesAppTests;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HermesApp.app/HermesApp";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = -Onone;
|
||||||
|
}; name = Debug; };
|
||||||
|
43ABF9DDFB26DCC1D7D88137 = {isa = XCBuildConfiguration; buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGNING_ALLOWED = NO;
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_TESTING_SEARCH_PATHS = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hermes.appTests;
|
||||||
|
PRODUCT_NAME = HermesAppTests;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HermesApp.app/HermesApp";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = -O;
|
||||||
|
}; name = Release; };
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
FCBE72429C0B1B8B87DC8CC9 = {isa = XCConfigurationList; buildConfigurations = (
|
||||||
|
C761B7D49C3C32C5F60E8010,
|
||||||
|
ACCCD85F61979F8ECCA377BC,
|
||||||
|
); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
|
||||||
|
6999223B144664B5601B7EE0 = {isa = XCConfigurationList; buildConfigurations = (
|
||||||
|
A393E557BBA174C592175785,
|
||||||
|
4848DE5FB3FF960B8E5B63DC,
|
||||||
|
); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
|
||||||
|
82A4B6F3DEB17576E838F4C6 = {isa = XCConfigurationList; buildConfigurations = (
|
||||||
|
0D633BD545D878A6647A1EBE,
|
||||||
|
43ABF9DDFB26DCC1D7D88137,
|
||||||
|
); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; };
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
};
|
||||||
|
rootObject = 63E87276D8BD98B1C9DA3FF1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme LastUpgradeVersion="1600" version="1.7">
|
||||||
|
<BuildAction parallelizeBuildables="YES" buildImplicitDependencies="YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry buildForTesting="YES" buildForRunning="YES" buildForProfiling="YES" buildForArchiving="YES" buildForAnalyzing="YES">
|
||||||
|
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="E9FB55C6F47F1FFA66FE0D94" BuildableName="HermesApp.app" BlueprintName="HermesApp" ReferencedContainer="container:HermesApp.xcodeproj"/>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry buildForTesting="YES" buildForRunning="NO" buildForProfiling="NO" buildForArchiving="NO" buildForAnalyzing="NO">
|
||||||
|
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="32127D1229D93E1AD0281CF5" BuildableName="HermesAppTests.xctest" BlueprintName="HermesAppTests" ReferencedContainer="container:HermesApp.xcodeproj"/>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction buildConfiguration="Debug" selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv="YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference skipped="NO">
|
||||||
|
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="32127D1229D93E1AD0281CF5" BuildableName="HermesAppTests.xctest" BlueprintName="HermesAppTests" ReferencedContainer="container:HermesApp.xcodeproj"/>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction buildConfiguration="Debug" selectedDebuggerIdentifier="Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier="Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle="0" useCustomWorkingDirectory="NO" ignoresPersistentStateOnLaunch="NO" debugDocumentVersioning="YES" debugServiceExtension="internal" allowLocationSimulation="YES">
|
||||||
|
<BuildableProductRunnable runnableDebuggingMode="0">
|
||||||
|
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="E9FB55C6F47F1FFA66FE0D94" BuildableName="HermesApp.app" BlueprintName="HermesApp" ReferencedContainer="container:HermesApp.xcodeproj"/>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction buildConfiguration="Release" shouldUseLaunchSchemeArgsEnv="YES" savedToolIdentifier="" useCustomWorkingDirectory="NO" debugDocumentVersioning="YES">
|
||||||
|
<BuildableProductRunnable runnableDebuggingMode="0">
|
||||||
|
<BuildableReference BuildableIdentifier="primary" BlueprintIdentifier="E9FB55C6F47F1FFA66FE0D94" BuildableName="HermesApp.app" BlueprintName="HermesApp" ReferencedContainer="container:HermesApp.xcodeproj"/>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction buildConfiguration="Debug"/>
|
||||||
|
<ArchiveAction buildConfiguration="Release" revealArchiveInOrganizer="YES"/>
|
||||||
|
</Scheme>
|
||||||
@@ -56,3 +56,9 @@
|
|||||||
"session.app_version_label" = "App version";
|
"session.app_version_label" = "App version";
|
||||||
"session.device_model_label" = "Device model";
|
"session.device_model_label" = "Device model";
|
||||||
"session.os_version_label" = "OS version";
|
"session.os_version_label" = "OS version";
|
||||||
|
"settings.title" = "Settings";
|
||||||
|
"settings.subtitle" = "Language, haptics and analytics preferences.";
|
||||||
|
"settings.language" = "Language";
|
||||||
|
"settings.enabled" = "Enabled";
|
||||||
|
"settings.haptics" = "Haptics";
|
||||||
|
"settings.analytics" = "Analytics";
|
||||||
|
|||||||
@@ -56,3 +56,9 @@
|
|||||||
"session.app_version_label" = "Appversion";
|
"session.app_version_label" = "Appversion";
|
||||||
"session.device_model_label" = "Enhetsmodell";
|
"session.device_model_label" = "Enhetsmodell";
|
||||||
"session.os_version_label" = "OS-version";
|
"session.os_version_label" = "OS-version";
|
||||||
|
"settings.title" = "Inställningar";
|
||||||
|
"settings.subtitle" = "Språk-, haptik- och analysinställningar.";
|
||||||
|
"settings.language" = "Språk";
|
||||||
|
"settings.enabled" = "Aktiverad";
|
||||||
|
"settings.haptics" = "Haptik";
|
||||||
|
"settings.analytics" = "Analys";
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import HermesApp
|
||||||
|
|
||||||
|
private struct TestFailure: Error, CustomStringConvertible {
|
||||||
|
let description: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
final class LocalizationStoreTests: XCTestCase {
|
||||||
|
func testEnglishBundleStringsLoad() throws {
|
||||||
|
let store = LocalizationStore(localeCode: "en")
|
||||||
|
|
||||||
|
try expectEqual(store.string(for: "app.name"), "Hermes")
|
||||||
|
try expectEqual(store.string(for: "settings.title"), "Settings")
|
||||||
|
try expectEqual(store.string(for: "settings.enabled"), "Enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSwedishBundleStringsLoad() throws {
|
||||||
|
let store = LocalizationStore(localeCode: "sv")
|
||||||
|
|
||||||
|
try expectEqual(store.string(for: "app.name"), "Hermes")
|
||||||
|
try expectEqual(store.string(for: "settings.title"), "Inställningar")
|
||||||
|
try expectEqual(store.string(for: "settings.enabled"), "Aktiverad")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testUnsupportedLocaleFallsBackToEnglish() throws {
|
||||||
|
let store = LocalizationStore(localeCode: "fr")
|
||||||
|
|
||||||
|
try expectEqual(store.string(for: "settings.analytics"), "Analytics")
|
||||||
|
try expectEqual(store.localeName(for: "sv", displayLocaleCode: "fr"), "Swedish")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func expectEqual(_ actual: String, _ expected: String) throws {
|
||||||
|
guard actual == expected else {
|
||||||
|
throw TestFailure(description: "Expected \(expected), got \(actual)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user