|
@@ -20,9 +20,14 @@ struct LauncherRootView: View {
|
|
|
@AppStorage("customLauncherAppsData") private var customAppsData = ""
|
|
@AppStorage("customLauncherAppsData") private var customAppsData = ""
|
|
|
@AppStorage("launcherAppOrderData") private var appOrderData = ""
|
|
@AppStorage("launcherAppOrderData") private var appOrderData = ""
|
|
|
@AppStorage("pinnedTileIDsData") private var pinnedTileIDsData = ""
|
|
@AppStorage("pinnedTileIDsData") private var pinnedTileIDsData = ""
|
|
|
|
|
+ @AppStorage("statusBarAppIDsData") private var statusBarAppIDsData = ""
|
|
|
|
|
+ @AppStorage("widgetAppIDsData") private var widgetAppIDsData = ""
|
|
|
|
|
+ @AppStorage("hiddenLauncherAppIDsData") private var hiddenLauncherAppIDsData = ""
|
|
|
|
|
|
|
|
private var apps: [LauncherApp] {
|
|
private var apps: [LauncherApp] {
|
|
|
- LauncherApp.sampleApps + customApps + [LauncherApp.createNewTile]
|
|
|
|
|
|
|
+ let hiddenIDs = decodeUUIDSet(from: hiddenLauncherAppIDsData)
|
|
|
|
|
+ let visibleApps = (LauncherApp.sampleApps + customApps).filter { !hiddenIDs.contains($0.id) }
|
|
|
|
|
+ return visibleApps + [LauncherApp.createNewTile]
|
|
|
}
|
|
}
|
|
|
private var columns: [GridItem] {
|
|
private var columns: [GridItem] {
|
|
|
[GridItem(.adaptive(minimum: 120, maximum: 145), spacing: 22)]
|
|
[GridItem(.adaptive(minimum: 120, maximum: 145), spacing: 22)]
|
|
@@ -67,6 +72,15 @@ struct LauncherRootView: View {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private var hiddenApps: [LauncherApp] {
|
|
|
|
|
+ let hiddenIDs = decodeUUIDSet(from: hiddenLauncherAppIDsData)
|
|
|
|
|
+ guard !hiddenIDs.isEmpty else { return [] }
|
|
|
|
|
+ let allApps = LauncherApp.sampleApps + customApps
|
|
|
|
|
+ return allApps
|
|
|
|
|
+ .filter { hiddenIDs.contains($0.id) }
|
|
|
|
|
+ .sorted { $0.name.localizedCaseInsensitiveCompare($1.name) == .orderedAscending }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
var body: some View {
|
|
var body: some View {
|
|
|
ZStack {
|
|
ZStack {
|
|
|
VisualEffectBlur(material: .hudWindow, blendingMode: .behindWindow)
|
|
VisualEffectBlur(material: .hudWindow, blendingMode: .behindWindow)
|
|
@@ -79,6 +93,7 @@ struct LauncherRootView: View {
|
|
|
SearchHeader(
|
|
SearchHeader(
|
|
|
query: $query,
|
|
query: $query,
|
|
|
isPanelMode: layoutMode == .panel,
|
|
isPanelMode: layoutMode == .panel,
|
|
|
|
|
+ hiddenApps: hiddenApps,
|
|
|
onToggleLayout: {
|
|
onToggleLayout: {
|
|
|
layoutMode = layoutMode == .grid ? .panel : .grid
|
|
layoutMode = layoutMode == .grid ? .panel : .grid
|
|
|
},
|
|
},
|
|
@@ -89,6 +104,12 @@ struct LauncherRootView: View {
|
|
|
if let url = URL(string: "https://www.google.com") {
|
|
if let url = URL(string: "https://www.google.com") {
|
|
|
InAppBrowserWindowManager.shared.open(url: url, title: "Google")
|
|
InAppBrowserWindowManager.shared.open(url: url, title: "Google")
|
|
|
}
|
|
}
|
|
|
|
|
+ },
|
|
|
|
|
+ onRestoreApp: { appID in
|
|
|
|
|
+ restoreHiddenApp(id: appID)
|
|
|
|
|
+ },
|
|
|
|
|
+ onRestoreAll: {
|
|
|
|
|
+ restoreAllHiddenApps()
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
.padding(.top, 12)
|
|
.padding(.top, 12)
|
|
@@ -166,15 +187,18 @@ struct LauncherRootView: View {
|
|
|
},
|
|
},
|
|
|
draggedAppID: $draggedAppID,
|
|
draggedAppID: $draggedAppID,
|
|
|
lastDropDestinationAppID: $lastDropDestinationAppID,
|
|
lastDropDestinationAppID: $lastDropDestinationAppID,
|
|
|
- onMove: moveApp
|
|
|
|
|
|
|
+ onMove: moveApp,
|
|
|
|
|
+ onHideApp: hideApp
|
|
|
)
|
|
)
|
|
|
} else {
|
|
} else {
|
|
|
ScrollView {
|
|
ScrollView {
|
|
|
LazyVGrid(columns: columns, spacing: 20) {
|
|
LazyVGrid(columns: columns, spacing: 20) {
|
|
|
ForEach(filteredApps) { app in
|
|
ForEach(filteredApps) { app in
|
|
|
- AppTileView(app: app) {
|
|
|
|
|
- handleAppTap(app)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ AppTileView(
|
|
|
|
|
+ app: app,
|
|
|
|
|
+ onTap: { handleAppTap(app) },
|
|
|
|
|
+ onHide: { hideApp(id: app.id) }
|
|
|
|
|
+ )
|
|
|
.onDrag {
|
|
.onDrag {
|
|
|
draggedAppID = app.id
|
|
draggedAppID = app.id
|
|
|
lastDropDestinationAppID = nil
|
|
lastDropDestinationAppID = nil
|
|
@@ -286,6 +310,37 @@ struct LauncherRootView: View {
|
|
|
saveAppOrderToStorage()
|
|
saveAppOrderToStorage()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private func hideApp(id: UUID) {
|
|
|
|
|
+ var hiddenIDs = decodeUUIDSet(from: hiddenLauncherAppIDsData)
|
|
|
|
|
+ guard hiddenIDs.insert(id).inserted else { return }
|
|
|
|
|
+ hiddenLauncherAppIDsData = encodeUUIDSetGlobal(hiddenIDs)
|
|
|
|
|
+ removeIDFromLinkedCollections(id)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private func restoreHiddenApp(id: UUID) {
|
|
|
|
|
+ var hiddenIDs = decodeUUIDSet(from: hiddenLauncherAppIDsData)
|
|
|
|
|
+ guard hiddenIDs.remove(id) != nil else { return }
|
|
|
|
|
+ hiddenLauncherAppIDsData = encodeUUIDSetGlobal(hiddenIDs)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private func restoreAllHiddenApps() {
|
|
|
|
|
+ hiddenLauncherAppIDsData = ""
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private func removeIDFromLinkedCollections(_ id: UUID) {
|
|
|
|
|
+ var pinnedIDs = decodeUUIDSet(from: pinnedTileIDsData)
|
|
|
|
|
+ pinnedIDs.remove(id)
|
|
|
|
|
+ pinnedTileIDsData = encodeUUIDSetGlobal(pinnedIDs)
|
|
|
|
|
+
|
|
|
|
|
+ var statusBarIDs = decodeUUIDSet(from: statusBarAppIDsData)
|
|
|
|
|
+ statusBarIDs.remove(id)
|
|
|
|
|
+ statusBarAppIDsData = encodeUUIDSetGlobal(statusBarIDs)
|
|
|
|
|
+
|
|
|
|
|
+ var widgetIDs = decodeUUIDSet(from: widgetAppIDsData)
|
|
|
|
|
+ widgetIDs.remove(id)
|
|
|
|
|
+ widgetAppIDsData = encodeUUIDSetGlobal(widgetIDs)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private func loadAppOrderFromStorage() {
|
|
private func loadAppOrderFromStorage() {
|
|
|
guard !appOrderData.isEmpty else {
|
|
guard !appOrderData.isEmpty else {
|
|
|
appOrder = []
|
|
appOrder = []
|
|
@@ -377,9 +432,12 @@ private struct TileReorderDropDelegate: DropDelegate {
|
|
|
private struct SearchHeader: View {
|
|
private struct SearchHeader: View {
|
|
|
@Binding var query: String
|
|
@Binding var query: String
|
|
|
let isPanelMode: Bool
|
|
let isPanelMode: Bool
|
|
|
|
|
+ let hiddenApps: [LauncherApp]
|
|
|
let onToggleLayout: () -> Void
|
|
let onToggleLayout: () -> Void
|
|
|
let onOpenPremium: () -> Void
|
|
let onOpenPremium: () -> Void
|
|
|
let onOpenGoogle: () -> Void
|
|
let onOpenGoogle: () -> Void
|
|
|
|
|
+ let onRestoreApp: (UUID) -> Void
|
|
|
|
|
+ let onRestoreAll: () -> Void
|
|
|
|
|
|
|
|
var body: some View {
|
|
var body: some View {
|
|
|
HStack {
|
|
HStack {
|
|
@@ -419,6 +477,20 @@ private struct SearchHeader: View {
|
|
|
Button("Open Google") {
|
|
Button("Open Google") {
|
|
|
onOpenGoogle()
|
|
onOpenGoogle()
|
|
|
}
|
|
}
|
|
|
|
|
+ if !hiddenApps.isEmpty {
|
|
|
|
|
+ Divider()
|
|
|
|
|
+ Menu("Manage Hidden Apps") {
|
|
|
|
|
+ ForEach(hiddenApps) { app in
|
|
|
|
|
+ Button("Add Back \(app.name)") {
|
|
|
|
|
+ onRestoreApp(app.id)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ Divider()
|
|
|
|
|
+ Button("Restore All Hidden Apps") {
|
|
|
|
|
+ onRestoreAll()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
} label: {
|
|
} label: {
|
|
|
Image(systemName: "ellipsis")
|
|
Image(systemName: "ellipsis")
|
|
|
}
|
|
}
|
|
@@ -437,6 +509,7 @@ private struct IconPanelView: View {
|
|
|
@Binding var draggedAppID: UUID?
|
|
@Binding var draggedAppID: UUID?
|
|
|
@Binding var lastDropDestinationAppID: UUID?
|
|
@Binding var lastDropDestinationAppID: UUID?
|
|
|
let onMove: (UUID, UUID) -> Void
|
|
let onMove: (UUID, UUID) -> Void
|
|
|
|
|
+ let onHideApp: (UUID) -> Void
|
|
|
|
|
|
|
|
var body: some View {
|
|
var body: some View {
|
|
|
ScrollView {
|
|
ScrollView {
|
|
@@ -447,7 +520,8 @@ private struct IconPanelView: View {
|
|
|
onAppTap: onAppTap,
|
|
onAppTap: onAppTap,
|
|
|
draggedAppID: $draggedAppID,
|
|
draggedAppID: $draggedAppID,
|
|
|
lastDropDestinationAppID: $lastDropDestinationAppID,
|
|
lastDropDestinationAppID: $lastDropDestinationAppID,
|
|
|
- onMove: onMove
|
|
|
|
|
|
|
+ onMove: onMove,
|
|
|
|
|
+ onHideApp: onHideApp
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -463,6 +537,7 @@ private struct PanelAppRowView: View {
|
|
|
@Binding var draggedAppID: UUID?
|
|
@Binding var draggedAppID: UUID?
|
|
|
@Binding var lastDropDestinationAppID: UUID?
|
|
@Binding var lastDropDestinationAppID: UUID?
|
|
|
let onMove: (UUID, UUID) -> Void
|
|
let onMove: (UUID, UUID) -> Void
|
|
|
|
|
+ let onHideApp: (UUID) -> Void
|
|
|
|
|
|
|
|
@AppStorage("pinnedTileIDsData") private var pinnedTileIDsData = ""
|
|
@AppStorage("pinnedTileIDsData") private var pinnedTileIDsData = ""
|
|
|
@AppStorage("statusBarAppIDsData") private var statusBarAppIDsData = ""
|
|
@AppStorage("statusBarAppIDsData") private var statusBarAppIDsData = ""
|
|
@@ -521,6 +596,8 @@ private struct PanelAppRowView: View {
|
|
|
Button("Add to StatusBar") { addToStatusBar() }
|
|
Button("Add to StatusBar") { addToStatusBar() }
|
|
|
Button("Add to desktop") { addToDesktop() }
|
|
Button("Add to desktop") { addToDesktop() }
|
|
|
Button("Add Widget") { addWidget() }
|
|
Button("Add Widget") { addWidget() }
|
|
|
|
|
+ Divider()
|
|
|
|
|
+ Button("Remove from View") { onHideApp(app.id) }
|
|
|
} label: {
|
|
} label: {
|
|
|
Image(systemName: "ellipsis")
|
|
Image(systemName: "ellipsis")
|
|
|
.font(.system(size: 13, weight: .semibold))
|
|
.font(.system(size: 13, weight: .semibold))
|