diff --git a/Gemfile.lock b/Gemfile.lock
index 6815a87..0620bcc 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,29 +1,32 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.6)
+ CFPropertyList (3.0.7)
+ base64
+ nkf
rexml
- addressable (2.8.5)
+ addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
- artifactory (3.0.15)
+ artifactory (3.0.17)
atomos (0.1.3)
- aws-eventstream (1.2.0)
- aws-partitions (1.843.0)
- aws-sdk-core (3.185.1)
- aws-eventstream (~> 1, >= 1.0.2)
+ aws-eventstream (1.3.0)
+ aws-partitions (1.937.0)
+ aws-sdk-core (3.196.1)
+ aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
- aws-sigv4 (~> 1.5)
+ aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.72.0)
- aws-sdk-core (~> 3, >= 3.184.0)
+ aws-sdk-kms (1.82.0)
+ aws-sdk-core (~> 3, >= 3.193.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.136.0)
- aws-sdk-core (~> 3, >= 3.181.0)
+ aws-sdk-s3 (1.151.0)
+ aws-sdk-core (~> 3, >= 3.194.0)
aws-sdk-kms (~> 1)
- aws-sigv4 (~> 1.6)
- aws-sigv4 (1.6.1)
+ aws-sigv4 (~> 1.8)
+ aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
+ base64 (0.2.0)
claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
@@ -32,11 +35,10 @@ GEM
declarative (0.0.20)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
- domain_name (0.5.20190701)
- unf (>= 0.0.5, < 1.0.0)
+ domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
- excon (0.104.0)
+ excon (0.110.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
@@ -65,15 +67,15 @@ GEM
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
- fastimage (2.2.7)
- fastlane (2.216.0)
+ fastimage (2.3.1)
+ fastlane (2.220.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
- colored
+ colored (~> 1.2)
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
@@ -85,6 +87,7 @@ GEM
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
@@ -93,10 +96,10 @@ GEM
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
- optparse (~> 0.1.1)
+ optparse (>= 0.1.1, < 1.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
- security (= 0.1.3)
+ security (= 0.1.5)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (~> 3)
@@ -105,11 +108,11 @@ GEM
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
- xcpretty-travis-formatter (>= 0.0.3)
+ xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
gh_inspector (1.1.3)
- google-apis-androidpublisher_v3 (0.51.0)
+ google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a)
- google-apis-core (0.11.2)
+ google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -117,24 +120,23 @@ GEM
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
- webrick
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
- google-apis-storage_v1 (0.19.0)
- google-apis-core (>= 0.9.0, < 2.a)
- google-cloud-core (1.6.0)
- google-cloud-env (~> 1.0)
+ google-apis-storage_v1 (0.31.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-cloud-core (1.7.0)
+ google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
- google-cloud-errors (1.3.1)
- google-cloud-storage (1.44.0)
+ google-cloud-errors (1.4.0)
+ google-cloud-storage (1.47.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
- google-apis-storage_v1 (~> 0.19.0)
+ google-apis-storage_v1 (~> 0.31.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
@@ -149,30 +151,33 @@ GEM
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.2)
- json (2.6.3)
- jwt (2.7.1)
+ json (2.7.2)
+ jwt (2.8.1)
+ base64
mini_magick (4.12.0)
mini_mime (1.1.5)
multi_json (1.15.0)
- multipart-post (2.3.0)
+ multipart-post (2.4.1)
nanaimo (0.3.0)
naturally (2.2.1)
- optparse (0.1.1)
+ nkf (0.2.0)
+ optparse (0.5.0)
os (1.1.4)
- plist (3.7.0)
- public_suffix (5.0.3)
- rake (13.1.0)
+ plist (3.7.1)
+ public_suffix (5.0.5)
+ rake (13.2.1)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
- rexml (3.2.6)
+ rexml (3.2.8)
+ strscan (>= 3.0.9)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
- security (0.1.3)
- signet (0.18.0)
+ security (0.1.5)
+ signet (0.19.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
@@ -180,25 +185,22 @@ GEM
simctl (1.6.10)
CFPropertyList
naturally
+ strscan (3.1.0)
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
- tty-screen (0.8.1)
+ tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
- unf (0.1.4)
- unf_ext
- unf_ext (0.0.8.2)
unicode-display_width (2.5.0)
- webrick (1.8.1)
word_wrap (1.0.0)
xcode-install (2.8.1)
claide (>= 0.9.1)
fastlane (>= 2.1.0, < 3.0.0)
- xcodeproj (1.23.0)
+ xcodeproj (1.24.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
diff --git a/LuasKit/AppMode.swift b/LuasKit/AppMode.swift
new file mode 100644
index 0000000..a3602e1
--- /dev/null
+++ b/LuasKit/AppMode.swift
@@ -0,0 +1,34 @@
+//
+// Created by Roland Gropmair on 27/05/2024.
+// Copyright © 2024 mApps.ie. All rights reserved.
+//
+
+import Foundation
+
+/// The way the user decided how current station should be determined
+public enum AppMode: Equatable {
+
+ /// need location
+ case closest
+ case closestOtherLine
+
+ /// no location required, because user selected specific station (via various options)
+ case favourite(TrainStation)
+ case nearby(TrainStation)
+ case specific(TrainStation)
+ case recents(TrainStation)
+
+ public var specificStation: TrainStation? {
+ switch self {
+
+ case .closest, .closestOtherLine:
+ return nil
+ case .favourite(let station), .nearby(let station), .specific(let station), .recents(let station):
+ return station
+ }
+ }
+
+ public var needsLocation: Bool {
+ self == .closest || self == .closestOtherLine
+ }
+}
diff --git a/LuasKit/AppModel+Codable.swift b/LuasKit/AppModel+Codable.swift
index dc36459..61ca5b4 100644
--- a/LuasKit/AppModel+Codable.swift
+++ b/LuasKit/AppModel+Codable.swift
@@ -5,7 +5,7 @@
import Foundation
-extension AppModel.AppMode: Codable {
+extension AppMode: Codable {
// https://stackoverflow.com/questions/69979095/codable-enum-with-arguments-and-fails-at-compile-time
diff --git a/LuasKit/AppModel+CustomStringConvertible.swift b/LuasKit/AppModel+CustomStringConvertible.swift
index 5abbd89..ff84bf8 100644
--- a/LuasKit/AppModel+CustomStringConvertible.swift
+++ b/LuasKit/AppModel+CustomStringConvertible.swift
@@ -5,7 +5,7 @@
import Foundation
-extension AppModel.AppState: CustomStringConvertible {
+extension AppState: CustomStringConvertible {
public var description: String {
switch self {
@@ -30,7 +30,7 @@ extension AppModel.AppState: CustomStringConvertible {
}
}
-extension AppModel.AppMode: CustomStringConvertible {
+extension AppMode: CustomStringConvertible {
public var description: String {
switch self {
diff --git a/LuasKit/AppModel.swift b/LuasKit/AppModel.swift
index 34bd565..d351ced 100644
--- a/LuasKit/AppModel.swift
+++ b/LuasKit/AppModel.swift
@@ -10,56 +10,6 @@ import SwiftUI
// @Observable does not work - circular reference?
public class AppModel: ObservableObject {
- /// state machine, drives UI
- public enum AppState {
-
- case idle
-
- case gettingLocation
- case locationAuthorizationUnknown
- case errorGettingLocation(String)
-
- case errorGettingStation(String)
- /// in case the user is too far away from Dublin area
-
- case loadingDueTimes(TrainStation, TrainsByDirection?)
- case errorGettingDueTimes(TrainStation, String)
-
- case foundDueTimes(TrainsByDirection)
-
- public init(_ state: AppState) {
- self = state
- }
- }
-
- /// how user decided how current station should be determined
- public enum AppMode: Equatable {
-
- /// need location
- case closest
- case closestOtherLine
-
- /// no location required, because user selected specific station (via various options)
- case favourite(TrainStation)
- case nearby(TrainStation)
- case specific(TrainStation)
- case recents(TrainStation)
-
- public var specificStation: TrainStation? {
- switch self {
-
- case .closest, .closestOtherLine:
- return nil
- case .favourite(let station), .nearby(let station), .specific(let station), .recents(let station):
- return station
- }
- }
-
- public var needsLocation: Bool {
- self == .closest || self == .closestOtherLine
- }
- }
-
@Published public var appState: AppState = .idle
@Published public var appMode: AppMode = .closest {
@@ -94,6 +44,11 @@ public class AppModel: ObservableObject {
@Published public var locationDenied: Bool = false
+#if DEBUG
+ // so we can simulate app state in a sequence
+ public let mockMode = false
+#endif
+
public init() {
if let storedAppModeData = UserDefaults.standard.object(forKey: "AppMode") as? Data,
let storedAppMode = try? JSONDecoder().decode(AppMode.self, from: storedAppModeData)
diff --git a/LuasKit/AppState.swift b/LuasKit/AppState.swift
new file mode 100644
index 0000000..ee64413
--- /dev/null
+++ b/LuasKit/AppState.swift
@@ -0,0 +1,41 @@
+//
+// Created by Roland Gropmair on 27/05/2024.
+// Copyright © 2024 mApps.ie. All rights reserved.
+//
+
+import Foundation
+
+/// App's state machine, drives UI
+public enum AppState {
+
+ case idle
+
+ case gettingLocation
+ case locationAuthorizationUnknown
+ case errorGettingLocation(String)
+
+ /// in case the user is too far away from Dublin area
+ case errorGettingStation(String)
+
+ // cachedTrains is optional because when we load that station for the first time, we won't have any trains cached
+ case loadingDueTimes(TrainStation, cachedTrains: TrainsByDirection?)
+
+ case errorGettingDueTimes(TrainStation, String)
+
+ case foundDueTimes(TrainsByDirection)
+
+ public init(_ state: AppState) {
+ self = state
+ }
+}
+
+public extension AppState {
+
+ var isLoading: Bool {
+ if case .loadingDueTimes = self {
+ return true
+ } else {
+ return false
+ }
+ }
+}
diff --git a/LuasKit/Info.plist b/LuasKit/Info.plist
index c0701c6..b73dca0 100644
--- a/LuasKit/Info.plist
+++ b/LuasKit/Info.plist
@@ -17,6 +17,6 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
+ 2
diff --git a/LuasKit/LuasStrings.swift b/LuasKit/LuasStrings.swift
index c3fa120..bfc0662 100644
--- a/LuasKit/LuasStrings.swift
+++ b/LuasKit/LuasStrings.swift
@@ -75,6 +75,8 @@ public struct LuasStrings {
public static let noTrains = NSLocalizedString("No trains due", comment: "String shown when no trains in specified direction")
+ public static let trainsLoading = NSLocalizedString("Loading trains...", comment: "String shown when trains are loading for station")
+
public static let locationDeniedFooter = NSLocalizedString(
"Unable to determine closest station, because location access not granted or disabled.\nYou can still select a station manually.",
comment: "Label shown when location access was denied by user, to explain why nearby stations won't work")
diff --git a/LuasWatch Watch App/Coordinator+Animiation.swift b/LuasWatch Watch App/Coordinator+Animiation.swift
index 39779b9..425190e 100644
--- a/LuasWatch Watch App/Coordinator+Animiation.swift
+++ b/LuasWatch Watch App/Coordinator+Animiation.swift
@@ -8,13 +8,16 @@ import SwiftUI
extension Coordinator {
- func updateWithAnimation(to state: AppModel.AppState) {
+ func updateWithAnimation(to state: AppState) {
withAnimation {
- DispatchQueue.main.async { [weak self] in
- self?.appModel.appState = state
+ if Thread.isMainThread {
+ appModel.appState = state
+ } else {
+ DispatchQueue.main.async { [weak self] in
+ self?.appModel.appState = state
+ }
}
}
-
}
}
diff --git a/LuasWatch Watch App/Coordinator+LocationDelegate.swift b/LuasWatch Watch App/Coordinator+LocationDelegate.swift
index f9e2970..b1e884f 100644
--- a/LuasWatch Watch App/Coordinator+LocationDelegate.swift
+++ b/LuasWatch Watch App/Coordinator+LocationDelegate.swift
@@ -106,9 +106,9 @@ extension Coordinator: LocationDelegate {
updateWithAnimation(
to: .loadingDueTimes(
closestStation,
- cachedTrains.trains))
+ cachedTrains: cachedTrains.trains))
} else {
- updateWithAnimation(to: .loadingDueTimes(closestStation, nil))
+ updateWithAnimation(to: .loadingDueTimes(closestStation, cachedTrains: nil))
}
} else {
myPrint("SidebarView is up -> ignore so we don't interfere UI")
diff --git a/LuasWatch Watch App/Coordinator.swift b/LuasWatch Watch App/Coordinator.swift
index c6b3ceb..51c3193 100644
--- a/LuasWatch Watch App/Coordinator.swift
+++ b/LuasWatch Watch App/Coordinator.swift
@@ -40,6 +40,23 @@ class Coordinator: NSObject {
func start() {
+ #if DEBUG
+ if appModel.mockMode == true {
+ // force specific app flow for debugging and taking screenshots
+
+ appModel.appState = .gettingLocation
+
+ executeAfterDelay { [weak self] in
+ self?.appModel.appState = .errorGettingLocation("error getting location")
+
+ self?.executeAfterDelay {
+ self?.appModel.appState = .locationAuthorizationUnknown
+ }
+ }
+ return
+ }
+ #endif
+
// //////////////////////////////////////////////
// step 1: if required, determine location
location.delegate = self
@@ -129,4 +146,12 @@ class Coordinator: NSObject {
}
}
}
+
+ #if DEBUG
+ private func executeAfterDelay(_ block: @escaping () -> Void) {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
+ block()
+ }
+ }
+ #endif
}
diff --git a/LuasWatch Watch App/LuasWatchApp.swift b/LuasWatch Watch App/LuasWatchApp.swift
index 7fe0626..983fa68 100644
--- a/LuasWatch Watch App/LuasWatchApp.swift
+++ b/LuasWatch Watch App/LuasWatchApp.swift
@@ -8,7 +8,7 @@ import SwiftData
import SwiftUI
@main
-struct LuasWatch_Watch_AppApp: App {
+struct LuasWatch_Watch_App: App {
@Environment(\.scenePhase) var scenePhase
@@ -62,6 +62,13 @@ struct LuasWatch_Watch_AppApp: App {
case .active:
myPrint("App became active -> fireAndScheduleTimer")
+
+ #if DEBUG
+ if appModel.mockMode == true {
+ return
+ }
+ #endif
+
mainCoordinator.fireAndScheduleTimer()
@unknown default:
diff --git a/LuasWatch Watch App/Previews/PreviewsData.swift b/LuasWatch Watch App/Previews/PreviewsData.swift
index b9775e8..7b55433 100644
--- a/LuasWatch Watch App/Previews/PreviewsData.swift
+++ b/LuasWatch Watch App/Previews/PreviewsData.swift
@@ -13,6 +13,10 @@ import SwiftUI
latitude: CLLocationDegrees(53.3292817872831),
longitude: CLLocationDegrees(-6.33382500275916))
+ let locationMarlborough = CLLocation(
+ latitude: CLLocationDegrees(53.3492448734525),
+ longitude: CLLocationDegrees(-6.25773158174389))
+
let userLocation = CLLocation(
latitude: locationBluebell.coordinate.latitude + 0.00425,
longitude: locationBluebell.coordinate.longitude + 0.005)
@@ -95,14 +99,22 @@ import SwiftUI
inbound: [trainGreen3],
outbound: [trainGreen1, trainGreen2])
- private let stationOneWay = TrainStation(
+ let noTrainsGreen = TrainsByDirection(
+ trainStation: stationGreen, inbound: [], outbound: [])
+
+ let stationOneWay = TrainStation(
stationId: "stationId",
- stationIdShort: "LUAS69",
+ stationIdShort: "LUAS62",
shortCode: "MAR",
route: .green,
name: "Marlborough",
- location: locationBluebell,
+ location: locationMarlborough,
stationType: .oneway)
+ let trainsMarlborough = TrainsByDirection(
+ trainStation: stationOneWay,
+ inbound: [trainGreen3],
+ outbound: [])
+
let trainsOneWayStation = TrainsByDirection(
trainStation: stationOneWay,
inbound: [trainGreen2, trainGreen3],
diff --git a/LuasWatch Watch App/Previews/PreviewsAllStates.swift b/LuasWatch Watch App/Previews/PreviewsErrorStates.swift
similarity index 73%
rename from LuasWatch Watch App/Previews/PreviewsAllStates.swift
rename to LuasWatch Watch App/Previews/PreviewsErrorStates.swift
index 3546c5d..3a7eaa0 100644
--- a/LuasWatch Watch App/Previews/PreviewsAllStates.swift
+++ b/LuasWatch Watch App/Previews/PreviewsErrorStates.swift
@@ -7,7 +7,7 @@ import LuasKit
import SwiftUI
#if DEBUG
- private func luasView(state: AppModel.AppState) -> some View {
+ private func luasView(state: AppState) -> some View {
let appModel = AppModel(state)
appModel.appMode = .favourite(stationGreen)
@@ -36,19 +36,7 @@ import SwiftUI
luasView(state: .errorGettingStation("Some internal error getting station."))
}
- #Preview("loading") {
- luasView(state: .loadingDueTimes(stationGreen, nil))
- }
-
- #Preview("loading (cached)") {
- luasView(state: .loadingDueTimes(stationGreen, trainsGreen))
- }
-
#Preview("errLoading") {
luasView(state: .errorGettingDueTimes(stationGreen, "Error loading due times - could not access internet?"))
}
-
- #Preview("OK") {
- luasView(state: .foundDueTimes(trainsGreen))
- }
#endif
diff --git a/LuasWatch Watch App/Previews/PreviewsLoadingStates.swift b/LuasWatch Watch App/Previews/PreviewsLoadingStates.swift
new file mode 100644
index 0000000..af082c1
--- /dev/null
+++ b/LuasWatch Watch App/Previews/PreviewsLoadingStates.swift
@@ -0,0 +1,38 @@
+//
+// Created by Roland Gropmair on 14/05/2024.
+// Copyright © 2024 mApps.ie. All rights reserved.
+//
+
+import LuasKit
+import SwiftUI
+
+#if DEBUG
+ private func luasView(state: AppState) -> some View {
+ let appModel = AppModel(state)
+ appModel.appMode = .favourite(stationGreen)
+
+ return LuasMainScreen()
+ .environmentObject(appModel)
+ .modelContainer(Previews().container)
+ }
+
+ #Preview("loading") {
+ luasView(state: .loadingDueTimes(stationGreen, cachedTrains: nil))
+ }
+
+ #Preview("loading (cached)") {
+ luasView(state: .loadingDueTimes(stationGreen, cachedTrains: trainsGreen))
+ }
+
+ #Preview("loading 1Way (cached)") {
+ luasView(state: .loadingDueTimes(stationOneWay, cachedTrains: trainsMarlborough))
+ }
+
+ #Preview("noTrains") {
+ luasView(state: .foundDueTimes(noTrainsGreen))
+ }
+
+ #Preview("OK") {
+ luasView(state: .foundDueTimes(trainsGreen))
+ }
+#endif
diff --git a/LuasWatch Watch App/Views/DetailView/DoubleTimetableView.swift b/LuasWatch Watch App/Views/DetailView/DoubleTimetableView.swift
index 6369dcc..0046d69 100644
--- a/LuasWatch Watch App/Views/DetailView/DoubleTimetableView.swift
+++ b/LuasWatch Watch App/Views/DetailView/DoubleTimetableView.swift
@@ -8,8 +8,12 @@ import SwiftUI
struct DoubleTimetableView: View {
+ @EnvironmentObject private var appModel: AppModel
+
let trainsByDirection: TrainsByDirection
- var isLoading: Bool
+}
+
+extension DoubleTimetableView {
var body: some View {
@@ -25,7 +29,7 @@ struct DoubleTimetableView: View {
due: $0.dueTimeDescription2)
}
if trainsByDirection.inboundHasOverflowSmall {
- OverflowView()
+ OverflowDotsView()
}
Spacer()
}
@@ -43,12 +47,12 @@ struct DoubleTimetableView: View {
due: $0.dueTimeDescription2)
}
if trainsByDirection.outboundHasOverflowSmall {
- OverflowView()
+ OverflowDotsView()
}
Spacer()
}
}
.timeTableStyle()
- .opacity(isLoading ? 0.52 : 1.0)
+ .opacity(appModel.appState.isLoading ? 0.52 : 1.0)
}
}
diff --git a/LuasWatch Watch App/Views/DetailView/LuasTextView.swift b/LuasWatch Watch App/Views/DetailView/LuasTextView.swift
index 4940888..1f98fbc 100644
--- a/LuasWatch Watch App/Views/DetailView/LuasTextView.swift
+++ b/LuasWatch Watch App/Views/DetailView/LuasTextView.swift
@@ -9,9 +9,17 @@ struct LuasTextView: View {
var text: String
var body: some View {
- Text(text)
- .multilineTextAlignment(.center)
- .frame(idealHeight: .greatestFiniteMagnitude)
- .padding(.horizontal, 8)
+ HStack {
+ Spacer()
+ Text(text)
+ .font(.caption2)
+ .monospaced()
+ Spacer()
+ }
+ .foregroundColor(.yellow)
+ .timeTableStyle()
+ .toolbar {
+ ToolbarInactive()
+ }
}
}
diff --git a/LuasWatch Watch App/Views/DetailView/OverflowView.swift b/LuasWatch Watch App/Views/DetailView/OverflowDotsView.swift
similarity index 88%
rename from LuasWatch Watch App/Views/DetailView/OverflowView.swift
rename to LuasWatch Watch App/Views/DetailView/OverflowDotsView.swift
index 607f1ee..5aa543c 100644
--- a/LuasWatch Watch App/Views/DetailView/OverflowView.swift
+++ b/LuasWatch Watch App/Views/DetailView/OverflowDotsView.swift
@@ -5,7 +5,7 @@
import SwiftUI
-struct OverflowView: View {
+struct OverflowDotsView: View {
var body: some View {
Text("...")
.offset(CGSize(width: 0, height: -6))
diff --git a/LuasWatch Watch App/Views/DetailView/SimpleTimetableView.swift b/LuasWatch Watch App/Views/DetailView/SimpleTimetableView.swift
index 90081c3..1403ece 100644
--- a/LuasWatch Watch App/Views/DetailView/SimpleTimetableView.swift
+++ b/LuasWatch Watch App/Views/DetailView/SimpleTimetableView.swift
@@ -8,6 +8,8 @@ import SwiftUI
struct SimpleTimetableView: View {
+ @EnvironmentObject private var appModel: AppModel
+
let trainsByDirection: TrainsByDirection
let direction: Direction
}
@@ -15,8 +17,10 @@ struct SimpleTimetableView: View {
extension SimpleTimetableView {
var body: some View {
+
var trains = [Train]()
var hasOverflow = false
+
switch direction {
/// noOverflowLarge cuts off after 6 - WIP: show overflow in subsequent tabView
case .inbound:
@@ -30,6 +34,9 @@ extension SimpleTimetableView {
trains = trainsByDirection.inbound
}
+ // we should always have train here, see where we're calling this view from
+ assert(trains.count > 0)
+
return VStack {
ForEach(trains, id: \.id) {
DueView(
@@ -37,10 +44,11 @@ extension SimpleTimetableView {
due: $0.dueTimeDescription2)
}
if hasOverflow {
- OverflowView()
+ OverflowDotsView()
}
Spacer()
}
.timeTableStyle()
+ .opacity(appModel.appState.isLoading ? 0.52 : 1.0)
}
}
diff --git a/LuasWatch Watch App/Views/DetailView/StationTimesView.swift b/LuasWatch Watch App/Views/DetailView/StationTimesView.swift
index 2eb76a9..37e1472 100644
--- a/LuasWatch Watch App/Views/DetailView/StationTimesView.swift
+++ b/LuasWatch Watch App/Views/DetailView/StationTimesView.swift
@@ -13,8 +13,8 @@ struct StationTimesView: View {
@State private var direction: Direction = .both
- let trains: TrainsByDirection
- var isLoading: Bool = false
+ let trainStation: TrainStation
+ let trains: TrainsByDirection?
}
extension StationTimesView {
@@ -24,71 +24,85 @@ extension StationTimesView {
NavigationStack {
VStack {
- Text(trains.trainStation.name)
+ Text(trainStation.name)
.font(.title3)
.padding(.bottom)
Spacer()
- if trains.trainStation.allowsSwitchingDirection {
-
- switch direction {
-
- case .inbound:
- if trains.inbound.isEmpty {
- NoTrainsView()
- .timeTableStyle()
- } else {
- SimpleTimetableView(
- trainsByDirection: trains, direction: .inbound)
- }
-
- case .outbound:
- if trains.outbound.isEmpty {
- NoTrainsView()
- .timeTableStyle()
- } else {
- SimpleTimetableView(
- trainsByDirection: trains, direction: .outbound)
- }
-
- case .both:
- DoubleTimetableView(
- trainsByDirection: trains, isLoading: isLoading)
- }
+ if let trains {
+
+ timetableView(for: trains)
} else {
- // we have a .terminal or .oneway station -> only show the inbound or outbound trains
- if !trains.inbound.isEmpty {
+ // no cachedTrains: we're loading that station for the first time
+ TrainsViewLoading()
+ .timeTableStyle()
+ }
+ }
- SimpleTimetableView(
- trainsByDirection: trains, direction: .inbound)
+ .onAppear {
+ direction = modelContext.directionConsideringStationType(for: trainStation.shortCode)
+ }
- } else if !trains.outbound.isEmpty {
+ .toolbar {
+ StationToolbar(
+ direction: $direction,
+ trainStation: trainStation)
+ }
+ }
+ }
- SimpleTimetableView(
- trainsByDirection: trains, direction: .outbound)
+ @ViewBuilder
+ fileprivate func timetableView(for trains: TrainsByDirection) -> some View {
+
+ if trains.trainStation.allowsSwitchingDirection {
+ switch direction {
+
+ case .inbound:
+ if trains.inbound.isEmpty {
+ NoTrainsView()
+ .timeTableStyle()
} else {
+ SimpleTimetableView(
+ trainsByDirection: trains, direction: .inbound)
+ }
+ case .outbound:
+ if trains.outbound.isEmpty {
NoTrainsView()
.timeTableStyle()
+ } else {
+ SimpleTimetableView(
+ trainsByDirection: trains, direction: .outbound)
}
- }
+ case .both:
+ DoubleTimetableView(
+ trainsByDirection: trains)
}
- .onAppear {
- direction = modelContext.directionConsideringStationType(for: trains.trainStation.shortCode)
- }
+ } else {
- .toolbar {
- StationToolbar(
- direction: $direction,
- trains: trains,
- isLoading: isLoading)
+ // we have a .terminal or .oneway station -> only show the inbound or outbound trains
+ if !trains.inbound.isEmpty {
+
+ SimpleTimetableView(
+ trainsByDirection: trains, direction: .inbound)
+
+ } else if !trains.outbound.isEmpty {
+
+ SimpleTimetableView(
+ trainsByDirection: trains, direction: .outbound)
+
+ } else {
+
+ NoTrainsView()
+ .timeTableStyle()
}
+
}
}
}
diff --git a/LuasWatch Watch App/Views/DetailView/StationToolbar.swift b/LuasWatch Watch App/Views/DetailView/StationToolbar.swift
index 30a8865..e17e29f 100644
--- a/LuasWatch Watch App/Views/DetailView/StationToolbar.swift
+++ b/LuasWatch Watch App/Views/DetailView/StationToolbar.swift
@@ -10,6 +10,8 @@ struct StationToolbar {
@Environment(\.modelContext) private var modelContext
+ @EnvironmentObject private var appModel: AppModel
+
// have to let SwiftUI know that underlying context has changed - can we avoid the isFavourite state?
@State private var isFavourite: Bool = false
@@ -17,8 +19,7 @@ struct StationToolbar {
@Binding var direction: Direction
- let trains: TrainsByDirection
- let isLoading: Bool
+ let trainStation: TrainStation
}
extension StationToolbar: ToolbarContent {
@@ -42,13 +43,13 @@ extension StationToolbar: ToolbarContent {
direction = direction.next()
}
- let shortCode = trains.trainStation.shortCode
+ let shortCode = trainStation.shortCode
myPrint("\(#function) createOrUpdate \(shortCode) to \(direction)")
modelContext.createOrUpdate(shortCode: shortCode, to: direction)
} label: {
- if trains.trainStation.allowsSwitchingDirection {
+ if trainStation.allowsSwitchingDirection {
switch direction {
case .inbound:
@@ -65,24 +66,24 @@ extension StationToolbar: ToolbarContent {
}
}
.onAppear {
- isSwitchingDirectionEnabled = trains.trainStation.allowsSwitchingDirection
+ isSwitchingDirectionEnabled = trainStation.allowsSwitchingDirection
}
.disabled(!isSwitchingDirectionEnabled)
- if isLoading {
+ if appModel.appState.isLoading {
Text(LuasStrings.loadingDueTimes)
.font(.subheadline)
}
/// Favourite
Button {
- modelContext.toggleFavouriteStation(shortCode: trains.trainStation.shortCode)
+ modelContext.toggleFavouriteStation(shortCode: trainStation.shortCode)
isFavourite.toggle()
} label: {
isFavourite ? Image(systemName: "heart.fill") : Image(systemName: "heart")
}
.onAppear {
- isFavourite = modelContext.doesFavouriteStationExist(shortCode: trains.trainStation.shortCode)
+ isFavourite = modelContext.doesFavouriteStationExist(shortCode: trainStation.shortCode)
}
}
}
diff --git a/LuasWatch Watch App/Views/DetailView/StationToolbarLoading.swift b/LuasWatch Watch App/Views/DetailView/StationToolbarLoading.swift
new file mode 100644
index 0000000..639ec84
--- /dev/null
+++ b/LuasWatch Watch App/Views/DetailView/StationToolbarLoading.swift
@@ -0,0 +1,52 @@
+//
+// Created by Roland Gropmair on 10/02/2024.
+// Copyright © 2024 mApps.ie. All rights reserved.
+//
+
+import LuasKit
+import SwiftUI
+
+struct StationToolbarLoading {
+
+ var isFavourite: Bool
+ var direction: Direction
+ var isSwitchingDirectionEnabled: Bool
+}
+
+extension StationToolbarLoading: ToolbarContent {
+
+ var body: some ToolbarContent {
+
+ ToolbarItemGroup(placement: .bottomBar) {
+
+ /// Change direction
+ Button {
+ // nop
+ } label: {
+
+ if isSwitchingDirectionEnabled {
+
+ switch direction {
+ case .inbound:
+ Image(systemName: "arrow.left")
+ case .outbound:
+ Image(systemName: "arrow.right")
+ case .both:
+ Image(systemName: "arrow.left.arrow.right")
+ }
+
+ } else {
+ // if station is terminal or a one way stop: show hard coded arrow; we disable the button below
+ Image(systemName: "arrow.right")
+ }
+ }
+ .disabled(!isSwitchingDirectionEnabled)
+
+ Text(LuasStrings.loadingDueTimes)
+ .font(.subheadline)
+
+ /// Favourite
+ isFavourite ? Image(systemName: "heart.fill") : Image(systemName: "heart")
+ }
+ }
+}
diff --git a/LuasWatch Watch App/Views/DetailView/StationView.swift b/LuasWatch Watch App/Views/DetailView/StationView.swift
index 9d29ea7..b4e243e 100644
--- a/LuasWatch Watch App/Views/DetailView/StationView.swift
+++ b/LuasWatch Watch App/Views/DetailView/StationView.swift
@@ -35,18 +35,14 @@ extension StationView: View {
case .errorGettingStation(let errorMessage):
LuasTextView(text: errorMessage)
- case .loadingDueTimes(_, let trains):
- if let trains {
- StationTimesView(trains: trains, isLoading: true)
- } else {
- LuasTextView(text: appModel.appState.description)
- }
+ case .loadingDueTimes(let trainStation, let cachedTrains):
+ StationTimesView(trainStation: trainStation, trains: cachedTrains)
case .errorGettingDueTimes(_, let message):
LuasTextView(text: message)
case .foundDueTimes(let trains):
- StationTimesView(trains: trains)
+ StationTimesView(trainStation: trains.trainStation, trains: trains)
}
}
}
diff --git a/LuasWatch Watch App/Views/DetailView/ToolbarInactive.swift b/LuasWatch Watch App/Views/DetailView/ToolbarInactive.swift
new file mode 100644
index 0000000..74b191f
--- /dev/null
+++ b/LuasWatch Watch App/Views/DetailView/ToolbarInactive.swift
@@ -0,0 +1,36 @@
+//
+// Created by Roland Gropmair on 10/02/2024.
+// Copyright © 2024 mApps.ie. All rights reserved.
+//
+
+import LuasKit
+import SwiftUI
+
+struct ToolbarInactive {
+ // no properties
+}
+
+extension ToolbarInactive: ToolbarContent {
+
+ var body: some ToolbarContent {
+
+ ToolbarItemGroup(placement: .bottomBar) {
+
+ /// Change direction
+ Button {
+ // nop
+ } label: {
+ Image(systemName: "arrow.left.arrow.right")
+ }
+ .disabled(true)
+
+ /// Favourite
+ Button {
+ // nop
+ } label: {
+ Image(systemName: "heart")
+ }
+ .disabled(true)
+ }
+ }
+}
diff --git a/LuasWatch Watch App/Views/DetailView/TrainsViewLoading.swift b/LuasWatch Watch App/Views/DetailView/TrainsViewLoading.swift
new file mode 100644
index 0000000..7153077
--- /dev/null
+++ b/LuasWatch Watch App/Views/DetailView/TrainsViewLoading.swift
@@ -0,0 +1,22 @@
+//
+// Created by Roland Gropmair on 25/05/2024.
+// Copyright © 2024 mApps.ie. All rights reserved.
+//
+
+import LuasKit
+import SwiftUI
+
+struct TrainsViewLoading: View {
+
+ var body: some View {
+ VStack {
+ Spacer()
+ Text(LuasStrings.trainsLoading)
+ .font(.caption2)
+ .monospaced()
+ .foregroundColor(.yellow)
+ .frame(maxWidth: .infinity)
+ Spacer()
+ }
+ }
+}
diff --git a/LuasWatch Watch App/Views/Sidebar/FavouritesSidebarView.swift b/LuasWatch Watch App/Views/Sidebar/FavouritesSidebarView.swift
index 522f626..ddecbe0 100644
--- a/LuasWatch Watch App/Views/Sidebar/FavouritesSidebarView.swift
+++ b/LuasWatch Watch App/Views/Sidebar/FavouritesSidebarView.swift
@@ -73,7 +73,7 @@ extension FavouritesSidebarView: View {
#if DEBUG
#Preview("Favourites") {
- let appModel = AppModel(AppModel.AppState(.foundDueTimes(trainsOneWayStation)))
+ let appModel = AppModel(AppState(.foundDueTimes(trainsOneWayStation)))
appModel.appMode = .favourite(stationGreen)
return List {
diff --git a/LuasWatch Watch App/Views/Sidebar/NearbyStationsView.swift b/LuasWatch Watch App/Views/Sidebar/NearbyStationsView.swift
index bbf2f36..bfa30b4 100644
--- a/LuasWatch Watch App/Views/Sidebar/NearbyStationsView.swift
+++ b/LuasWatch Watch App/Views/Sidebar/NearbyStationsView.swift
@@ -50,7 +50,7 @@ extension NearbyStationsView: View {
#if DEBUG
#Preview("Nearby") {
- let appModel = AppModel(AppModel.AppState(.foundDueTimes(trainsOneWayStation)))
+ let appModel = AppModel(AppState(.foundDueTimes(trainsOneWayStation)))
appModel.appMode = .favourite(stationGreen)
return List {
diff --git a/LuasWatch Watch App/Views/Sidebar/SidebarView.swift b/LuasWatch Watch App/Views/Sidebar/SidebarView.swift
index ddd0247..e2be70a 100644
--- a/LuasWatch Watch App/Views/Sidebar/SidebarView.swift
+++ b/LuasWatch Watch App/Views/Sidebar/SidebarView.swift
@@ -101,7 +101,7 @@ extension SidebarView: View {
#Preview("Sidebar") {
@State var selectedStation: TrainStation?
- let appModel = AppModel(AppModel.AppState(.foundDueTimes(trainsOneWayStation)))
+ let appModel = AppModel(AppState(.foundDueTimes(trainsOneWayStation)))
appModel.appMode = .favourite(stationGreen)
return SidebarView(selectedStation: $selectedStation)
@@ -112,7 +112,7 @@ extension SidebarView: View {
#Preview("Sidebar (loc denied)") {
@State var selectedStation: TrainStation?
- let appModel = AppModel(AppModel.AppState(.foundDueTimes(trainsOneWayStation)))
+ let appModel = AppModel(AppState(.foundDueTimes(trainsOneWayStation)))
appModel.appMode = .favourite(stationGreen)
appModel.locationDenied = true
diff --git a/LuasWatch Watch App/Views/Sidebar/StationsModal.swift b/LuasWatch Watch App/Views/Sidebar/StationsModal.swift
index 894320c..1b5f272 100644
--- a/LuasWatch Watch App/Views/Sidebar/StationsModal.swift
+++ b/LuasWatch Watch App/Views/Sidebar/StationsModal.swift
@@ -47,7 +47,7 @@ extension StationsModal {
#if DEBUG
#Preview("Stations Modal (green)") {
- let appModel = AppModel(AppModel.AppState(.foundDueTimes(trainsGreen)))
+ let appModel = AppModel(AppState(.foundDueTimes(trainsGreen)))
appModel.appMode = .specific(stationGreen)
// highlight in preview doesn't work?? does it used StoredAppMode?
diff --git a/LuasWatch.xcodeproj/project.pbxproj b/LuasWatch.xcodeproj/project.pbxproj
index b4e2cf0..118832f 100644
--- a/LuasWatch.xcodeproj/project.pbxproj
+++ b/LuasWatch.xcodeproj/project.pbxproj
@@ -88,11 +88,17 @@
AB925F492B6FCD0800F23497 /* StationDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB925F482B6FCD0800F23497 /* StationDirection.swift */; };
AB925F4B2B715FAD00F23497 /* AppModel+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB925F4A2B715FAD00F23497 /* AppModel+Codable.swift */; };
AB925F4D2B715FCD00F23497 /* AppModel+CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB925F4C2B715FCD00F23497 /* AppModel+CustomStringConvertible.swift */; };
+ AB9D3F092BF409EA00584B69 /* PreviewsLoadingStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB9D3F082BF409EA00584B69 /* PreviewsLoadingStates.swift */; };
ABA68B242AF43977002A9F0D /* LuasMainScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABA68B232AF43977002A9F0D /* LuasMainScreen.swift */; };
ABC207AB2B78E34A00C1F8F7 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC207AA2B78E34A00C1F8F7 /* Utils.swift */; };
ABC207AD2B8156BB00C1F8F7 /* CLAuthorizationStatus+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC207AC2B8156BB00C1F8F7 /* CLAuthorizationStatus+Extensions.swift */; };
ABC207AF2B81653200C1F8F7 /* Coordinator+Animiation.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC207AE2B81653200C1F8F7 /* Coordinator+Animiation.swift */; };
- ABCDB4C42B5DADE40068EFAA /* PreviewsAllStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABCDB4C32B5DADE40068EFAA /* PreviewsAllStates.swift */; };
+ ABC24A7B2C0289D30004014B /* StationToolbarLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC24A7A2C0289D30004014B /* StationToolbarLoading.swift */; };
+ ABC24A7D2C028E120004014B /* TrainsViewLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC24A7C2C028E120004014B /* TrainsViewLoading.swift */; };
+ ABC24A7F2C0525F50004014B /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC24A7E2C0525F50004014B /* AppState.swift */; };
+ ABC24A812C0526950004014B /* AppMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC24A802C0526950004014B /* AppMode.swift */; };
+ ABC24A832C052DBB0004014B /* ToolbarInactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC24A822C052DBB0004014B /* ToolbarInactive.swift */; };
+ ABCDB4C42B5DADE40068EFAA /* PreviewsErrorStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABCDB4C32B5DADE40068EFAA /* PreviewsErrorStates.swift */; };
ABD1CA4E2B781DDD0015DB81 /* DueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABD1CA4D2B781DDD0015DB81 /* DueView.swift */; };
ABD1CA502B781F730015DB81 /* LuasTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABD1CA4F2B781F730015DB81 /* LuasTextView.swift */; };
ABD1CA522B78211D0015DB81 /* StationTimesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABD1CA512B78211D0015DB81 /* StationTimesView.swift */; };
@@ -104,7 +110,7 @@
ABE7F1A02B8A62FC00AE0644 /* NoTrainsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABE7F19F2B8A62FC00AE0644 /* NoTrainsView.swift */; };
ABE7F1A22B8A63EC00AE0644 /* View+LuasFormatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABE7F1A12B8A63EC00AE0644 /* View+LuasFormatting.swift */; };
ABF0388F2B9265FD000034D6 /* DoubleTimetableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABF0388E2B9265FD000034D6 /* DoubleTimetableView.swift */; };
- ABF038912B926AB5000034D6 /* OverflowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABF038902B926AB5000034D6 /* OverflowView.swift */; };
+ ABF038912B926AB5000034D6 /* OverflowDotsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABF038902B926AB5000034D6 /* OverflowDotsView.swift */; };
ABF038932B933639000034D6 /* StationsModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABF038922B933639000034D6 /* StationsModal.swift */; };
/* End PBXBuildFile section */
@@ -304,12 +310,18 @@
AB925F482B6FCD0800F23497 /* StationDirection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationDirection.swift; sourceTree = ""; };
AB925F4A2B715FAD00F23497 /* AppModel+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppModel+Codable.swift"; sourceTree = ""; };
AB925F4C2B715FCD00F23497 /* AppModel+CustomStringConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppModel+CustomStringConvertible.swift"; sourceTree = ""; };
+ AB9D3F082BF409EA00584B69 /* PreviewsLoadingStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewsLoadingStates.swift; sourceTree = ""; };
ABA68B232AF43977002A9F0D /* LuasMainScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LuasMainScreen.swift; sourceTree = ""; };
ABAFF5B424ED58A8004DB119 /* LuasPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = LuasPlayground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
ABC207AA2B78E34A00C1F8F7 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; };
ABC207AC2B8156BB00C1F8F7 /* CLAuthorizationStatus+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CLAuthorizationStatus+Extensions.swift"; sourceTree = ""; };
ABC207AE2B81653200C1F8F7 /* Coordinator+Animiation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Coordinator+Animiation.swift"; sourceTree = ""; };
- ABCDB4C32B5DADE40068EFAA /* PreviewsAllStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewsAllStates.swift; sourceTree = ""; };
+ ABC24A7A2C0289D30004014B /* StationToolbarLoading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StationToolbarLoading.swift; sourceTree = ""; };
+ ABC24A7C2C028E120004014B /* TrainsViewLoading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrainsViewLoading.swift; sourceTree = ""; };
+ ABC24A7E2C0525F50004014B /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; };
+ ABC24A802C0526950004014B /* AppMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppMode.swift; sourceTree = ""; };
+ ABC24A822C052DBB0004014B /* ToolbarInactive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarInactive.swift; sourceTree = ""; };
+ ABCDB4C32B5DADE40068EFAA /* PreviewsErrorStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewsErrorStates.swift; sourceTree = ""; };
ABD1CA4D2B781DDD0015DB81 /* DueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DueView.swift; sourceTree = ""; };
ABD1CA4F2B781F730015DB81 /* LuasTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LuasTextView.swift; sourceTree = ""; };
ABD1CA512B78211D0015DB81 /* StationTimesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationTimesView.swift; sourceTree = ""; };
@@ -321,7 +333,7 @@
ABE7F19F2B8A62FC00AE0644 /* NoTrainsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoTrainsView.swift; sourceTree = ""; };
ABE7F1A12B8A63EC00AE0644 /* View+LuasFormatting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+LuasFormatting.swift"; sourceTree = ""; };
ABF0388E2B9265FD000034D6 /* DoubleTimetableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleTimetableView.swift; sourceTree = ""; };
- ABF038902B926AB5000034D6 /* OverflowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverflowView.swift; sourceTree = ""; };
+ ABF038902B926AB5000034D6 /* OverflowDotsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverflowDotsView.swift; sourceTree = ""; };
ABF038922B933639000034D6 /* StationsModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationsModal.swift; sourceTree = ""; };
/* End PBXFileReference section */
@@ -571,6 +583,8 @@
AB3CC01A2AE4094F002AA60A /* LuasKit.h */,
AB3CC0112AE4094F002AA60A /* Models */,
AB3CC0072AE4094F002AA60A /* API */,
+ ABC24A7E2C0525F50004014B /* AppState.swift */,
+ ABC24A802C0526950004014B /* AppMode.swift */,
AB8220782B49F79200022CA0 /* AppModel.swift */,
AB925F4A2B715FAD00F23497 /* AppModel+Codable.swift */,
AB925F4C2B715FCD00F23497 /* AppModel+CustomStringConvertible.swift */,
@@ -624,7 +638,8 @@
AB695E5E2AE41CAC00B6DB99 /* Previews */ = {
isa = PBXGroup;
children = (
- ABCDB4C32B5DADE40068EFAA /* PreviewsAllStates.swift */,
+ ABCDB4C32B5DADE40068EFAA /* PreviewsErrorStates.swift */,
+ AB9D3F082BF409EA00584B69 /* PreviewsLoadingStates.swift */,
ABD285802B5DB3F00000011C /* PreviewsStationView.swift */,
ABE7F19B2B8A5BEA00AE0644 /* PreviewsStationView_EdgeCases.swift */,
AB695E602AE41CAC00B6DB99 /* PreviewsData.swift */,
@@ -678,10 +693,13 @@
ABD1CA512B78211D0015DB81 /* StationTimesView.swift */,
ABD1CA532B7826610015DB81 /* SimpleTimetableView.swift */,
ABF0388E2B9265FD000034D6 /* DoubleTimetableView.swift */,
- ABF038902B926AB5000034D6 /* OverflowView.swift */,
+ ABF038902B926AB5000034D6 /* OverflowDotsView.swift */,
ABD1CA552B7828870015DB81 /* StationToolbar.swift */,
+ ABC24A7A2C0289D30004014B /* StationToolbarLoading.swift */,
+ ABC24A822C052DBB0004014B /* ToolbarInactive.swift */,
ABD1CA4D2B781DDD0015DB81 /* DueView.swift */,
ABE7F19F2B8A62FC00AE0644 /* NoTrainsView.swift */,
+ ABC24A7C2C028E120004014B /* TrainsViewLoading.swift */,
ABE7F1A12B8A63EC00AE0644 /* View+LuasFormatting.swift */,
);
path = DetailView;
@@ -1147,6 +1165,7 @@
files = (
AB3CC01E2AE4094F002AA60A /* Parser.swift in Sources */,
AB3CC0272AE4094F002AA60A /* TrainStations.swift in Sources */,
+ ABC24A812C0526950004014B /* AppMode.swift in Sources */,
AB3CC0252AE4094F002AA60A /* TrainStation.swift in Sources */,
AB3CC0262AE4094F002AA60A /* Train.swift in Sources */,
AB925F4D2B715FCD00F23497 /* AppModel+CustomStringConvertible.swift in Sources */,
@@ -1156,6 +1175,7 @@
AB3CC02A2AE4094F002AA60A /* MyUserDefaults.swift in Sources */,
AB3CC0242AE4094F002AA60A /* TrainsByDirection.swift in Sources */,
AB3CC0292AE4094F002AA60A /* Direction.swift in Sources */,
+ ABC24A7F2C0525F50004014B /* AppState.swift in Sources */,
AB8220792B49F79200022CA0 /* AppModel.swift in Sources */,
AB3CC01B2AE4094F002AA60A /* APIParser.swift in Sources */,
AB925F4B2B715FAD00F23497 /* AppModel+Codable.swift in Sources */,
@@ -1172,16 +1192,19 @@
buildActionMask = 2147483647;
files = (
AB38CED02B52F28C0074D901 /* CLLocation+Extensions.swift in Sources */,
+ ABC24A7D2C028E120004014B /* TrainsViewLoading.swift in Sources */,
+ ABC24A7B2C0289D30004014B /* StationToolbarLoading.swift in Sources */,
AB695E7D2AE41CAC00B6DB99 /* Coordinator.swift in Sources */,
ABD1CA562B7828870015DB81 /* StationToolbar.swift in Sources */,
AB0BFCF12B42ECEF0060AAD5 /* FavouriteStation.swift in Sources */,
- ABF038912B926AB5000034D6 /* OverflowView.swift in Sources */,
+ ABF038912B926AB5000034D6 /* OverflowDotsView.swift in Sources */,
AB695E762AE41CAC00B6DB99 /* GrantLocationAuthView.swift in Sources */,
ABD285812B5DB3F00000011C /* PreviewsStationView.swift in Sources */,
AB695E332AE41C1D00B6DB99 /* LuasWatchApp.swift in Sources */,
ABC207AF2B81653200C1F8F7 /* Coordinator+Animiation.swift in Sources */,
ABE7F1A02B8A62FC00AE0644 /* NoTrainsView.swift in Sources */,
AB0BFCED2B42E7780060AAD5 /* FavouritesSidebarView.swift in Sources */,
+ ABC24A832C052DBB0004014B /* ToolbarInactive.swift in Sources */,
AB0A86CE2B461767002E7E31 /* Collection+Extensions.swift in Sources */,
AB0BFCEB2B42E58A0060AAD5 /* SidebarView.swift in Sources */,
AB38CECE2B52F16C0074D901 /* Coordinator+LocationDelegate.swift in Sources */,
@@ -1191,7 +1214,7 @@
ABE7F19C2B8A5BEA00AE0644 /* PreviewsStationView_EdgeCases.swift in Sources */,
AB0BFCE92B42E5430060AAD5 /* StationView.swift in Sources */,
AB695E712AE41CAC00B6DB99 /* PreviewsData.swift in Sources */,
- ABCDB4C42B5DADE40068EFAA /* PreviewsAllStates.swift in Sources */,
+ ABCDB4C42B5DADE40068EFAA /* PreviewsErrorStates.swift in Sources */,
AB89FB8B2B49B7B50020A943 /* LineRow.swift in Sources */,
AB0A86CC2B460C74002E7E31 /* AllStationsListView.swift in Sources */,
ABE7F1A22B8A63EC00AE0644 /* View+LuasFormatting.swift in Sources */,
@@ -1204,6 +1227,7 @@
AB0BFCEF2B42ECA80060AAD5 /* Previews.swift in Sources */,
ABD1CA502B781F730015DB81 /* LuasTextView.swift in Sources */,
AB0BFCF42B43129F0060AAD5 /* NearbyStationsView.swift in Sources */,
+ AB9D3F092BF409EA00584B69 /* PreviewsLoadingStates.swift in Sources */,
ABD1CA522B78211D0015DB81 /* StationTimesView.swift in Sources */,
AB925F492B6FCD0800F23497 /* StationDirection.swift in Sources */,
AB89FB892B49B6BE0020A943 /* StationRow.swift in Sources */,
@@ -1280,7 +1304,7 @@
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 2H43Y8J8SC;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -1303,7 +1327,7 @@
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = 2H43Y8J8SC;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -1576,9 +1600,9 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 122;
+ CURRENT_PROJECT_VERSION = 123;
DEBUG_INFORMATION_FORMAT = dwarf;
- DYLIB_CURRENT_VERSION = 121;
+ DYLIB_CURRENT_VERSION = 2;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1597,7 +1621,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
- MARKETING_VERSION = 2.0;
+ MARKETING_VERSION = 2.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -1644,9 +1668,9 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 122;
+ CURRENT_PROJECT_VERSION = 123;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DYLIB_CURRENT_VERSION = 121;
+ DYLIB_CURRENT_VERSION = 2;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1659,7 +1683,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
- MARKETING_VERSION = 2.0;
+ MARKETING_VERSION = 2.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index 3be2c28..c648f3b 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -8,7 +8,7 @@ default_platform(:ios)
platform :ios do
before_all do |lane, options|
- xcversion(version: "15.0")
+ xcversion(version: "15.4")
end
def build_app