Skip to content

Commit 971954b

Browse files
authored
Merge pull request merlos#275 from merlos/enhancement/screen-always-on
Screen always on & display loading toast while loading preferences
2 parents fbd582e + f80b9af commit 971954b

16 files changed

+198
-23
lines changed

OpenGpxTracker/Preferences.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ let kDefaultsKeyDateFormatUseEN: String = "DateFormatPresetUseEN"
4040
/// Key on Defaults for the folder where GPX files are store, `nil` means default folder
4141
let kDefaultsKeyGPXFilesFolder: String = "GPXFilesFolder"
4242

43+
let kDefaultsKeyKeepScreenAlwaysOn: String = "KeepScreenAlwaysOn"
44+
4345
/// A class to handle app preferences in one single place.
4446
/// When the app starts for the first time the following preferences are set:
4547
///
@@ -86,6 +88,9 @@ class Preferences: NSObject {
8688
///
8789
private var _gpxFilesFolderBookmark: Data?
8890

91+
///
92+
private var _keepScreenAlwaysOn: Bool = false
93+
8994
/// UserDefaults.standard shortcut
9095
private let defaults = UserDefaults.standard
9196

@@ -160,6 +165,13 @@ class Preferences: NSObject {
160165
_gpxFilesFolderBookmark = gpxFilesFolderBookmark
161166
print("** Preferences:: loaded preference from defaults gpxFilesFolderBookmark \(gpxFilesFolderBookmark)")
162167
}
168+
169+
// load previous date format, to use EN locale instead of local locale
170+
if let keepScreenAlwaysOnBool = defaults.object(forKey: kDefaultsKeyKeepScreenAlwaysOn) as? Bool {
171+
_keepScreenAlwaysOn = keepScreenAlwaysOnBool
172+
print("** Preferences:: loaded preference from defaults keepScreenAlwaysOn \(keepScreenAlwaysOnBool)")
173+
}
174+
163175
}
164176

165177
/// If true, user prefers to display imperial units (miles, feets). Otherwise metric units
@@ -293,6 +305,18 @@ class Preferences: NSObject {
293305
}
294306
}
295307

308+
/// Get and sets whether to set the screen always On or not
309+
var keepScreenAlwaysOn: Bool {
310+
get {
311+
return _keepScreenAlwaysOn
312+
}
313+
set {
314+
_keepScreenAlwaysOn = newValue
315+
defaults.set(newValue, forKey: kDefaultsKeyKeepScreenAlwaysOn)
316+
print("** Preferences:: setting keepScreenAlwaysOn: \(newValue)")
317+
}
318+
}
319+
296320
var gpxFilesFolderURL: URL? {
297321
get {
298322
guard let bookmarkData = self._gpxFilesFolderBookmark else {

OpenGpxTracker/PreferencesTableViewController.swift

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,33 @@ import CoreServices
1616
/// Units Section Id in PreferencesTableViewController
1717
let kUnitsSection = 0
1818

19+
/// Screen always on section id
20+
let kScreenSection = 1
21+
1922
/// Cache Section Id in PreferencesTableViewController
20-
let kCacheSection = 1
23+
let kCacheSection = 2
2124

2225
/// Map Source Section Id in PreferencesTableViewController
23-
let kMapSourceSection = 2
26+
let kMapSourceSection = 3
2427

2528
/// Activity Type Section Id in PreferencesTableViewController
26-
let kActivityTypeSection = 3
29+
let kActivityTypeSection = 4
2730

2831
/// Default Name Section Id in PreferencesTableViewController
29-
let kDefaultNameSection = 4
32+
let kDefaultNameSection = 5
3033

3134
/// GPX Files Location Section Id in PreferencesTableViewController
32-
let kGPXFilesLocationSection = 5
35+
let kGPXFilesLocationSection = 6
3336

3437
/// Cell Id of the Use Imperial units in UnitsSection
3538
let kUseImperialUnitsCell = 0
3639

40+
41+
/// Cell Id of the keepScreenAlwaysOnl units in ScreenSection
42+
let kKeepScreenAlwaysOnCell = 0
43+
44+
45+
3746
/// Cell Id for Use offline cache in CacheSection of PreferencesTableViewController
3847
let kUseOfflineCacheCell = 0
3948

@@ -119,6 +128,7 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
119128
case kActivityTypeSection: return NSLocalizedString("ACTIVITY_TYPE", comment: "no comment")
120129
case kDefaultNameSection: return NSLocalizedString("DEFAULT_NAME_SECTION", comment: "no comment")
121130
case kGPXFilesLocationSection: return NSLocalizedString("GPX_FILES_FOLDER", comment: "no comment")
131+
case kScreenSection: return NSLocalizedString("SCREEN", comment: "no comment")
122132
default: fatalError("Unknown section")
123133
}
124134
}
@@ -134,6 +144,7 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
134144
case kActivityTypeSection: return CLActivityType.count
135145
case kDefaultNameSection: return 1
136146
case kGPXFilesLocationSection: return 1
147+
case kScreenSection: return 1
137148
default: fatalError("Unknown section")
138149
}
139150
}
@@ -166,6 +177,19 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
166177
}
167178
}
168179

180+
// Units section
181+
if indexPath.section == kScreenSection {
182+
switch indexPath.row {
183+
case kKeepScreenAlwaysOnCell:
184+
cell = UITableViewCell(style: .value1, reuseIdentifier: "CacheCell")
185+
cell.textLabel?.text = NSLocalizedString("KEEP_SCREEN_ALWAYS_ON", comment: "no comment")
186+
if preferences.keepScreenAlwaysOn {
187+
cell.accessoryType = .checkmark
188+
}
189+
default: fatalError("Unknown section")
190+
}
191+
}
192+
169193
// Cache Section
170194
if indexPath.section == kCacheSection {
171195
switch indexPath.row {
@@ -264,6 +288,22 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
264288
}
265289
}
266290

291+
if indexPath.section == kScreenSection {
292+
switch indexPath.row {
293+
case kKeepScreenAlwaysOnCell:
294+
let newKeepScreenAlwaysOn = !preferences.keepScreenAlwaysOn
295+
preferences.keepScreenAlwaysOn = newKeepScreenAlwaysOn
296+
print("PreferencesTableViewController: toggle keep screen always on to \(newKeepScreenAlwaysOn)")
297+
// Update cell UI
298+
tableView.cellForRow(at: indexPath)?.accessoryType = newKeepScreenAlwaysOn ? .checkmark : .none
299+
// Notify the map
300+
self.delegate?.didUpdateKeepScreenAlwaysOn(newKeepScreenAlwaysOn)
301+
default:
302+
fatalError("didSelectRowAt: Unknown cell")
303+
}
304+
}
305+
306+
267307
if indexPath.section == kCacheSection { // 0 -> sets and unsets cache
268308
switch indexPath.row {
269309
case kUseOfflineCacheCell:

OpenGpxTracker/PreferencesTableViewControllerDelegate.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ protocol PreferencesTableViewControllerDelegate: AnyObject {
2222
/// User updated the usage of imperial units
2323
func didUpdateUseImperial(_ newUseImperial: Bool)
2424

25+
/// User updated the keep screen always on option
26+
func didUpdateKeepScreenAlwaysOn(_ newKeepScreenAlwaysOn: Bool)
27+
2528
/// User updated the activity type
2629
func didUpdateActivityType(_ newActivityType: Int)
2730

OpenGpxTracker/Toast.swift

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Toast {
7575
/// Long delay
7676
static let kDelayLong = 5.0
7777

78+
static let kDisabledDelay = -1.0
7879
/// Background opacity
7980
static let kBackgroundOpacity: Double = 0.9
8081

@@ -118,7 +119,10 @@ class Toast {
118119
case center
119120
case top
120121
}
121-
122+
123+
/// Singleton instance of the loading toast
124+
private static var manualToast: UIView?
125+
122126
///
123127
/// Generic implementation to show toast
124128
/// - Parameters:
@@ -169,16 +173,24 @@ class Toast {
169173
}
170174
label.center.x = window.center.x
171175

172-
window.addSubview(label)
173-
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn,
174-
animations: { label.alpha = 1 },
175-
completion: { _ in
176-
UIView.animate(withDuration: 0.5, delay: delay,
177-
options: .curveEaseOut,
178-
animations: {label.alpha = 0 },
179-
completion: {_ in label.removeFromSuperview()
180-
})
181-
})
176+
if delay == kDisabledDelay {
177+
manualToast = label
178+
window.addSubview(manualToast!)
179+
UIView.animate(withDuration: 0.3) {
180+
manualToast!.alpha = 1
181+
}
182+
} else {
183+
window.addSubview(label)
184+
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn,
185+
animations: { label.alpha = 1 },
186+
completion: { _ in
187+
UIView.animate(withDuration: 0.5, delay: delay,
188+
options: .curveEaseOut,
189+
animations: {label.alpha = 0 },
190+
completion: {_ in label.removeFromSuperview()
191+
})
192+
})
193+
}
182194
}
183195

184196
///
@@ -248,4 +260,30 @@ class Toast {
248260
position: position,
249261
delay: delay)
250262
}
251-
}
263+
///
264+
/// Shows a persistent loading toast with a spinner
265+
/// - Parameters:
266+
/// - message: Text message to display alongside the spinner
267+
/// - position: Position within the screen (.bottom, .center, .top)
268+
///
269+
class func showLoading(_ message: String = "Loading...", position: Position = .center) {
270+
showToast(String("⌛️")+" "+message,
271+
textColor: kRegularTextColor,
272+
backgroundColor: kRegularBackgroundColor,
273+
position: position,
274+
delay: kDisabledDelay)
275+
}
276+
277+
///
278+
/// Hides the persistent loading toast
279+
///
280+
class func hideLoading() {
281+
guard let toast = manualToast else { return }
282+
UIView.animate(withDuration: 0.3, animations: {
283+
toast.alpha = 0
284+
}, completion: { _ in
285+
toast.removeFromSuperview()
286+
manualToast = nil
287+
})
288+
}
289+
}

OpenGpxTracker/ViewController.swift

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
433433
useImperial = Preferences.shared.useImperial
434434
// LocationManager.activityType = Preferences.shared.locationActivityType
435435

436+
// Shall it keep the screen always on?
437+
UIApplication.shared.isIdleTimerDisabled = Preferences.shared.keepScreenAlwaysOn
438+
436439
//
437440
// Config user interface
438441
//
@@ -974,13 +977,28 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate {
974977
///
975978
@objc func openPreferencesTableViewController() {
976979
print("openPreferencesTableViewController")
977-
let vc = PreferencesTableViewController(style: .grouped)
978-
vc.delegate = self
979-
let navController = UINavigationController(rootViewController: vc)
980-
self.present(navController, animated: true) { () -> Void in }
980+
981+
// Show loading toast
982+
Toast.showLoading("Loading Preferences...")
983+
984+
// Perform all operations on the main thread
985+
DispatchQueue.main.async {
986+
// Simulate a delay for testing (remove in production)
987+
//Thread.sleep(forTimeInterval: 4.5)
988+
989+
let vc = PreferencesTableViewController(style: .grouped)
990+
vc.delegate = self
991+
let navController = UINavigationController(rootViewController: vc)
992+
993+
// Hide the loading toast and present the view controller
994+
Toast.hideLoading()
995+
self.present(navController, animated: true)
996+
}
981997
}
982-
998+
999+
///
9831000
/// Opens an Activity View Controller to share the file
1001+
///
9841002
@objc func openShare() {
9851003
print("ViewController: Share Button tapped")
9861004

@@ -1313,6 +1331,7 @@ extension ViewController: StopWatchDelegate {
13131331

13141332
extension ViewController: PreferencesTableViewControllerDelegate {
13151333

1334+
13161335
/// Update the activity type that the location manager is using.
13171336
///
13181337
/// When user changes the activity type in preferences, this function is invoked to update the activity type of the location manager.
@@ -1356,7 +1375,14 @@ extension ViewController: PreferencesTableViewControllerDelegate {
13561375
// In regular circunstances it will go to the new units relatively fast.
13571376
speedLabel.text = kUnknownSpeedText
13581377
signalAccuracyLabel.text = kUnknownAccuracyText
1359-
}}
1378+
}
1379+
1380+
// User changed the setting of use imperial units.
1381+
func didUpdateKeepScreenAlwaysOn(_ newKeepScreenAlwaysOn: Bool) {
1382+
print("PreferencesTableViewControllerDelegate:: didUpdateKeepScreenAlwaysOn: \(newKeepScreenAlwaysOn)")
1383+
UIApplication.shared.isIdleTimerDisabled = newKeepScreenAlwaysOn
1384+
}
1385+
}
13601386

13611387
/// Extends `ViewController`` to support `GPXFilesTableViewControllerDelegate` function
13621388
/// that loads into the map a the file selected by the user.

OpenGpxTracker/de.lproj/Localizable.strings

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@
3232
"SHARE" = "Teilen";
3333
"LOADING_FILE" = "Lade GPX Datei...";
3434
"ABOUT" = "Über";
35+
36+
// Preferences
3537
"PREFERENCES" = "Einstellungen";
3638
"UNITS" = "Einheiten";
3739
"CACHE" = "Cache";
40+
"SCREEN" = "Bildschirm";
41+
"KEEP_SCREEN_ALWAYS_ON" = "Bildschirm immer eingeschaltet lassen?";
3842
"MAP_SOURCE" = "Kartentyp";
3943
"ACTIVITY_TYPE" = "Aktivitätstyp";
4044
"USE_IMPERIAL_UNITS" = "Meilen verwenden";

OpenGpxTracker/en.lproj/Localizable.strings

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@
3333
"SHARE" = "Share";
3434
"LOADING_FILE" = "Loading GPX File...";
3535
"ABOUT" = "About";
36+
37+
// Preferences
3638
"PREFERENCES" = "Preferences";
3739
"UNITS" = "Units";
40+
"SCREEN" = "Screen";
41+
"KEEP_SCREEN_ALWAYS_ON" = "Keep screen always on?";
3842
"CACHE" = "Cache";
3943
"MAP_SOURCE" = "Map Source";
4044
"ACTIVITY_TYPE" = "Activity Type";

OpenGpxTracker/es.lproj/Localizable.strings

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@
3333
"SHARE" = "Compartir";
3434
"LOADING_FILE" = "Cargando ...";
3535
"ABOUT" = "Acerca de";
36+
37+
//Preferences
3638
"PREFERENCES" = "Preferencias";
3739
"UNITS" = "Unidades";
3840
"CACHE" = "Caché";
41+
"SCREEN" = "Pantalla";
42+
"KEEP_SCREEN_ALWAYS_ON" = "¿Mantener la pantalla siempre encendida?";
3943
"MAP_SOURCE" = "Mapas";
4044
"ACTIVITY_TYPE" = "Tipo de actividad";
4145
"USE_IMPERIAL_UNITS" = "¿Usar sistema imperial?";

OpenGpxTracker/fi-FI.lproj/Localizable.strings

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ Created by Phiilman on 28.03.20.
3333
"SHARE" = "Jaa";
3434
"LOADING_FILE" = "Lataa GPX tiedostoa";
3535
"ABOUT" = "Tietoja";
36+
37+
// Preferences
3638
"PREFERENCES" = "Asetukset";
3739
"UNITS" = "Yksiköt";
3840
"CACHE" = "Välimuisti";
41+
"SCREEN" = "Näyttö";
42+
"KEEP_SCREEN_ALWAYS_ON" = "Pidä näyttö aina päällä?";
3943
"MAP_SOURCE" = "Kartan lähde";
4044
"ACTIVITY_TYPE" = "Aktiviteetti";
4145
"USE_IMPERIAL_UNITS" = "Käytä Britti-mittoja?";

OpenGpxTracker/fr.lproj/Localizable.strings

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@
3434
"SHARE" = "Partager";
3535
"LOADING_FILE" = "Chargement du fichier GPX...";
3636
"ABOUT" = "A propos";
37+
38+
// Preferences
3739
"PREFERENCES" = "Préférences";
3840
"UNITS" = "Unités";
3941
"CACHE" = "Cache";
42+
"SCREEN" = "Écran";
43+
"KEEP_SCREEN_ALWAYS_ON" = "Garder l'écran toujours allumé ?";
4044
"MAP_SOURCE" = "Source de la carte";
4145
"ACTIVITY_TYPE" = "Type d'activité";
4246
"USE_IMPERIAL_UNITS" = "Utiliser les unités impériales?";

OpenGpxTracker/it.lproj/Localizable.strings

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@
3232
"SHARE" = "Condividere";
3333
"LOADING_FILE" = "Caricare Documento GPX...";
3434
"ABOUT" = "a proposito";
35+
36+
// Preferences
3537
"PREFERENCES" = "Impostazioni";
3638
"UNITS" = "Unità";
3739
"CACHE" = "Cache";
40+
"SCREEN" = "Schermo";
41+
"KEEP_SCREEN_ALWAYS_ON" = "Mantenere lo schermo sempre acceso?";
3842
"MAP_SOURCE" = "Tipo Mappe";
3943
"ACTIVITY_TYPE" = "Tipo di attività";
4044
"USE_IMPERIAL_UNITS" = "Usare Miglia";

0 commit comments

Comments
 (0)