فهرست منبع

Simplify Drive variants and redesign compact quick actions.

Remove the medium Drive widget variant, replace static sample rows with action-based shortcuts in the small widget, and tune compact Drive sizing and spacing for a cleaner panel layout.

Made-with: Cursor
huzaifahayat12 3 ماه پیش
والد
کامیت
9259a17553
2فایلهای تغییر یافته به همراه45 افزوده شده و 185 حذف شده
  1. 41 176
      google_apps/Widgets/DriveDesktopWidgetView.swift
  2. 4 9
      google_apps/Widgets/WidgetTemplates.swift

+ 41 - 176
google_apps/Widgets/DriveDesktopWidgetView.swift

@@ -14,8 +14,6 @@ struct DriveDesktopWidgetView: View {
             switch mode {
             switch mode {
             case .recentQuick:
             case .recentQuick:
                 recentQuickBody
                 recentQuickBody
-            case .filesPreview:
-                filesPreviewBody
             case .interactive:
             case .interactive:
                 interactiveBody
                 interactiveBody
             }
             }
@@ -25,54 +23,49 @@ struct DriveDesktopWidgetView: View {
 
 
     // MARK: - Small
     // MARK: - Small
 
 
-    private struct RecentEntry: Identifiable {
+    private struct DriveQuickAction: Identifiable {
         let id: String
         let id: String
-        let name: String
+        let title: String
         let systemImage: String
         let systemImage: String
-        let time: String
+        let path: String
     }
     }
 
 
-    private static let recentSamples: [RecentEntry] = [
-        RecentEntry(id: "1", name: "Q4 Budget.xlsx", systemImage: "tablecells", time: "2h ago"),
-        RecentEntry(id: "2", name: "Project Notes", systemImage: "doc.text", time: "Yesterday"),
-        RecentEntry(id: "3", name: "Design mockup.png", systemImage: "photo", time: "Mon"),
+    private static let smallQuickActions: [DriveQuickAction] = [
+        DriveQuickAction(id: "recent", title: "Recent", systemImage: "clock.fill", path: "/drive/recent"),
+        DriveQuickAction(id: "starred", title: "Starred", systemImage: "star.fill", path: "/drive/starred"),
+        DriveQuickAction(id: "shared", title: "Shared", systemImage: "person.2.fill", path: "/drive/shared-with-me"),
+        DriveQuickAction(id: "upload", title: "Upload", systemImage: "arrow.up.doc.fill", path: "/drive/home"),
+        DriveQuickAction(id: "folders", title: "Folders", systemImage: "folder.fill", path: "/drive/folders"),
+        DriveQuickAction(id: "trash", title: "Trash", systemImage: "trash.fill", path: "/drive/trash"),
     ]
     ]
 
 
     private var recentQuickBody: some View {
     private var recentQuickBody: some View {
         ZStack(alignment: .topLeading) {
         ZStack(alignment: .topLeading) {
             driveGradientBackground
             driveGradientBackground
                 .frame(maxWidth: .infinity, maxHeight: .infinity)
                 .frame(maxWidth: .infinity, maxHeight: .infinity)
-            VStack(alignment: .leading, spacing: 10) {
-                HStack(spacing: 10) {
+            VStack(alignment: .leading, spacing: 9) {
+                HStack(spacing: 8) {
                     AppIconView(app: app, size: 32, showAppBackground: false, iconPaddingFactor: 0.08)
                     AppIconView(app: app, size: 32, showAppBackground: false, iconPaddingFactor: 0.08)
                     VStack(alignment: .leading, spacing: 2) {
                     VStack(alignment: .leading, spacing: 2) {
                         Text(app.name)
                         Text(app.name)
                             .font(.system(size: 14, weight: .bold))
                             .font(.system(size: 14, weight: .bold))
                             .foregroundStyle(.white.opacity(0.95))
                             .foregroundStyle(.white.opacity(0.95))
-                        Text("Recent files")
+                        Text("Quick actions")
                             .font(.system(size: 10, weight: .semibold))
                             .font(.system(size: 10, weight: .semibold))
                             .foregroundStyle(.white.opacity(0.65))
                             .foregroundStyle(.white.opacity(0.65))
                     }
                     }
                     Spacer(minLength: 0)
                     Spacer(minLength: 0)
                 }
                 }
 
 
-                Text("Sample")
-                    .font(.system(size: 9, weight: .bold))
-                    .foregroundStyle(.white.opacity(0.45))
-
-                VStack(spacing: 6) {
-                    ForEach(Self.recentSamples) { item in
-                        recentRow(name: item.name, systemImage: item.systemImage, time: item.time) {
-                            openDriveSearch(query: item.name)
-                        }
-                    }
-                }
+                smallActionsGrid
+                    .padding(.top, 3)
 
 
                 drivePrimaryButton(title: "Open Drive", systemImage: "externaldrive.fill") {
                 drivePrimaryButton(title: "Open Drive", systemImage: "externaldrive.fill") {
                     openDrivePath("/drive/home")
                     openDrivePath("/drive/home")
                 }
                 }
+                .padding(.top, 3)
             }
             }
-            .padding(14)
+            .padding(12)
             .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
             .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
         }
         }
         .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
         .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
@@ -80,166 +73,38 @@ struct DriveDesktopWidgetView: View {
         .opacity(isPreview ? 0.85 : 1)
         .opacity(isPreview ? 0.85 : 1)
     }
     }
 
 
-    private func recentRow(name: String, systemImage: String, time: String, action: @escaping () -> Void) -> some View {
-        Button(action: {
-            NSApp.activate(ignoringOtherApps: true)
-            action()
-        }) {
-            HStack(spacing: 10) {
-                Image(systemName: systemImage)
-                    .font(.system(size: 14, weight: .semibold))
-                    .foregroundStyle(Color(red: 0.75, green: 0.92, blue: 0.82))
-                    .frame(width: 28, height: 28)
-                    .background(RoundedRectangle(cornerRadius: 8).fill(Color.white.opacity(0.12)))
-                VStack(alignment: .leading, spacing: 2) {
-                    Text(name)
-                        .font(.system(size: 12, weight: .semibold))
-                        .foregroundStyle(.white.opacity(0.95))
-                        .lineLimit(1)
-                    Text(time)
-                        .font(.system(size: 10, weight: .medium))
-                        .foregroundStyle(.white.opacity(0.5))
-                }
-                Spacer(minLength: 0)
-                Image(systemName: "chevron.right")
-                    .font(.system(size: 10, weight: .bold))
-                    .foregroundStyle(.white.opacity(0.35))
-            }
-            .padding(10)
-            .background(RoundedRectangle(cornerRadius: 12, style: .continuous).fill(Color.black.opacity(0.22)))
-        }
-        .buttonStyle(.plain)
-        .disabled(isPreview)
-        .allowsHitTesting(!isPreview)
-    }
-
-    // MARK: - Medium
-
-    private struct StarredEntry: Identifiable {
-        let id: String
-        let name: String
-        let systemImage: String
-    }
-
-    private static let starredSamples: [StarredEntry] = [
-        StarredEntry(id: "s1", name: "Roadmap 2026", systemImage: "rectangle.on.rectangle"),
-        StarredEntry(id: "s2", name: "Team roster", systemImage: "doc.richtext"),
-    ]
-
-    private var filesPreviewBody: some View {
-        ZStack(alignment: .topLeading) {
-            driveGradientBackground
-                .frame(maxWidth: .infinity, maxHeight: .infinity)
-            ScrollView {
-                VStack(alignment: .leading, spacing: 12) {
-                    HStack(spacing: 8) {
-                        AppIconView(app: app, size: 30, showAppBackground: false, iconPaddingFactor: 0.08)
-                        Text("Drive")
-                            .font(.system(size: 14, weight: .bold))
-                            .foregroundStyle(.white.opacity(0.95))
-                        Spacer(minLength: 0)
-                        Text("Sample")
-                            .font(.system(size: 10, weight: .bold))
-                            .foregroundStyle(.white.opacity(0.5))
-                            .padding(.horizontal, 8)
-                            .padding(.vertical, 4)
-                            .background(Capsule().fill(Color.white.opacity(0.12)))
-                    }
-
-                    drivePrimaryButton(title: "Open Drive", systemImage: "externaldrive.fill") {
-                        openDrivePath("/drive/home")
-                    }
-
-                    sectionTitle("Recent")
-                    VStack(spacing: 8) {
-                        ForEach(Self.recentSamples) { item in
-                            fileActionRow(
-                                name: item.name,
-                                systemImage: item.systemImage,
-                                subtitle: item.time,
-                                onOpen: { openDrivePath("/drive/recent") },
-                                onShare: { openDriveSearch(query: item.name) }
-                            )
-                        }
-                    }
-
-                    sectionTitle("Starred")
-                    VStack(spacing: 8) {
-                        ForEach(Self.starredSamples) { item in
-                            fileActionRow(
-                                name: item.name,
-                                systemImage: item.systemImage,
-                                subtitle: "Starred",
-                                onOpen: { openDrivePath("/drive/starred") },
-                                onShare: { openDriveSearch(query: item.name) }
-                            )
-                        }
-                    }
-                }
-                .frame(maxWidth: .infinity, alignment: .leading)
-                .padding(.bottom, 6)
-            }
-            .padding(14)
-            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
-        }
-        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
-        .disabled(isPreview)
-        .opacity(isPreview ? 0.85 : 1)
-    }
-
-    private func sectionTitle(_ text: String) -> some View {
-        Text(text)
-            .font(.system(size: 11, weight: .bold))
-            .foregroundStyle(.white.opacity(0.62))
-    }
-
-    private func fileActionRow(
-        name: String,
-        systemImage: String,
-        subtitle: String,
-        onOpen: @escaping () -> Void,
-        onShare: @escaping () -> Void
-    ) -> some View {
-        VStack(alignment: .leading, spacing: 8) {
-            HStack(spacing: 10) {
-                Image(systemName: systemImage)
-                    .font(.system(size: 13, weight: .semibold))
-                    .foregroundStyle(Color(red: 0.75, green: 0.92, blue: 0.82))
-                VStack(alignment: .leading, spacing: 2) {
-                    Text(name)
-                        .font(.system(size: 12, weight: .bold))
-                        .foregroundStyle(.white.opacity(0.95))
-                        .lineLimit(1)
-                    Text(subtitle)
-                        .font(.system(size: 10, weight: .medium))
-                        .foregroundStyle(.white.opacity(0.5))
-                }
-                Spacer(minLength: 0)
-            }
-            HStack(spacing: 8) {
-                smallAction(title: "Open", systemImage: "arrow.up.right.square", action: onOpen)
-                smallAction(title: "Share", systemImage: "square.and.arrow.up", action: onShare)
+    private var smallActionsGrid: some View {
+        let cols = [GridItem(.flexible(minimum: 0), spacing: 8), GridItem(.flexible(minimum: 0), spacing: 8)]
+        return LazyVGrid(columns: cols, spacing: 8) {
+            ForEach(Self.smallQuickActions) { action in
+                smallQuickActionButton(action)
             }
             }
         }
         }
-        .padding(10)
-        .background(RoundedRectangle(cornerRadius: 12, style: .continuous).fill(Color.black.opacity(0.24)))
     }
     }
 
 
-    private func smallAction(title: String, systemImage: String, action: @escaping () -> Void) -> some View {
+    private func smallQuickActionButton(_ actionItem: DriveQuickAction) -> some View {
         Button(action: {
         Button(action: {
             NSApp.activate(ignoringOtherApps: true)
             NSApp.activate(ignoringOtherApps: true)
-            action()
+            openDrivePath(actionItem.path)
         }) {
         }) {
-            HStack(spacing: 4) {
-                Image(systemName: systemImage)
-                    .font(.system(size: 10, weight: .semibold))
-                Text(title)
-                    .font(.system(size: 10, weight: .bold))
+            HStack(spacing: 6) {
+                Image(systemName: actionItem.systemImage)
+                    .font(.system(size: 11, weight: .semibold))
+                Text(actionItem.title)
+                    .font(.system(size: 11, weight: .bold))
+                    .lineLimit(1)
             }
             }
-            .foregroundStyle(.white.opacity(0.9))
-            .padding(.horizontal, 10)
-            .padding(.vertical, 6)
-            .background(Capsule().fill(Color.white.opacity(0.14)))
+            .foregroundStyle(.white.opacity(0.94))
+            .frame(maxWidth: .infinity)
+            .padding(.vertical, 8)
+            .background(
+                RoundedRectangle(cornerRadius: 10, style: .continuous)
+                    .fill(Color.black.opacity(0.24))
+            )
+            .overlay(
+                RoundedRectangle(cornerRadius: 10, style: .continuous)
+                    .stroke(Color.white.opacity(0.12), lineWidth: 1)
+            )
         }
         }
         .buttonStyle(.plain)
         .buttonStyle(.plain)
         .disabled(isPreview)
         .disabled(isPreview)

+ 4 - 9
google_apps/Widgets/WidgetTemplates.swift

@@ -24,10 +24,8 @@ enum GmailWidgetMode: Hashable, Sendable {
 }
 }
 
 
 enum DriveWidgetMode: Hashable, Sendable {
 enum DriveWidgetMode: Hashable, Sendable {
-    /// Sample recent files and shortcuts to Drive recent.
+    /// Action-first compact Drive launcher.
     case recentQuick
     case recentQuick
-    /// Recent + starred sample rows with open / share.
-    case filesPreview
     /// Shortcut hub: search, folders, quick find, create, and tools — open in app browser (no embedded Drive UI).
     /// Shortcut hub: search, folders, quick find, create, and tools — open in app browser (no embedded Drive UI).
     case interactive
     case interactive
 }
 }
@@ -212,8 +210,7 @@ enum WidgetTemplates {
             ]
             ]
         case .drive:
         case .drive:
             return [
             return [
-                v("drive_small", "Recent files", .small, false, .drive(.recentQuick), []),
-                v("drive_medium", "Files & sharing", .medium, false, .drive(.filesPreview), []),
+                v("drive_small", "Quick actions", .small, false, .drive(.recentQuick), []),
                 v("drive_large", "Full Drive", .large, false, .drive(.interactive), []),
                 v("drive_large", "Full Drive", .large, false, .drive(.interactive), []),
             ]
             ]
         case .docs:
         case .docs:
@@ -597,8 +594,7 @@ extension WidgetLayoutMode {
             }
             }
         case .drive(let mode):
         case .drive(let mode):
             switch mode {
             switch mode {
-            case .recentQuick: return CGSize(width: 230, height: 260)
-            case .filesPreview: return CGSize(width: 420, height: 480)
+            case .recentQuick: return CGSize(width: 230, height: 238)
             case .interactive: return CGSize(width: 540, height: 580)
             case .interactive: return CGSize(width: 540, height: 580)
             }
             }
         case .keep(let mode):
         case .keep(let mode):
@@ -670,8 +666,7 @@ extension WidgetLayoutMode {
             }
             }
         case .drive(let mode):
         case .drive(let mode):
             switch mode {
             switch mode {
-            case .recentQuick: return CGSize(width: 210, height: 230)
-            case .filesPreview: return CGSize(width: 380, height: 420)
+            case .recentQuick: return CGSize(width: 210, height: 212)
             case .interactive: return CGSize(width: 480, height: 440)
             case .interactive: return CGSize(width: 480, height: 440)
             }
             }
         case .keep(let mode):
         case .keep(let mode):