aboutsummaryrefslogtreecommitdiff
path: root/iosApp
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2023-09-17 21:56:55 -0600
committerIván Ávalos <avalos@disroot.org>2023-09-17 23:51:33 -0600
commitedbd2c7713a0ba4e7e7a3ba6d59d16861ea4eb23 (patch)
tree885ca095c993c7a661303d215d9be0a6271ba3ea /iosApp
parent7aec305729b872d668df45eae4821b106c1a20cb (diff)
downloadetbsa-trackermap-mobile-edbd2c7713a0ba4e7e7a3ba6d59d16861ea4eb23.tar.gz
etbsa-trackermap-mobile-edbd2c7713a0ba4e7e7a3ba6d59d16861ea4eb23.tar.bz2
etbsa-trackermap-mobile-edbd2c7713a0ba4e7e7a3ba6d59d16861ea4eb23.zip
- [shared] Implement network state monitoring
- [android] UI reacts to network state - [ios] UI reacts to network state
Diffstat (limited to 'iosApp')
-rw-r--r--iosApp/iosApp.xcodeproj/project.pbxproj4
-rw-r--r--iosApp/iosApp/Session/RootView.swift32
-rw-r--r--iosApp/iosApp/Session/RootViewModel.swift36
-rw-r--r--iosApp/iosApp/Shared/OfflineBanner.swift27
-rw-r--r--iosApp/iosApp/Units/UnitsViewModel.swift12
-rw-r--r--iosApp/iosApp/en.lproj/Localizable.strings1
-rw-r--r--iosApp/iosApp/es-419.lproj/Localizable.strings1
-rw-r--r--iosApp/iosApp/iOSApp.swift9
8 files changed, 107 insertions, 15 deletions
diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj
index 2e88271..28bf50a 100644
--- a/iosApp/iosApp.xcodeproj/project.pbxproj
+++ b/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -51,6 +51,7 @@
E3C651E727CB5426002F6F4C /* Tabler in Frameworks */ = {isa = PBXBuildFile; productRef = E3C651E627CB5426002F6F4C /* Tabler */; };
E3C651EA27CB61EE002F6F4C /* GEOSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E3C651E927CB61EE002F6F4C /* GEOSwift */; };
E3E77EE6279E6CE400150070 /* FlowCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3E77EE5279E6CE400150070 /* FlowCollector.swift */; };
+ E3F5F2792AB8080E008A47A7 /* OfflineBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3F5F2782AB8080E008A47A7 /* OfflineBanner.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -121,6 +122,7 @@
E3B5740727F68F5F0018AFCF /* XlsxFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XlsxFile.swift; sourceTree = "<group>"; };
E3B5740927F69F750018AFCF /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
E3E77EE5279E6CE400150070 /* FlowCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowCollector.swift; sourceTree = "<group>"; };
+ E3F5F2782AB8080E008A47A7 /* OfflineBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfflineBanner.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -287,6 +289,7 @@
E31D721427CF159900CDA320 /* SidewaysScroller.swift */,
E3B5740727F68F5F0018AFCF /* XlsxFile.swift */,
E3B5740927F69F750018AFCF /* ShareViewController.swift */,
+ E3F5F2782AB8080E008A47A7 /* OfflineBanner.swift */,
);
path = Shared;
sourceTree = "<group>";
@@ -420,6 +423,7 @@
E3385A4F27B0D8A10025311C /* UnitCommandsViewModel.swift in Sources */,
E392BE1727B77B7E002698F3 /* AppDelegate.swift in Sources */,
E36DF77B27AB740C003C561C /* MapViewController.swift in Sources */,
+ E3F5F2792AB8080E008A47A7 /* OfflineBanner.swift in Sources */,
E33A237327A7581A00DD647F /* Utils.swift in Sources */,
E3E77EE6279E6CE400150070 /* FlowCollector.swift in Sources */,
E33A236527A530F300DD647F /* SmallLabelStyle.swift in Sources */,
diff --git a/iosApp/iosApp/Session/RootView.swift b/iosApp/iosApp/Session/RootView.swift
index 297a2aa..d4f28f5 100644
--- a/iosApp/iosApp/Session/RootView.swift
+++ b/iosApp/iosApp/Session/RootView.swift
@@ -35,16 +35,28 @@ struct RootView: View {
var body: some View {
Group {
- switch rootViewModel.loginState {
- case is SessionController.LoginStateLoading:
- LoadingView()
- case is SessionController.LoginStateSuccess:
- UnitsView()
- default:
- LoginContentView(username: $username,
- password: $password,
- server: $server,
- onLogin: rootViewModel.login)
+ VStack {
+ if (rootViewModel.networkAvailable != true) {
+ OfflineBanner()
+ }
+
+ if rootViewModel.showLoadingView {
+ LoadingView()
+ .frame(minHeight: 0, maxHeight: .infinity)
+ } else {
+ switch rootViewModel.loginState {
+ case is SessionController.LoginStateSuccess:
+ UnitsView()
+ case is SessionController.LoginStateLoading:
+ LoadingView()
+ .frame(minHeight: 0, maxHeight: .infinity)
+ default:
+ LoginContentView(username: $username,
+ password: $password,
+ server: $server,
+ onLogin: rootViewModel.login)
+ }
+ }
}
}.environmentObject(rootViewModel)
}
diff --git a/iosApp/iosApp/Session/RootViewModel.swift b/iosApp/iosApp/Session/RootViewModel.swift
index ec103ba..16f21f3 100644
--- a/iosApp/iosApp/Session/RootViewModel.swift
+++ b/iosApp/iosApp/Session/RootViewModel.swift
@@ -20,14 +20,42 @@ import shared
@MainActor
class RootViewModel: ObservableObject {
+ @Inject private var networkController: NetworkController
@Inject private var sessionController: SessionController
+ @Published var networkAvailable: Bool? = nil
@Published var loginState: SessionController.LoginState = SessionController.LoginStateNothing()
+ @Published var showLoadingView: Bool = false
+
+ var hasSession: Bool{
+ get { return sessionController.hasSession }
+ }
init() {
- let collector = Collector<SessionController.LoginState?>(callback: setLoginState)
- sessionController.loginStateFlow.collect(collector: collector) { _ in }
- restoreSession()
+ let networkCollector = Collector<Bool?>(callback: setNetworkState)
+ networkController.networkAvailable.collect(collector: networkCollector) { _ in }
+ let sessionCollector = Collector<SessionController.LoginState?>(callback: setLoginState)
+ sessionController.loginStateFlow.collect(collector: sessionCollector) { _ in }
+ }
+
+ func setNetworkState(state: Bool?) {
+ print("Network state is: \(state?.description ?? "")")
+ Task { @MainActor in
+ self.networkAvailable = state
+
+ // Wait for internet to restore session
+ if (state == true && sessionController.hasSession) {
+ showLoadingView = false
+ restoreSession()
+ return
+ }
+
+ if (state == nil) {
+ showLoadingView = true
+ } else {
+ showLoadingView = hasSession
+ }
+ }
}
func setLoginState(state: SessionController.LoginState?) {
@@ -38,7 +66,7 @@ class RootViewModel: ObservableObject {
}
func restoreSession() {
- sessionController.restoreSession()
+ sessionController.getSession()
}
private func getFcmToken() -> String? {
diff --git a/iosApp/iosApp/Shared/OfflineBanner.swift b/iosApp/iosApp/Shared/OfflineBanner.swift
new file mode 100644
index 0000000..f29ab7d
--- /dev/null
+++ b/iosApp/iosApp/Shared/OfflineBanner.swift
@@ -0,0 +1,27 @@
+//
+// OfflineBanner.swift
+// iosApp
+//
+// Created by Ivan Avalos on 17/09/23.
+// Copyright © 2023 orgName. All rights reserved.
+//
+
+import SwiftUI
+
+struct OfflineBanner: View {
+ var body: some View {
+ Group {
+ Text("offline")
+ .foregroundColor(.white)
+ .padding(5)
+ }
+ .frame(minWidth: 0, maxWidth: .infinity)
+ .background(Color.red)
+ }
+}
+
+struct OfflineBanner_Previews: PreviewProvider {
+ static var previews: some View {
+ OfflineBanner()
+ }
+}
diff --git a/iosApp/iosApp/Units/UnitsViewModel.swift b/iosApp/iosApp/Units/UnitsViewModel.swift
index 7fcc80e..b12291e 100644
--- a/iosApp/iosApp/Units/UnitsViewModel.swift
+++ b/iosApp/iosApp/Units/UnitsViewModel.swift
@@ -21,6 +21,7 @@ import shared
@MainActor
class UnitsViewModel: ObservableObject {
+ @Inject var networkController: NetworkController
@Inject var unitsController: UnitsController
@Inject var geofenceController: GeofencesController
@@ -34,6 +35,7 @@ class UnitsViewModel: ObservableObject {
var detailsUnit: UnitInformation? = nil
var detailsAction = DeviceRow.Action.details
+ @Published var networkAvailable: Bool? = nil
@Published var searchQuery = "" {
didSet {
unitsDisplayMode = .list
@@ -83,6 +85,9 @@ class UnitsViewModel: ObservableObject {
}
private func setupObservers() {
+ let networkCollector = Collector<Bool?>(callback: setNetworkState)
+ networkController.networkAvailable.collect(collector: networkCollector) { _ in }
+
let unitsCollector = Collector<[UnitInformation]>(callback: setUnits)
unitsController.displayedUnitsFlow.collect(collector: unitsCollector) { _ in }
@@ -90,6 +95,13 @@ class UnitsViewModel: ObservableObject {
geofenceController.geofencesFlow.collect(collector: geofencesCollector) { _ in }
}
+ private func setNetworkState(state: Bool?) {
+ print("Network state is: \(state?.description ?? "")")
+ Task { @MainActor in
+ self.networkAvailable = state
+ }
+ }
+
private func setUnits(units: [UnitInformation]) {
print("Positions")
Task { @MainActor in
diff --git a/iosApp/iosApp/en.lproj/Localizable.strings b/iosApp/iosApp/en.lproj/Localizable.strings
index ca1c3b8..0c5ff4a 100644
--- a/iosApp/iosApp/en.lproj/Localizable.strings
+++ b/iosApp/iosApp/en.lproj/Localizable.strings
@@ -22,6 +22,7 @@
"loading" = "Loading";
"done" = "Done";
+"offline" = "No internet access";
"username" = "Username";
"password" = "Password";
diff --git a/iosApp/iosApp/es-419.lproj/Localizable.strings b/iosApp/iosApp/es-419.lproj/Localizable.strings
index 146da98..995473e 100644
--- a/iosApp/iosApp/es-419.lproj/Localizable.strings
+++ b/iosApp/iosApp/es-419.lproj/Localizable.strings
@@ -22,6 +22,7 @@
"loading" = "Cargando";
"done" = "Hecho";
+"offline" = "No hay acceso a internet";
"username" = "Usuario";
"password" = "Contraseña";
diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift
index 763e0e2..46848ae 100644
--- a/iosApp/iosApp/iOSApp.swift
+++ b/iosApp/iosApp/iOSApp.swift
@@ -53,8 +53,15 @@ struct iOSApp: App {
Resolver.shared.add(CommandsApi.self) { resolver in
return CommandsApi(sessionManager: resolver.resolve())
}
+ Resolver.shared.add(NetworkController.self) { resolver in
+ return NetworkController()
+ }
Resolver.shared.add(SessionController.self) { resolver in
- return SessionController(sessionApi: resolver.resolve(), usersApi: resolver.resolve())
+ return SessionController(
+ sessionManager: resolver.resolve(),
+ sessionApi: resolver.resolve(),
+ usersApi: resolver.resolve()
+ )
}
Resolver.shared.add(UnitsController.self) { resolver in
return UnitsController(devicesApi: resolver.resolve(), positionsApi: resolver.resolve())