Skip to content

Commit

Permalink
Refactor "Devices" tab from List to Table from SwiftUI (#84)
Browse files Browse the repository at this point in the history
* refactor: migrate from List to Table

* fix: formatting

* fix: formatting

* chore: apply suggestions

* chore: address comments
  • Loading branch information
jaworek authored Oct 31, 2023
1 parent 3995aef commit 191982c
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 97 deletions.
22 changes: 21 additions & 1 deletion MiniSim.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
52B363EA2AEC0D3D006F515C /* ParametersTableViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B363E92AEC0D3D006F515C /* ParametersTableViewModel.swift */; };
52B363EC2AEC10A3006F515C /* ParametersTableForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B363EB2AEC10A3006F515C /* ParametersTableForm.swift */; };
52B363EE2AEC10B3006F515C /* ParametersTableFormViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B363ED2AEC10B3006F515C /* ParametersTableFormViewModel.swift */; };
76059BF52AD4361C0008D38B /* SetupPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76059BF42AD4361C0008D38B /* SetupPreferences.swift */; };
76059BF72AD449DC0008D38B /* OnboardingHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76059BF62AD449DC0008D38B /* OnboardingHeader.swift */; };
76059BF92AD558C30008D38B /* SetupItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76059BF82AD558C30008D38B /* SetupItemView.swift */; };
Expand Down Expand Up @@ -79,6 +82,9 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
52B363E92AEC0D3D006F515C /* ParametersTableViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParametersTableViewModel.swift; sourceTree = "<group>"; };
52B363EB2AEC10A3006F515C /* ParametersTableForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParametersTableForm.swift; sourceTree = "<group>"; };
52B363ED2AEC10B3006F515C /* ParametersTableFormViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParametersTableFormViewModel.swift; sourceTree = "<group>"; };
76059BF42AD4361C0008D38B /* SetupPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPreferences.swift; sourceTree = "<group>"; };
76059BF62AD449DC0008D38B /* OnboardingHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingHeader.swift; sourceTree = "<group>"; };
76059BF82AD558C30008D38B /* SetupItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupItemView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -164,6 +170,17 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
52B363E82AEC0AFD006F515C /* ParametersTable */ = {
isa = PBXGroup;
children = (
76630F0D29BDE7EB00FB64F9 /* ParametersTable.swift */,
52B363EB2AEC10A3006F515C /* ParametersTableForm.swift */,
52B363E92AEC0D3D006F515C /* ParametersTableViewModel.swift */,
52B363ED2AEC10B3006F515C /* ParametersTableFormViewModel.swift */,
);
path = ParametersTable;
sourceTree = "<group>";
};
762CF1E12981DDD400099999 /* Extensions */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -197,13 +214,13 @@
7630B2642985C43300D8B57D /* Views */ = {
isa = PBXGroup;
children = (
52B363E82AEC0AFD006F515C /* ParametersTable */,
7631218C2A12B3A900EE7F48 /* CustomCommands */,
7677999629C25865009030F8 /* Onboarding */,
76F2A9162991B7B6002D4EF6 /* ViewModifiers.swift */,
7630B2652985C44A00D8B57D /* Preferences.swift */,
7630B2672985C4CF00D8B57D /* About.swift */,
76630F0B29BDD0C000FB64F9 /* Devices.swift */,
76630F0D29BDE7EB00FB64F9 /* ParametersTable.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -472,6 +489,7 @@
76E4451429D4403F00039025 /* NSNotificationName.swift in Sources */,
76630F0E29BDE7EB00FB64F9 /* ParametersTable.swift in Sources */,
7677999829C25894009030F8 /* OnboardingPager.swift in Sources */,
52B363EC2AEC10A3006F515C /* ParametersTableForm.swift in Sources */,
7630B2682985C4CF00D8B57D /* About.swift in Sources */,
76630F0C29BDD0C000FB64F9 /* Devices.swift in Sources */,
767C761F29B26ED3009B9AEC /* AccessibilityElement.swift in Sources */,
Expand All @@ -491,13 +509,15 @@
76F2A914299050F9002D4EF6 /* UserDefaults+Configuration.swift in Sources */,
76059BF72AD449DC0008D38B /* OnboardingHeader.swift in Sources */,
763121902A12B45000EE7F48 /* CustomCommandFormViewModel.swift in Sources */,
52B363EE2AEC10B3006F515C /* ParametersTableFormViewModel.swift in Sources */,
7630B2772986D65800D8B57D /* Bundle+appName.swift in Sources */,
763121892A12AF9C00EE7F48 /* Command.swift in Sources */,
767DDF6829D32ABC005E6F32 /* ReadyPopOver.swift in Sources */,
764BA3E92A5AD418003A78AF /* GetDevicesCommand.swift in Sources */,
76059BF92AD558C30008D38B /* SetupItemView.swift in Sources */,
76630F2929BE09D800FB64F9 /* Parameter.swift in Sources */,
7630B27C2987207200D8B57D /* Menu.swift in Sources */,
52B363EA2AEC0D3D006F515C /* ParametersTableViewModel.swift in Sources */,
762CF1E02981968F00099999 /* String+match.swift in Sources */,
76F2A9172991B7B6002D4EF6 /* ViewModifiers.swift in Sources */,
763121872A12AF3400EE7F48 /* CustomCommandForm.swift in Sources */,
Expand Down
96 changes: 0 additions & 96 deletions MiniSim/Views/ParametersTable.swift

This file was deleted.

66 changes: 66 additions & 0 deletions MiniSim/Views/ParametersTable/ParametersTable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// ParametersTable.swift
// MiniSim
//
// Created by Oskar Kwasniewski on 12/03/2023.
//

import SwiftUI

struct ParametersTable: View {
@StateObject private var viewModel: ViewModel = ViewModel()

var body: some View {
VStack {
SectionHeader(
title: "Android additional launch parameters",
subTitle: "These parameters are passed to every android launch command. \nFor example: Cold boot, Run without audio etc."
)
Table(viewModel.parameters, selection: $viewModel.selection) {
TableColumn("Title", value: \.title)
.width(80)
TableColumn("Command", value: \.command)
TableColumn("Enabled") {
Text("\(String($0.enabled))")
}
}
.contextMenu {
if viewModel.selection != nil {
Button(viewModel.selectedParameter?.enabled == true ? "Disable" : "Enable") {
viewModel.toggleEnabled(item: viewModel.selectedParameter?.id)
}
Divider()
Button("Edit") {
viewModel.showForm.toggle()
}
Divider()
Button("Delete") {
viewModel.deleteParameter(item: viewModel.selection)
}
}
}

HStack {
Spacer()
Button("Add New") {
viewModel.selection = nil
viewModel.showForm.toggle()
}
.buttonStyle(.borderedProminent)
.keyboardShortcut("n", modifiers: .command)
}
}
.onAppear {
viewModel.loadData()
}
.sheet(isPresented: $viewModel.showForm) {
ParametersTableForm(parameter: viewModel.selectedParameter, allParameters: viewModel.parameters, onSubmit: viewModel.handleForm)
}
}
}

struct ParametersTable_Previews: PreviewProvider {
static var previews: some View {
ParametersTable()
}
}
77 changes: 77 additions & 0 deletions MiniSim/Views/ParametersTable/ParametersTableForm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// ParametersTableForm.swift
// MiniSim
//
// Created by Jan Jaworski on 27/10/2023.
//

import SwiftUI
import SymbolPicker
import CodeEditor


struct ParametersTableForm: View {
var parameter: Parameter?
var allParameters: [Parameter]
var onSubmit: (_ parameter: Parameter, _ prevParameter: Parameter?) -> Void

@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme

@StateObject private var viewModel: ViewModel = ViewModel()

var body: some View {
Form {
TextField("Title", text: $viewModel.title)
HStack(alignment: .top) {
CodeEditor(
source: $viewModel.command,
language: .bash,
theme: colorScheme == .dark ? .atelierSavannaDark : .atelierSavannaLight,
flags: [.selectable, .editable, .smartIndent]
)
.cornerRadius(6)
}
Toggle("Enabled", isOn: $viewModel.enabled)
.help("Determines if command is enabled.")
.toggleStyle(.switch)

HStack {
HStack {
Button("Cancel") {
dismiss()
viewModel.clearForm()
}
}
Spacer()
Button(parameter != nil ? "Update" : "Add") {
onSubmit(
Parameter(
title: viewModel.title,
command: viewModel.command,
enabled: viewModel.enabled
),
parameter
)
viewModel.clearForm()
}
.buttonStyle(.borderedProminent)
.disabled(viewModel.disableForm)
.keyboardShortcut("s", modifiers: .command)
}
.padding(.top)
}
.padding()
.frame(minWidth: 550, minHeight: 250)
.onAppear {
if let parameter {
viewModel.onAppear(
title: parameter.title,
command: parameter.command,
enabled: parameter.enabled
)
}
viewModel.onAppear(allCommands: allParameters, isUpdating: parameter != nil)
}
}
}
41 changes: 41 additions & 0 deletions MiniSim/Views/ParametersTable/ParametersTableFormViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// ParametersTableFormViewModel.swift
// MiniSim
//
// Created by Jan Jaworski on 27/10/2023.
//

import Foundation

extension ParametersTableForm {
class ViewModel: ObservableObject {
@Published var title = ""
@Published var command = ""
@Published var enabled = true

var allParameters: [Parameter] = []
var isUpdating: Bool = false

func onAppear(title: String = "", command: String = "", enabled: Bool = true) {
self.title = title
self.command = command
self.enabled = enabled
}

func onAppear(allCommands: [Parameter], isUpdating: Bool = false) {
self.allParameters = allCommands
self.isUpdating = isUpdating
}

var disableForm: Bool {
let hasDuplicatedName = !isUpdating && allParameters.contains(where: { $0.title.lowercased() == title.lowercased() })
return title.isEmpty || command.isEmpty || hasDuplicatedName
}

func clearForm() {
title = ""
command = ""
enabled = true
}
}
}
Loading

0 comments on commit 191982c

Please sign in to comment.