Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Onboarding Flow #1050

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
42 changes: 42 additions & 0 deletions Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,9 @@
}
}
}
},
"Allow Meshtastic to send notifications for messages, newly discovered nodes and low battery alerts for the connected device." : {

},
"Allow Position Requests" : {
"localizations" : {
Expand Down Expand Up @@ -1764,6 +1767,9 @@
}
}
}
},
"App Notifications" : {

},
"App Settings" : {
"localizations" : {
Expand Down Expand Up @@ -2962,6 +2968,9 @@
}
}
}
},
"Bluetooth" : {

},
"bluetooth.config" : {
"localizations" : {
Expand Down Expand Up @@ -6249,6 +6258,9 @@
}
}
}
},
"Configure notification permissions" : {

},
"Connect to a Node" : {
"localizations" : {
Expand Down Expand Up @@ -6619,6 +6631,9 @@
}
}
}
},
"Continue to next step" : {

},
"Control Type" : {
"localizations" : {
Expand Down Expand Up @@ -6831,6 +6846,9 @@
}
}
}
},
"Critical Alerts" : {

},
"Current Firmware Version: %@" : {
"localizations" : {
Expand Down Expand Up @@ -9449,6 +9467,9 @@
}
}
}
},
"Enable MQTT" : {

},
"Enable Notifications" : {
"localizations" : {
Expand Down Expand Up @@ -10848,6 +10869,9 @@
}
}
}
},
"Get started" : {

},
"Get the latest alpha firmware" : {
"localizations" : {
Expand Down Expand Up @@ -19176,6 +19200,9 @@
}
}
}
},
"Meshtastic" : {

},
"Meshtastic Node %@ has shared channels with you" : {
"localizations" : {
Expand All @@ -19192,6 +19219,9 @@
}
}
}
},
"Meshtastic uses your phone's location to enable a number of features. You can update your location permissions at any time from Settings > App Settings > Open Settings." : {

},
"Meshtastic® Copyright Meshtastic LLC" : {
"localizations" : {
Expand Down Expand Up @@ -21920,6 +21950,9 @@
}
}
}
},
"Phone Location" : {

},
"phone.gps" : {
"localizations" : {
Expand Down Expand Up @@ -26105,6 +26138,9 @@
}
}
}
},
"Send Notifications" : {

},
"Send Reboot OTA" : {
"localizations" : {
Expand Down Expand Up @@ -26732,6 +26768,9 @@
}
}
}
},
"Set up later" : {

},
"set.region" : {
"localizations" : {
Expand Down Expand Up @@ -31368,6 +31407,9 @@
}
}
}
},
"Welcome to" : {

},
"What does the lock mean?" : {
"localizations" : {
Expand Down
22 changes: 18 additions & 4 deletions Meshtastic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
25A978BC2C13F90D0003AAE7 /* MeshtasticProtobufs in Frameworks */ = {isa = PBXBuildFile; productRef = 25A978BB2C13F90D0003AAE7 /* MeshtasticProtobufs */; };
25AECD4F2C2F723200862C8E /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 25AECD4E2C2F723200862C8E /* Localizable.xcstrings */; };
25C49D902C471AEA0024FBD1 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25C49D8F2C471AEA0024FBD1 /* Constants.swift */; };
25CEC8E52C54536000B5F7C9 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25CEC8E42C54536000B5F7C9 /* OnboardingView.swift */; };
25F26B1E2C2F610D00C9CD9D /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD5BB0C2C285F00007E03CA /* Logger.swift */; };
25F26B1F2C2F611300C9CD9D /* AppData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD5BB152C28B1E4007E03CA /* AppData.swift */; };
25F5D5BE2C3F6D87008036E3 /* NavigationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25F5D5BD2C3F6D87008036E3 /* NavigationState.swift */; };
Expand Down Expand Up @@ -281,6 +282,7 @@
251926912C3CB52300249DF5 /* DeleteNodeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteNodeButton.swift; sourceTree = "<group>"; };
25AECD4E2C2F723200862C8E /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
25C49D8F2C471AEA0024FBD1 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
25CEC8E42C54536000B5F7C9 /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
25F5D5BD2C3F6D87008036E3 /* NavigationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationState.swift; sourceTree = "<group>"; };
25F5D5BF2C3F6DA6008036E3 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; };
25F5D5C12C3F6E4B008036E3 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -605,6 +607,14 @@
path = Actions;
sourceTree = "<group>";
};
25CEC8E32C54532400B5F7C9 /* Onboarding */ = {
isa = PBXGroup;
children = (
25CEC8E42C54536000B5F7C9 /* OnboardingView.swift */,
);
path = Onboarding;
sourceTree = "<group>";
};
25F5D5BC2C3F6D7B008036E3 /* Router */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -956,12 +966,13 @@
DDC2E18726CE24E40042C5E4 /* Views */ = {
isa = PBXGroup;
children = (
DD47E3D726F2F21A00029299 /* Bluetooth */,
DDC2E18D26CE25CB0042C5E4 /* Helpers */,
DD6D5A312CA1176A00ED3032 /* Layouts */,
C9483F6B2773016700998F6B /* MapKitMap */,
DDC2E18D26CE25CB0042C5E4 /* Helpers */,
DD47E3D726F2F21A00029299 /* Bluetooth */,
DDC2E18B26CE25A70042C5E4 /* Messages */,
DD47E3CA26F0E50300029299 /* Nodes */,
25CEC8E32C54532400B5F7C9 /* Onboarding */,
DD4A911C2708C57100501B7E /* Settings */,
DDC2E18E26CE25FE0042C5E4 /* ContentView.swift */,
);
Expand Down Expand Up @@ -1517,6 +1528,7 @@
DDA9515E2BC6F56F00CEA535 /* IndoorAirQuality.swift in Sources */,
DDDB444E29F8AB0E00EE2349 /* Int.swift in Sources */,
DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */,
25CEC8E52C54536000B5F7C9 /* OnboardingView.swift in Sources */,
DDC4C9FF2A8D982900CE201C /* DetectionSensorConfig.swift in Sources */,
D9C983A22B79D1A600BDBE6A /* RequestPositionButton.swift in Sources */,
DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */,
Expand Down Expand Up @@ -1741,7 +1753,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Meshtastic/Meshtastic.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Meshtastic/Preview Content\"";
Expand All @@ -1758,6 +1770,7 @@
MARKETING_VERSION = 2.5.18;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -1775,7 +1788,7 @@
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Meshtastic/Meshtastic.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Meshtastic/Preview Content\"";
Expand All @@ -1792,6 +1805,7 @@
MARKETING_VERSION = 2.5.18;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down
9 changes: 3 additions & 6 deletions Meshtastic/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ import Combine
import SwiftUI

class AppState: ObservableObject {
@Published
var router: Router
@Published var router: Router

@Published
var unreadChannelMessages: Int
@Published var unreadChannelMessages: Int

@Published
var unreadDirectMessages: Int
@Published var unreadDirectMessages: Int

var totalUnreadMessages: Int {
unreadChannelMessages + unreadDirectMessages
Expand Down
9 changes: 9 additions & 0 deletions Meshtastic/Extensions/UserDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ extension UserDefaults {
case firmwareVersion
case environmentEnableWeatherKit
case enableAdministration
case firstLaunch
case showOnboarding
case onboardingVersion
case testIntEnum
}

Expand Down Expand Up @@ -166,6 +169,12 @@ extension UserDefaults {
@UserDefault(.enableAdministration, defaultValue: false)
static var enableAdministration: Bool

@UserDefault(.firstLaunch, defaultValue: true)
static var firstLaunch: Bool

@UserDefault(.provideLocation, defaultValue: false)
static var showOnboarding: Bool

@UserDefault(.testIntEnum, defaultValue: .one)
static var testIntEnum: TestIntEnum
}
Expand Down
4 changes: 4 additions & 0 deletions Meshtastic/Helpers/BLEManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
lastConnectionError = ""
isSubscribed = true
Logger.mesh.info("🤜 [BLE] Want Config Complete. ID:\(decodedInfo.configCompleteID)")
if UserDefaults.firstLaunch {
UserDefaults.showOnboarding = true
}
if sendTime() {

}
peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected })
// Config conplete returns so we don't read the characteristic again
Expand Down
1 change: 0 additions & 1 deletion Meshtastic/Helpers/LocalNotificationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ class LocalNotificationManager {
// Step 1 Request Permissions for notifications
private func requestAuthorization() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in

if granted == true && error == nil {
self.scheduleNotifications()
}
Expand Down
13 changes: 10 additions & 3 deletions Meshtastic/Helpers/LocationHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate {

// @Published var region = MKCoordinateRegion()
@Published var authorizationStatus: CLAuthorizationStatus?

// The continuation we will use to asynchronously ask the user permission to track their location.
private var permissionContinuation: CheckedContinuation<CLAuthorizationStatus, Never>?

func requestLocationAlwaysPermissions() async -> CLAuthorizationStatus {
self.locationManager.requestAlwaysAuthorization()
return await withCheckedContinuation { continuation in
permissionContinuation = continuation
}
}
override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.pausesLocationUpdatesAutomatically = true
locationManager.allowsBackgroundLocationUpdates = true
locationManager.activityType = .other
}
Expand Down Expand Up @@ -55,14 +64,12 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate {
authorizationStatus = .authorizedAlways
case .authorizedWhenInUse:
authorizationStatus = .authorizedWhenInUse
locationManager.requestLocation()
case .restricted:
authorizationStatus = .restricted
case .denied:
authorizationStatus = .denied
case .notDetermined:
authorizationStatus = .notDetermined
locationManager.requestAlwaysAuthorization()
default:
break
}
Expand Down
6 changes: 3 additions & 3 deletions Meshtastic/Helpers/LocationsHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ import OSLog
}

func startLocationUpdates() {
if self.manager.authorizationStatus == .notDetermined {
self.manager.requestWhenInUseAuthorization()
let status = self.manager.authorizationStatus
guard status == .authorizedAlways || status == .authorizedWhenInUse else {
return
}
Logger.services.info("📍 [App] Starting location updates")
Task {
Expand All @@ -71,7 +72,6 @@ import OSLog
} catch {
Logger.services.error("💥 [App] Could not start location updates: \(error.localizedDescription)")
}
return
}
}

Expand Down
6 changes: 1 addition & 5 deletions Meshtastic/MeshtasticApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ struct MeshtasticAppleApp: App {
@UIApplicationDelegateAdaptor(MeshtasticAppDelegate.self)
private var appDelegate

@ObservedObject
var appState: AppState

// @ObservedObject
// private var bleManager: BLEManager
@ObservedObject var appState: AppState

private let persistenceController: PersistenceController

Expand Down
14 changes: 0 additions & 14 deletions Meshtastic/Views/Bluetooth/Connect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,6 @@ struct Connect: View {
@State var liveActivityStarted = false
@State var selectedPeripherialId = ""

init () {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.getNotificationSettings(completionHandler: { (settings) in
if settings.authorizationStatus == .notDetermined {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound, .criticalAlert]) { success, error in
if success {
Logger.services.info("Notifications are all set!")
} else if let error = error {
Logger.services.error("\(error.localizedDescription)")
}
}
}
})
}
var body: some View {
NavigationStack {
VStack {
Expand Down
Loading
Loading