|
@@ -28,6 +28,7 @@ struct LauncherRootView: View {
|
|
|
@AppStorage("statusBarAppIDsData") private var statusBarAppIDsData = ""
|
|
@AppStorage("statusBarAppIDsData") private var statusBarAppIDsData = ""
|
|
|
@AppStorage("widgetAppIDsData") private var widgetAppIDsData = ""
|
|
@AppStorage("widgetAppIDsData") private var widgetAppIDsData = ""
|
|
|
@AppStorage("hiddenLauncherAppIDsData") private var hiddenLauncherAppIDsData = ""
|
|
@AppStorage("hiddenLauncherAppIDsData") private var hiddenLauncherAppIDsData = ""
|
|
|
|
|
+ @AppStorage("hasOpenedWidgetsHubFromLauncher") private var hasOpenedWidgetsHubFromLauncher = false
|
|
|
|
|
|
|
|
private var apps: [LauncherApp] {
|
|
private var apps: [LauncherApp] {
|
|
|
let hiddenIDs = decodeUUIDSet(from: hiddenLauncherAppIDsData)
|
|
let hiddenIDs = decodeUUIDSet(from: hiddenLauncherAppIDsData)
|
|
@@ -119,6 +120,10 @@ struct LauncherRootView: View {
|
|
|
InAppBrowserWindowManager.shared.open(url: url, title: "Google")
|
|
InAppBrowserWindowManager.shared.open(url: url, title: "Google")
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
+ onOpenWidgets: {
|
|
|
|
|
+ openWidgetsHub()
|
|
|
|
|
+ },
|
|
|
|
|
+ shouldHighlightWidgets: !hasOpenedWidgetsHubFromLauncher,
|
|
|
onRestoreApp: { appID in
|
|
onRestoreApp: { appID in
|
|
|
restoreHiddenApp(id: appID)
|
|
restoreHiddenApp(id: appID)
|
|
|
},
|
|
},
|
|
@@ -310,6 +315,7 @@ struct LauncherRootView: View {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func openWidgetsPage(for app: LauncherApp) {
|
|
private func openWidgetsPage(for app: LauncherApp) {
|
|
|
|
|
+ hasOpenedWidgetsHubFromLauncher = true
|
|
|
var updated = decodeUUIDSetGlobal(from: widgetAppIDsData)
|
|
var updated = decodeUUIDSetGlobal(from: widgetAppIDsData)
|
|
|
updated.insert(app.id)
|
|
updated.insert(app.id)
|
|
|
widgetAppIDsData = encodeUUIDSetGlobal(updated)
|
|
widgetAppIDsData = encodeUUIDSetGlobal(updated)
|
|
@@ -320,6 +326,15 @@ struct LauncherRootView: View {
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private func openWidgetsHub() {
|
|
|
|
|
+ hasOpenedWidgetsHubFromLauncher = true
|
|
|
|
|
+ let firstAppID = orderedApps.first(where: { !$0.isCreateNew })?.id
|
|
|
|
|
+ WidgetsWindowManager.shared.open(
|
|
|
|
|
+ apps: orderedApps.filter { !$0.isCreateNew },
|
|
|
|
|
+ selectedAppID: firstAppID
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private func addCustomApp(name: String, url: URL) {
|
|
private func addCustomApp(name: String, url: URL) {
|
|
|
let newApp = LauncherApp(
|
|
let newApp = LauncherApp(
|
|
|
name: name,
|
|
name: name,
|
|
@@ -524,8 +539,11 @@ private struct SearchHeader: View {
|
|
|
let onToggleLayout: () -> Void
|
|
let onToggleLayout: () -> Void
|
|
|
let onOpenPremium: () -> Void
|
|
let onOpenPremium: () -> Void
|
|
|
let onOpenGoogle: () -> Void
|
|
let onOpenGoogle: () -> Void
|
|
|
|
|
+ let onOpenWidgets: () -> Void
|
|
|
|
|
+ let shouldHighlightWidgets: Bool
|
|
|
let onRestoreApp: (UUID) -> Void
|
|
let onRestoreApp: (UUID) -> Void
|
|
|
let onRestoreAll: () -> Void
|
|
let onRestoreAll: () -> Void
|
|
|
|
|
+ @State private var pulse = false
|
|
|
|
|
|
|
|
var body: some View {
|
|
var body: some View {
|
|
|
HStack {
|
|
HStack {
|
|
@@ -550,6 +568,52 @@ private struct SearchHeader: View {
|
|
|
Spacer(minLength: 8)
|
|
Spacer(minLength: 8)
|
|
|
|
|
|
|
|
HStack(spacing: 12) {
|
|
HStack(spacing: 12) {
|
|
|
|
|
+ Button(action: onOpenWidgets) {
|
|
|
|
|
+ HStack(spacing: 6) {
|
|
|
|
|
+ Image(systemName: "square.grid.2x2.fill")
|
|
|
|
|
+ Text("Widgets")
|
|
|
|
|
+ .font(.system(size: 12, weight: .bold))
|
|
|
|
|
+ if shouldHighlightWidgets {
|
|
|
|
|
+ Text("NEW")
|
|
|
|
|
+ .font(.system(size: 9, weight: .black))
|
|
|
|
|
+ .padding(.horizontal, 5)
|
|
|
|
|
+ .padding(.vertical, 2)
|
|
|
|
|
+ .background(
|
|
|
|
|
+ Capsule(style: .continuous)
|
|
|
|
|
+ .fill(Color.white.opacity(0.92))
|
|
|
|
|
+ )
|
|
|
|
|
+ .foregroundStyle(Color.blue.opacity(0.95))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .foregroundStyle(.white.opacity(0.95))
|
|
|
|
|
+ .padding(.horizontal, 10)
|
|
|
|
|
+ .padding(.vertical, 6)
|
|
|
|
|
+ .background(
|
|
|
|
|
+ Capsule(style: .continuous)
|
|
|
|
|
+ .fill(shouldHighlightWidgets ? Color.blue.opacity(0.82) : Color.white.opacity(0.12))
|
|
|
|
|
+ )
|
|
|
|
|
+ .overlay(
|
|
|
|
|
+ Capsule(style: .continuous)
|
|
|
|
|
+ .stroke(
|
|
|
|
|
+ shouldHighlightWidgets
|
|
|
|
|
+ ? Color.white.opacity(0.95)
|
|
|
|
|
+ : Color.white.opacity(0.15),
|
|
|
|
|
+ lineWidth: shouldHighlightWidgets ? 1.4 : 1
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+ .shadow(
|
|
|
|
|
+ color: shouldHighlightWidgets
|
|
|
|
|
+ ? Color.blue.opacity(0.55)
|
|
|
|
|
+ : Color.clear,
|
|
|
|
|
+ radius: pulse ? 18 : 9,
|
|
|
|
|
+ x: 0,
|
|
|
|
|
+ y: 5
|
|
|
|
|
+ )
|
|
|
|
|
+ .scaleEffect(shouldHighlightWidgets && pulse ? 1.03 : 1.0)
|
|
|
|
|
+ .animation(.easeInOut(duration: 1.2).repeatForever(autoreverses: true), value: pulse)
|
|
|
|
|
+ }
|
|
|
|
|
+ .buttonStyle(.plain)
|
|
|
|
|
+
|
|
|
Button(action: onToggleLayout) {
|
|
Button(action: onToggleLayout) {
|
|
|
Image(systemName: isPanelMode ? "square.grid.2x2" : "list.bullet")
|
|
Image(systemName: isPanelMode ? "square.grid.2x2" : "list.bullet")
|
|
|
}
|
|
}
|
|
@@ -588,6 +652,12 @@ private struct SearchHeader: View {
|
|
|
.foregroundStyle(.white.opacity(0.82))
|
|
.foregroundStyle(.white.opacity(0.82))
|
|
|
.padding(.trailing, 4)
|
|
.padding(.trailing, 4)
|
|
|
}
|
|
}
|
|
|
|
|
+ .onAppear {
|
|
|
|
|
+ pulse = shouldHighlightWidgets
|
|
|
|
|
+ }
|
|
|
|
|
+ .onChange(of: shouldHighlightWidgets) { shouldHighlight in
|
|
|
|
|
+ pulse = shouldHighlight
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|