Skip to content

Commit a0f1333

Browse files
committed
Added new option for selecting custom output folder
1 parent 4981e2d commit a0f1333

File tree

5 files changed

+135
-30
lines changed

5 files changed

+135
-30
lines changed

OpenGpxTracker/GPXFileManager.swift

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,26 @@ class GPXFileManager: NSObject {
2121
/// Folder that where all GPX files are stored
2222
///
2323
class var GPXFilesFolderURL: URL {
24-
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
24+
if let customFolderURL = Preferences.shared.gpxFilesFolderURL {
25+
return customFolderURL
26+
}
27+
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
2528
return documentsUrl
2629
}
2730

2831
///
2932
/// Gets the list of `.gpx` files in Documents directory ordered by modified date
3033
///
3134
class var fileList: [GPXFileInfo] {
32-
var GPXFiles: [GPXFileInfo] = []
3335
let fileManager = FileManager.default
3436
let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
35-
do {
36-
// Get all files from the directory .documentsURL. Of each file get the URL (~path)
37-
// last modification date and file size
38-
if let directoryURLs = try? fileManager.contentsOfDirectory(at: documentsURL,
39-
includingPropertiesForKeys: [.attributeModificationDateKey, .fileSizeKey],
40-
options: .skipsSubdirectoryDescendants) {
41-
//Order files based on the date
42-
// This map creates a tuple (url: URL, modificationDate: String, filesize: Int)
43-
// and then orders it by modificationDate
44-
let sortedURLs = directoryURLs.map { url in
45-
(url: url,
46-
modificationDate: (try? url.resourceValues(forKeys: [.contentModificationDateKey]))?.contentModificationDate ?? Date.distantPast,
47-
fileSize: (try? url.resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? 0)
48-
}
49-
.sorted(by: { $0.1 > $1.1 }) // sort descending modification dates
50-
print(sortedURLs)
51-
//Now we filter GPX Files
52-
for (url, modificationDate, fileSize) in sortedURLs {
53-
if kFileExt.contains(url.pathExtension) {
54-
GPXFiles.append(GPXFileInfo(fileURL: url))
55-
let lastPathComponent = url.deletingPathExtension().lastPathComponent
56-
print("\(modificationDate) \(modificationDate.timeAgo(numericDates: true)) \(fileSize)bytes -- \(lastPathComponent)")
57-
}
58-
}
59-
}
37+
var files = self.fetchFilesList(from: documentsURL)
38+
if let customFolderURL = Preferences.shared.gpxFilesFolderURL {
39+
files += self.fetchFilesList(from: customFolderURL)
40+
}
41+
return files.sorted { lhs, rhs in
42+
return lhs.modifiedDate > rhs.modifiedDate
6043
}
61-
return GPXFiles
6244
}
6345

6446
///
@@ -199,4 +181,38 @@ class GPXFileManager: NSObject {
199181
print(error)
200182
}
201183
}
184+
185+
// MARK: - Private
186+
187+
private class func fetchFilesList(from rootURL: URL) -> [GPXFileInfo] {
188+
var GPXFiles: [GPXFileInfo] = []
189+
let fileManager = FileManager.default
190+
do {
191+
// Get all files from the directory .documentsURL. Of each file get the URL (~path)
192+
// last modification date and file size
193+
if let directoryURLs = try? fileManager.contentsOfDirectory(at: rootURL,
194+
includingPropertiesForKeys: [.attributeModificationDateKey, .fileSizeKey],
195+
options: .skipsSubdirectoryDescendants) {
196+
//Order files based on the date
197+
// This map creates a tuple (url: URL, modificationDate: String, filesize: Int)
198+
// and then orders it by modificationDate
199+
let sortedURLs = directoryURLs.map { url in
200+
(url: url,
201+
modificationDate: (try? url.resourceValues(forKeys: [.contentModificationDateKey]))?.contentModificationDate ?? Date.distantPast,
202+
fileSize: (try? url.resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? 0)
203+
}
204+
.sorted(by: { $0.1 > $1.1 }) // sort descending modification dates
205+
print(sortedURLs)
206+
//Now we filter GPX Files
207+
for (url, modificationDate, fileSize) in sortedURLs {
208+
if kFileExt.contains(url.pathExtension) {
209+
GPXFiles.append(GPXFileInfo(fileURL: url))
210+
let lastPathComponent = url.deletingPathExtension().lastPathComponent
211+
print("\(modificationDate) \(modificationDate.timeAgo(numericDates: true)) \(fileSize)bytes -- \(lastPathComponent)")
212+
}
213+
}
214+
}
215+
}
216+
return GPXFiles
217+
}
202218
}

OpenGpxTracker/Preferences.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ let kDefaultsKeyDateFormatUseUTC: String = "DateFormatPresetUseUTC"
3737
/// Key on Defaults for the current selected date format, to use local Locale or `en_US_POSIX`
3838
let kDefaultsKeyDateFormatUseEN: String = "DateFormatPresetUseEN"
3939

40+
/// Key on Defaults for the folder where GPX files are store, `nil` means default folder
41+
let kDefaultsKeyGPXFilesFolder: String = "GPXFilesFolder"
42+
4043
/// A class to handle app preferences in one single place.
4144
/// When the app starts for the first time the following preferences are set:
4245
///
@@ -80,6 +83,9 @@ class Preferences: NSObject {
8083
///
8184
private var _dateFormatUseEN: Bool = false
8285

86+
///
87+
private var _gpxFilesFolderBookmark: Data? = nil
88+
8389
/// UserDefaults.standard shortcut
8490
private let defaults = UserDefaults.standard
8591

@@ -148,6 +154,12 @@ class Preferences: NSObject {
148154
_dateFormatUseEN = dateFormatENBool
149155
print("** Preferences:: loaded preference from defaults dateFormatPresetENBool \(dateFormatENBool)")
150156
}
157+
158+
// load previous gpx files folder bookmark
159+
if let gpxFilesFolderBookmark = defaults.object(forKey: kDefaultsKeyGPXFilesFolder) as? Data {
160+
_gpxFilesFolderBookmark = gpxFilesFolderBookmark
161+
print("** Preferences:: loaded preference from defaults gpxFilesFolderBookmark \(gpxFilesFolderBookmark)")
162+
}
151163
}
152164

153165
/// If true, user prefers to display imperial units (miles, feets). Otherwise metric units
@@ -280,4 +292,38 @@ class Preferences: NSObject {
280292
defaults.set(newValue, forKey: kDefaultsKeyDateFormatUseEN)
281293
}
282294
}
295+
296+
var gpxFilesFolderURL: URL? {
297+
get {
298+
guard let bookmarkData = self._gpxFilesFolderBookmark else {
299+
return nil
300+
}
301+
do {
302+
var isStale: Bool = false
303+
let url = try URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &isStale)
304+
if isStale {
305+
let newBookmark = try url.bookmarkData()
306+
_gpxFilesFolderBookmark = newBookmark
307+
defaults.set(newBookmark, forKey: kDefaultsKeyGPXFilesFolder)
308+
}
309+
return url
310+
} catch {
311+
print("** Preferences:: failed to retrieve url from bookmark data: \(String(describing: error))")
312+
return nil
313+
}
314+
}
315+
set {
316+
guard let newValue else {
317+
defaults.removeObject(forKey: kDefaultsKeyGPXFilesFolder)
318+
return
319+
}
320+
do {
321+
let newBookmark = try newValue.bookmarkData()
322+
_gpxFilesFolderBookmark = newBookmark
323+
defaults.set(newBookmark, forKey: kDefaultsKeyGPXFilesFolder)
324+
} catch {
325+
print("** Preferences:: failed to generate bookmark data for url: \(String(describing: error))")
326+
}
327+
}
328+
}
283329
}

OpenGpxTracker/PreferencesTableViewController.swift

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Foundation
1111
import UIKit
1212
import CoreLocation
1313
import MapCache
14+
import CoreServices
1415

1516
/// Units Section Id in PreferencesTableViewController
1617
let kUnitsSection = 0
@@ -27,6 +28,9 @@ let kActivityTypeSection = 3
2728
/// Default Name Section Id in PreferencesTableViewController
2829
let kDefaultNameSection = 4
2930

31+
/// GPX Files Location Section Id in PreferencesTableViewController
32+
let kGPXFilesLocationSection = 5
33+
3034
/// Cell Id of the Use Imperial units in UnitsSection
3135
let kUseImperialUnitsCell = 0
3236

@@ -44,7 +48,7 @@ let kClearCacheCell = 1
4448
/// Preferences are kept on UserDefaults with the keys `kDefaultKeyTileServerInt` (Int)
4549
/// and `kDefaultUseCache`` (Bool)
4650
///
47-
class PreferencesTableViewController: UITableViewController, UINavigationBarDelegate {
51+
class PreferencesTableViewController: UITableViewController, UINavigationBarDelegate, UIDocumentPickerDelegate {
4852

4953
/// Delegate for this table view controller.
5054
weak var delegate: PreferencesTableViewControllerDelegate?
@@ -102,7 +106,7 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
102106
/// Returns 4 sections: Units, Cache, Map Source, Activity Type
103107
override func numberOfSections(in tableView: UITableView?) -> Int {
104108
// Return the number of sections.
105-
return 5
109+
return 6
106110
}
107111

108112
/// Returns the title of the existing sections.
@@ -115,6 +119,7 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
115119
case kMapSourceSection: return NSLocalizedString("MAP_SOURCE", comment: "no comment")
116120
case kActivityTypeSection: return NSLocalizedString("ACTIVITY_TYPE", comment: "no comment")
117121
case kDefaultNameSection: return NSLocalizedString("DEFAULT_NAME_SECTION", comment: "no comment")
122+
case kGPXFilesLocationSection: return NSLocalizedString("GPX_FILES_LOCATION_SECTION", comment: "no comment")
118123
default: fatalError("Unknown section")
119124
}
120125
}
@@ -129,6 +134,7 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
129134
case kMapSourceSection: return GPXTileServer.count
130135
case kActivityTypeSection: return CLActivityType.count
131136
case kDefaultNameSection: return 1
137+
case kGPXFilesLocationSection: return 1
132138
default: fatalError("Unknown section")
133139
}
134140
}
@@ -214,6 +220,18 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
214220
cell.accessoryType = .disclosureIndicator
215221
}
216222

223+
if indexPath.section == kGPXFilesLocationSection {
224+
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "GPXFilesLocation")
225+
cell.textLabel?.text = NSLocalizedString("PRESS_TO_SELECT_FOLDER", comment: "no comment")
226+
if let url = preferences.gpxFilesFolderURL {
227+
cell.detailTextLabel?.lineBreakMode = .byTruncatingHead
228+
cell.detailTextLabel?.text = url.lastPathComponent
229+
} else {
230+
cell.detailTextLabel?.text = NSLocalizedString("USING_DEFAULT_FOLDER", comment: "no comment")
231+
}
232+
cell.accessoryType = .disclosureIndicator
233+
}
234+
217235
return cell
218236
}
219237

@@ -312,7 +330,26 @@ class PreferencesTableViewController: UITableViewController, UINavigationBarDele
312330
self.navigationController?.pushViewController(DefaultNameSetupViewController(style: .grouped), animated: true)
313331
}
314332

333+
if indexPath.section == kGPXFilesLocationSection {
334+
print("PreferencesTableView GPX Files Location cell clicked")
335+
let documentVC = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open)
336+
documentVC.allowsMultipleSelection = false
337+
documentVC.delegate = self
338+
self.present(documentVC, animated: true)
339+
}
340+
315341
//unselect row
316342
tableView.deselectRow(at: indexPath, animated: true)
317343
}
344+
345+
// MARK: - UIDocumentPickerDelegate
346+
347+
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
348+
guard let folderURL = urls.first else {
349+
print("Didn't select any folder")
350+
return
351+
}
352+
preferences.gpxFilesFolderURL = folderURL
353+
tableView.reloadData()
354+
}
318355
}

OpenGpxTracker/en.lproj/Localizable.strings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
"CACHE_IS_EMPTY" = "Cache is now empty";
4545
"EDIT_WAYPOINT_NAME_TITLE" = "Edit waypoint name";
4646
"EDIT_WAYPOINT_NAME_MESSAGE" = "Hint: To change the waypoint location drag and drop the pin";
47+
"GPX_FILES_LOCATION_SECTION" = "GPX files location";
48+
"PRESS_TO_SELECT_FOLDER" = "Press to select folder";
49+
"USING_DEFAULT_FOLDER" = "Using default folder";
4750

4851
// Watch
4952
"SENDING" = "Sending:";

OpenGpxTracker/ru.lproj/Localizable.strings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
"CACHE_IS_EMPTY" = "Кэш очищен";
4545
"EDIT_WAYPOINT_NAME_TITLE" = "Введите имя метки";
4646
"EDIT_WAYPOINT_NAME_MESSAGE" = "Подсказка: Чтобы изменить положение метки на карте, перетащите ее";
47+
"GPX_FILES_LOCATION_SECTION" = "Расположение GPX файлов";
48+
"PRESS_TO_SELECT_FOLDER" = "Нажмите, чтобы выбрать";
49+
"USING_DEFAULT_FOLDER" = "Исп. папка по-умолчанию";
4750

4851
// Watch
4952
"SENDING" = "Отправка:";

0 commit comments

Comments
 (0)