1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-06 19:40:08 +02:00

♻️ Various extension list improvements (#274)

Installing and removing extensions now scrolls to the extension afterwards, and animates this. This is done to emphasise that the operation succeeded.
This commit is contained in:
2024-08-31 15:57:08 +02:00
parent 3c0a4a6142
commit e026ecf60d
5 changed files with 53 additions and 20 deletions

View File

@ -45,7 +45,6 @@ func grepContains(file: String, query: String) async -> Bool {
/**
Attempts to introduce sleep for a particular duration. Use with caution.
Only intended for testing purposes.
*/
func delay(seconds: Double) async {
try! await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))

View File

@ -951,9 +951,9 @@ Gw
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="3Wp-DX-An9">
<rect key="frame" x="5" y="4.5" width="19" height="45"/>
<rect key="frame" x="5" y="4" width="20" height="47"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="Q76-fI-lkW">
<imageReference key="image" image="star.square.fill" catalog="system" symbolScale="large"/>
<imageReference key="image" image="star.circle.fill" catalog="system" symbolScale="large"/>
</imageCell>
<color key="contentTintColor" name="AccentColor"/>
</imageView>
@ -1547,7 +1547,7 @@ Gw
<image name="Lock" width="30" height="30"/>
<image name="arrow.clockwise" catalog="system" width="14" height="16"/>
<image name="plus" catalog="system" width="14" height="13"/>
<image name="star.square.fill" catalog="system" width="19" height="18"/>
<image name="star.circle.fill" catalog="system" width="20" height="20"/>
<namedColor name="AccentColor">
<color red="0.0" green="0.46000000000000002" blue="0.89000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>

View File

@ -27,13 +27,14 @@ extension PhpExtensionManagerView {
)
}
public func install(_ ext: BrewPhpExtension) {
public func install(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
Task {
await self.runCommand(InstallPhpExtensionCommand(install: [ext]))
onCompletion()
}
}
public func confirmUninstall(_ ext: BrewPhpExtension) {
public func confirmUninstall(_ ext: BrewPhpExtension, onCompletion: @escaping () -> Void = {}) {
Alert.confirm(
onWindow: App.shared.phpExtensionManagerWindowController!.window!,
messageText: "phpextman.warnings.removal.title".localized(ext.name),
@ -45,6 +46,7 @@ extension PhpExtensionManagerView {
onFirstButtonPressed: {
Task {
await self.runCommand(RemovePhpExtensionCommand(remove: ext))
onCompletion()
}
}
)

View File

@ -13,6 +13,7 @@ struct PhpExtensionManagerView: View {
@ObservedObject var manager: BrewExtensionsObservable
@ObservedObject var status: BusyStatus
@State var searchText: String
@State private var highlightedExtension: String?
init() {
self.searchText = ""
@ -24,9 +25,12 @@ struct PhpExtensionManagerView: View {
var filteredExtensions: [BrewPhpExtension] {
guard !searchText.isEmpty else {
return manager.extensions
return manager.extensions.sorted { $0.isInstalled && !$1.isInstalled }
}
return manager.extensions.filter { $0.name.contains(searchText) }
return manager.extensions
.filter { $0.name.contains(searchText) }
.sorted { $0.isInstalled && !$1.isInstalled }
}
var body: some View {
@ -48,14 +52,19 @@ struct PhpExtensionManagerView: View {
title: self.status.title,
text: self.status.description
) {
List(Array(self.filteredExtensions.enumerated()), id: \.1.name) { (_, ext) in
listContent(for: ext)
.padding(.vertical, 8)
.padding(.horizontal, 8)
ScrollViewReader { proxy in
List(Array(self.filteredExtensions.enumerated()), id: \.1.name) { (_, ext) in
listContent(for: ext, proxy: proxy)
}
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
.searchable(text: $searchText)
.onChange(of: manager.phpVersion, perform: { _ in
if let ext = self.filteredExtensions.first {
proxy.scrollTo(ext.name)
}
})
}
.edgesIgnoringSafeArea(.top)
.listStyle(PlainListStyle())
.searchable(text: $searchText)
}
}
.frame(minWidth: 600, minHeight: 600)
@ -147,7 +156,20 @@ struct PhpExtensionManagerView: View {
}
}
private func listContent(for ext: BrewPhpExtension) -> some View {
private func scrollAndAnimate(_ ext: BrewPhpExtension, _ proxy: ScrollViewProxy) {
withAnimation {
highlightedExtension = ext.name
proxy.scrollTo(ext.name, anchor: .top)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
withAnimation {
highlightedExtension = nil
}
}
}
private func listContent(for ext: BrewPhpExtension, proxy: ScrollViewProxy) -> some View {
HStack(alignment: .center, spacing: 7.0) {
VStack(alignment: .center, spacing: 0) {
HStack {
@ -184,15 +206,25 @@ struct PhpExtensionManagerView: View {
HStack {
if ext.isInstalled {
Button("phpman.buttons.uninstall".localizedForSwiftUI, role: .destructive) {
self.confirmUninstall(ext)
}.disabled(ext.firstDependent(in: self.manager.extensions) != nil)
self.confirmUninstall(ext, onCompletion: {
scrollAndAnimate(ext, proxy)
})
}
.disabled(ext.firstDependent(in: self.manager.extensions) != nil)
} else {
Button("phpman.buttons.install".localizedForSwiftUI) {
self.install(ext)
self.install(ext, onCompletion: {
scrollAndAnimate(ext, proxy)
})
}.disabled(ext.hasAlternativeInstall)
}
}
}
.padding(.vertical, 8)
.padding(.horizontal, 8)
.background(highlightedExtension == ext.name ? Color.accentColor.opacity(0.3) : Color.clear)
.cornerRadius(8)
.animation(.easeInOut(duration: 0.5), value: highlightedExtension)
}
}

View File

@ -120,7 +120,7 @@
"phpextman.list.status.external" = "This extension is already installed via another source, and cannot be managed.";
"phpextman.list.status.installable" = "This extension can be installed.";
"phpextman.list.status.dependent" = "You cannot uninstall this before uninstalling %@.";
"phpextman.list.status.can_manage" = "This extension is installed and can be managed by PHP Monitor.";
"phpextman.list.status.can_manage" = "This extension is installed and managed by PHP Monitor.";
"phpextman.errors.not_found.title" = "Uh oh. No extensions discovered!";
"phpextman.errors.not_found.desc" = "This is not supposed to happen. You may need to run the following command in your terminal: