Skip to content

Commit 8c3730a

Browse files
committed
feat: folder bookmarks, unify quick actions, routes and hand-off user activities
Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>
1 parent 61edf8f commit 8c3730a

File tree

14 files changed

+1088
-227
lines changed

14 files changed

+1088
-227
lines changed

Localizable.xcstrings

Lines changed: 697 additions & 93 deletions
Large diffs are not rendered by default.

Sushitrain.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
65C9E1542C42B9AE00EDCE6C /* ExtraFilesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65C9E1532C42B9AE00EDCE6C /* ExtraFilesView.swift */; };
6363
65D40FCC2CBDB10600CAE91A /* SelectiveFolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65D40FCB2CBDB10300CAE91A /* SelectiveFolderView.swift */; };
6464
65DE11A72D69CC60002FDB08 /* PreviewWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DE11A62D69CC5E002FDB08 /* PreviewWindow.swift */; };
65+
65E359732EAE1EB20051D5A9 /* Route.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E359722EAE1EB00051D5A9 /* Route.swift */; };
6566
65F15BFC2CA03CBE00E13DDD /* BackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F15BFB2CA03CBA00E13DDD /* BackgroundManager.swift */; };
6667
65F15BFD2CA03DCE00E13DDD /* SushitrainCore.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65AE125A2C3AB03E00E721D4 /* SushitrainCore.xcframework */; };
6768
65F15C012CA06B2300E13DDD /* UploadsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65F15C002CA06B2100E13DDD /* UploadsView.swift */; };
@@ -154,6 +155,7 @@
154155
65C9E1532C42B9AE00EDCE6C /* ExtraFilesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtraFilesView.swift; sourceTree = "<group>"; };
155156
65D40FCB2CBDB10300CAE91A /* SelectiveFolderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectiveFolderView.swift; sourceTree = "<group>"; };
156157
65DE11A62D69CC5E002FDB08 /* PreviewWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewWindow.swift; sourceTree = "<group>"; };
158+
65E359722EAE1EB00051D5A9 /* Route.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Route.swift; sourceTree = "<group>"; };
157159
65F15BFB2CA03CBA00E13DDD /* BackgroundManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundManager.swift; sourceTree = "<group>"; };
158160
65F15C002CA06B2100E13DDD /* UploadsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadsView.swift; sourceTree = "<group>"; };
159161
65F15C022CA1F85D00E13DDD /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = "<group>"; };
@@ -240,6 +242,7 @@
240242
65DE11A62D69CC5E002FDB08 /* PreviewWindow.swift */,
241243
65AE123B2C39F34B00E721D4 /* PrivacyInfo.xcprivacy */,
242244
657603F02D045D0900B36D78 /* QuickActions.swift */,
245+
65E359722EAE1EB00051D5A9 /* Route.swift */,
243246
65F15C022CA1F85D00E13DDD /* SafariView.swift */,
244247
652879A72C4D06F5004AF46F /* SearchView.swift */,
245248
65D40FCB2CBDB10300CAE91A /* SelectiveFolderView.swift */,
@@ -401,6 +404,7 @@
401404
657603EF2D0457B400B36D78 /* Intents.swift in Sources */,
402405
654272982C7BC77000F2CEF8 /* FileQuickLookView.swift in Sources */,
403406
6510F19E2DAA52CF003E4D3C /* FolderSettings.swift in Sources */,
407+
65E359732EAE1EB20051D5A9 /* Route.swift in Sources */,
404408
6596E2422E04ABD70069B31C /* DownloadsView.swift in Sources */,
405409
6505643F2CA98D22009FFFB9 /* ThumbnailView.swift in Sources */,
406410
65F7EFF72E5F58B8008A64E0 /* SupportView.swift in Sources */,

Sushitrain/App.swift

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import AppIntents
1111

1212
@main
1313
struct SushitrainApp: App {
14-
static var browseFolderActivityID = "nl.t-shaped.Sushitrain.browse-folder"
15-
static var viewFileActivityID = "nl.t-shaped.Sushitrain.view-file"
14+
static var viewRouteActivityID = "nl.t-shaped.Sushitrain.view-route"
1615

1716
@State fileprivate var appState: AppState
1817

@@ -181,12 +180,8 @@ struct SushitrainApp: App {
181180
#endif
182181

183182
#if os(macOS)
184-
.onContinueUserActivity(SushitrainApp.browseFolderActivityID) { ua in
185-
Log.info("Receive browse-folder handoff at app level: \(String(describing: ua.userInfo))")
186-
}
187-
188-
.onContinueUserActivity(SushitrainApp.viewFileActivityID) { ua in
189-
Log.info("Receive view-file handoff at app level: \(String(describing: ua.userInfo))")
183+
.onContinueUserActivity(SushitrainApp.viewRouteActivityID) { ua in
184+
Log.info("Receive view-route handoff at app level: \(String(describing: ua.userInfo))")
190185
}
191186
#endif
192187
}

Sushitrain/AppState.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,6 @@ class SushitrainDelegate: NSObject {
9595
@AppStorage("ignoreLongTimeNoSeeDevices") var ignoreLongTimeNoSeeDevices = Set<String>()
9696
@AppStorage("ignoreDiscoveredDevices") var ignoreDiscoveredDevices = Set<String>()
9797

98-
#if os(iOS)
99-
// Whether to re-enable hideHiddenFolders when app comes to the foreground
100-
@AppStorage("rehideHiddenFoldersOnActivate") var rehideHiddenFoldersOnActivate: Bool = false
101-
#endif
102-
10398
@AppStorage("onboardingVersionShown") var onboardingVersionShown = 0
10499

105100
// Number of seconds after which we remind the user that a device hasn't connected in a while
@@ -114,6 +109,14 @@ class SushitrainDelegate: NSObject {
114109
// Whether to show the onboarding on the next startup, regardless of whether it has been shown before
115110
@AppStorage("forceOnboardingOnNextStartup") var forceOnboardingOnNextStartup = false
116111

112+
#if os(iOS)
113+
// Whether to re-enable hideHiddenFolders when app comes to the foreground
114+
@AppStorage("rehideHiddenFoldersOnActivate") var rehideHiddenFoldersOnActivate: Bool = false
115+
116+
// Bookmarked places in the app
117+
@AppStorage("bookmarkedRoutes") var bookmarkedRoutes: [URL] = []
118+
#endif
119+
117120
#if os(macOS)
118121
// The action to perform when a user clicks a folder in the dock menu
119122
@AppStorage("menuFolderAction") var menuFolderAction: MenuFolderAction = .finderExceptSelective
@@ -723,11 +726,19 @@ struct SyncState {
723726
#endif
724727
}
725728

729+
#if os(iOS)
730+
private var bookmarkedRoutesAsRoute: [Route] {
731+
return self.userSettings.bookmarkedRoutes.compactMap { url in
732+
return Route(url: url)
733+
}
734+
}
735+
#endif
736+
726737
func sleep() async {
727738
self.stopNetworkMonitor()
728739

729740
#if os(iOS)
730-
QuickActionService.provideActions()
741+
QuickActionService.provideActions(bookmarks: self.bookmarkedRoutesAsRoute)
731742

732743
if userSettings.lingeringEnabled {
733744
Log.info("Background time remaining: \(UIApplication.shared.backgroundTimeRemaining)")
@@ -788,6 +799,7 @@ struct SyncState {
788799
#if os(iOS)
789800
self.backgroundManager.inactivate()
790801
self.reduceMemoryUsage()
802+
QuickActionService.provideActions(bookmarks: self.bookmarkedRoutesAsRoute)
791803
#endif
792804
}
793805
#if os(iOS)

Sushitrain/BrowserListView.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ struct BrowserListView: View {
4747
Section {
4848
ForEach(subdirectories, id: \.self) { (subDirEntry: SushitrainEntry) in
4949
let fileName = subDirEntry.fileName()
50-
NavigationLink(destination: BrowserView(folder: folder, prefix: "\(prefix)\(fileName)/")) {
50+
NavigationLink(
51+
destination: BrowserView(folder: folder, prefix: "\(prefix)\(fileName)/", userSettings: appState.userSettings)
52+
) {
5153
ItemSelectSwipeView(file: subDirEntry) {
5254
// Subdirectory name
5355
HStack(spacing: 9.0) {
@@ -145,7 +147,8 @@ struct EntryView: View {
145147
if targetEntry.isDirectory() {
146148
if let targetFolder = targetEntry.folder {
147149
NavigationLink(
148-
destination: BrowserView(folder: targetFolder, prefix: targetEntry.path() + "/")
150+
destination: BrowserView(
151+
folder: targetFolder, prefix: targetEntry.path() + "/", userSettings: appState.userSettings)
149152
) { self.entryView(entry: entry) }.contextMenu {
150153
NavigationLink(
151154
destination: FileView(file: targetEntry, showPath: self.folder == nil, siblings: nil)
@@ -297,7 +300,9 @@ struct FileEntryLink<Content: View>: View {
297300
// Show 'go to location' in list if we are not in the file's folder already
298301
if self.inFolder == nil {
299302
if let folder = entry.folder {
300-
NavigationLink(destination: BrowserView(folder: folder, prefix: entry.parentPath())) {
303+
NavigationLink(
304+
destination: BrowserView(folder: folder, prefix: entry.parentPath(), userSettings: appState.userSettings)
305+
) {
301306
let parentFolderName = entry.parentFolderName
302307
if parentFolderName.isEmpty {
303308
Label("Go to location", systemImage: "document.circle")

Sushitrain/BrowserTableView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ struct BrowserTableView: View {
207207
// Symlink to a directory
208208
if targetEntry.isDirectory() {
209209
if let targetFolder = targetEntry.folder {
210-
BrowserView(folder: targetFolder, prefix: targetEntry.path() + "/")
210+
BrowserView(folder: targetFolder, prefix: targetEntry.path() + "/", userSettings: appState.userSettings)
211211
}
212212
}
213213
else {
@@ -233,7 +233,7 @@ struct BrowserTableView: View {
233233
}
234234
else if oe.isDirectory() {
235235
if honorTapToPreview {
236-
BrowserView(folder: folder, prefix: oe.path() + "/")
236+
BrowserView(folder: folder, prefix: oe.path() + "/", userSettings: appState.userSettings)
237237
}
238238
else {
239239
FileView(file: oe, showPath: false, siblings: self.entries)

Sushitrain/BrowserView.swift

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// You can obtain one at https://mozilla.org/MPL/2.0/.
66
import SwiftUI
77
import QuickLook
8+
import UniformTypeIdentifiers
89
@preconcurrency import SushitrainCore
910

1011
enum BrowserViewStyle: String {
@@ -26,8 +27,10 @@ private struct FolderPopoverView: View {
2627

2728
struct BrowserView: View {
2829
@Environment(AppState.self) private var appState
30+
2931
var folder: SushitrainFolder
3032
var prefix: String
33+
@ObservedObject var userSettings: AppUserSettings
3134

3235
@State private var showSettings = false
3336
@State private var searchText = ""
@@ -232,14 +235,14 @@ struct BrowserView: View {
232235
dismissButton: .default(Text("OK")))
233236
}
234237

235-
.userActivity(SushitrainApp.browseFolderActivityID) { ua in
238+
.userActivity(SushitrainApp.viewRouteActivityID) { ua in
239+
let routeURL = self.route.url
236240
ua.title = self.folderName
237241
ua.isEligibleForHandoff = true
238-
ua.targetContentIdentifier = "browse:\(self.folder.folderID):\(prefix)" // Not really used
242+
ua.targetContentIdentifier = routeURL.absoluteString
239243
ua.userInfo = [
240244
"version": 1,
241-
"folderID": self.folder.folderID,
242-
"prefix": self.prefix,
245+
"url": routeURL.absoluteString,
243246
]
244247
ua.needsSave = true
245248
}
@@ -375,7 +378,17 @@ struct BrowserView: View {
375378
self.showInFinder()
376379
}.disabled(!canShowInFinder)
377380
#endif
381+
}
378382

383+
#if os(iOS)
384+
Toggle(isOn: Binding(get: { self.isBookmarked }, set: { self.setBookmarked($0) })) {
385+
Label("Bookmark", systemImage: self.isBookmarked ? "bookmark.fill" : "bookmark")
386+
}
387+
#endif
388+
389+
Divider()
390+
391+
if folderExists {
379392
#if os(iOS)
380393
Button("Folder statistics...", systemImage: "chart.pie") {
381394
showFolderStatistics = true
@@ -412,6 +425,25 @@ struct BrowserView: View {
412425
}.disabled(!folderExists)
413426
}
414427

428+
private var route: Route {
429+
return Route.folder(folderID: self.folder.folderID, prefix: self.prefix)
430+
}
431+
432+
#if os(iOS)
433+
private var isBookmarked: Bool {
434+
let url = self.route.url
435+
return userSettings.bookmarkedRoutes.contains(where: { $0 == url })
436+
}
437+
438+
private func setBookmarked(_ fav: Bool) {
439+
let url = self.route.url
440+
userSettings.bookmarkedRoutes.removeAll(where: { $0 == url })
441+
if fav {
442+
userSettings.bookmarkedRoutes.append(url)
443+
}
444+
}
445+
#endif
446+
415447
private func onDrop(_ providers: [NSItemProvider]) async throws {
416448
var urls: [URL] = []
417449

0 commit comments

Comments
 (0)