Преглед на файлове

home: indicate busy status in card view

Show a spinner when VM is loading and hide start button when VM is started.
This will give a better visual cue of which VM is started. Additionally,
add a double-click handler to easily open/start a VM.

Resolves #3885
osy преди 3 години
родител
ревизия
db40dc50af
променени са 3 файла, в които са добавени 88 реда и са изтрити 7 реда
  1. 16 7
      Platform/Shared/VMCardView.swift
  2. 68 0
      Platform/macOS/DoubleClickHandler.swift
  3. 4 0
      UTM.xcodeproj/project.pbxproj

+ 16 - 7
Platform/Shared/VMCardView.swift

@@ -48,16 +48,25 @@ struct VMCardView: View {
             }.lineLimit(1)
             .truncationMode(.tail)
             Spacer()
-            Button {
-                data.run(vm: vm)
-            } label: {
-                Label("Run", systemImage: "play.circle")
-                    .font(.largeTitle)
-                    .foregroundColor(buttonColor)
-                    .labelStyle(.iconOnly)
+            if vm.state == .vmStopped {
+                Button {
+                    data.run(vm: vm)
+                } label: {
+                    Label("Run", systemImage: "play.circle")
+                        .font(.largeTitle)
+                        .foregroundColor(buttonColor)
+                        .labelStyle(.iconOnly)
+                }
+            } else if vm.isBusy {
+                BigWhiteSpinner()
             }
         }.padding([.top, .bottom], 10)
         .buttonStyle(.plain)
+        #if os(macOS)
+        .onDoubleClick {
+            data.run(vm: vm)
+        }
+        #endif
     }
 }
 

+ 68 - 0
Platform/macOS/DoubleClickHandler.swift

@@ -0,0 +1,68 @@
+//
+// Copyright © 2022 osy. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+import SwiftUI
+
+// from https://gist.github.com/joelekstrom/91dad79ebdba409556dce663d28e8297
+extension View {
+    /// Adds a double click handler this view (macOS only)
+    ///
+    /// Example
+    /// ```
+    /// Text("Hello")
+    ///     .onDoubleClick { print("Double click detected") }
+    /// ```
+    /// - Parameters:
+    ///   - handler: Block invoked when a double click is detected
+    func onDoubleClick(handler: @escaping () -> Void) -> some View {
+        modifier(DoubleClickHandler(handler: handler))
+    }
+}
+
+struct DoubleClickHandler: ViewModifier {
+    let handler: () -> Void
+    func body(content: Content) -> some View {
+        content.overlay(DoubleClickListeningViewRepresentable(handler: handler))
+    }
+}
+
+struct DoubleClickListeningViewRepresentable: NSViewRepresentable {
+    let handler: () -> Void
+    func makeNSView(context: Context) -> DoubleClickListeningView {
+        DoubleClickListeningView(handler: handler)
+    }
+    func updateNSView(_ nsView: DoubleClickListeningView, context: Context) {}
+}
+
+class DoubleClickListeningView: NSView {
+    let handler: () -> Void
+
+    init(handler: @escaping () -> Void) {
+        self.handler = handler
+        super.init(frame: .zero)
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    override func mouseDown(with event: NSEvent) {
+        super.mouseDown(with: event)
+        if event.clickCount == 2 {
+            handler()
+        }
+    }
+}

+ 4 - 0
UTM.xcodeproj/project.pbxproj

@@ -1119,6 +1119,7 @@
 		CEA905C92603DA0D00801E7C /* VMDisplayMetalViewController+USB.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA905C82603DA0D00801E7C /* VMDisplayMetalViewController+USB.m */; };
 		CEA905CD2603DBFB00801E7C /* VMUSBDevicesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEA905CC2603DBFB00801E7C /* VMUSBDevicesView.xib */; };
 		CEA905D82603DC5300801E7C /* VMUSBDevicesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA905D72603DC5300801E7C /* VMUSBDevicesViewController.swift */; };
+		CEB20EEA282053320033EFB5 /* DoubleClickHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB20EE9282053320033EFB5 /* DoubleClickHandler.swift */; };
 		CEB63A7624F4654400CAF323 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB63A7524F4654400CAF323 /* Main.swift */; };
 		CEB63A7724F4654400CAF323 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB63A7524F4654400CAF323 /* Main.swift */; };
 		CEB63A7A24F469E300CAF323 /* UTMJailbreak.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB63A7924F469E300CAF323 /* UTMJailbreak.m */; };
@@ -2100,6 +2101,7 @@
 		CEA905C82603DA0D00801E7C /* VMDisplayMetalViewController+USB.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "VMDisplayMetalViewController+USB.m"; sourceTree = "<group>"; };
 		CEA905CC2603DBFB00801E7C /* VMUSBDevicesView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = VMUSBDevicesView.xib; sourceTree = "<group>"; };
 		CEA905D72603DC5300801E7C /* VMUSBDevicesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMUSBDevicesViewController.swift; sourceTree = "<group>"; };
+		CEB20EE9282053320033EFB5 /* DoubleClickHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoubleClickHandler.swift; sourceTree = "<group>"; };
 		CEB63A7524F4654400CAF323 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = "<group>"; };
 		CEB63A7824F468BA00CAF323 /* UTMJailbreak.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UTMJailbreak.h; sourceTree = "<group>"; };
 		CEB63A7924F469E300CAF323 /* UTMJailbreak.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UTMJailbreak.m; sourceTree = "<group>"; };
@@ -2583,6 +2585,7 @@
 			children = (
 				CE1BD9FA24F4825C0022A468 /* Display */,
 				CEECE13B25E47D9500A2AAB8 /* AppDelegate.swift */,
+				CEB20EE9282053320033EFB5 /* DoubleClickHandler.swift */,
 				CEEC811A24E48EC600ACB0B3 /* SettingsView.swift */,
 				CEBBF1A624B5730F00C15049 /* UTMDataExtension.swift */,
 				CE93759524BB7E9F0074066F /* UTMTabViewController.swift */,
@@ -4086,6 +4089,7 @@
 				CE0B6CF624AD568400FE012D /* UTMQemuConfiguration+Drives.m in Sources */,
 				CE0B6D4324AD584C00FE012D /* qapi-types.c in Sources */,
 				CE0B6D0824AD56C300FE012D /* qapi-visit-core.c in Sources */,
+				CEB20EEA282053320033EFB5 /* DoubleClickHandler.swift in Sources */,
 				CE0B6D2024AD57FC00FE012D /* qapi-commands-dump.c in Sources */,
 				CE0B6D5224AD584C00FE012D /* qapi-visit-sockets.c in Sources */,
 				CE0B6D7F24AD584D00FE012D /* qapi-events-qom.c in Sources */,