Skip to content

Commit

Permalink
introduce a view model in service tab
Browse files Browse the repository at this point in the history
  • Loading branch information
CanglongCl committed Jan 15, 2024
1 parent 5b31ce4 commit 2e6db53
Showing 1 changed file with 48 additions and 34 deletions.
82 changes: 48 additions & 34 deletions Easydict/NewApp/View/SettingView/Tabs/ServiceTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import SwiftUI

@available(macOS 13, *)
struct ServiceTab: View {
@State private var windowType = EZWindowType.mini
@State private var selectedService: QueryService?
@StateObject private var viewModel: ServiceTabViewModel = .init()

@Environment(\.colorScheme) private var colorScheme

Expand All @@ -27,10 +26,10 @@ struct ServiceTab: View {
var body: some View {
HStack {
VStack {
WindowTypePicker(windowType: $windowType)
WindowTypePicker(windowType: $viewModel.windowType)
.padding()
List {
ServiceItems(windowType: windowType, selectedService: $selectedService)
ServiceItems()
}
.scrollContentBackground(.hidden)
.listStyle(.plain)
Expand All @@ -42,7 +41,7 @@ struct ServiceTab: View {
}
.background(bgColor)
Group {
if let service = selectedService {
if let service = viewModel.selectedService {
// To provide configuration options for a service, follow these steps
// 1. If the Service is an object of Objc, expose it to Swift.
// 2. Create a new file in the Utility - Extensions - QueryService+ConfigurableService,
Expand All @@ -61,33 +60,33 @@ struct ServiceTab: View {
}
.frame(minWidth: 500)
}
.environmentObject(viewModel)
}
}

@available(macOS 13.0, *)
private struct ServiceItems: View {
let windowType: EZWindowType
@Binding var selectedService: QueryService?

private var services: [QueryService] {
EZLocalStorage.shared().allServices(windowType)
private class ServiceTabViewModel: ObservableObject {
@Published var windowType = EZWindowType.mini {
didSet {
if oldValue != windowType {
updateServices()
}
}
}

private var servicesWithID: [(QueryService, String)] {
services.map { service in
(service, service.name())
}
@Published var selectedService: QueryService?

lazy var services: [QueryService] = EZLocalStorage.shared().allServices(windowType)

func updateServices() {
services = getServices()
}

var body: some View {
ForEach(servicesWithID, id: \.1) { service, _ in
ServiceItemView(service: service, windowType: windowType, selectedService: $selectedService)
.tag(service)
}
.onMove(perform: onServiceItemMove)
func getServices() -> [QueryService] {
EZLocalStorage.shared().allServices(windowType)
}

private func onServiceItemMove(fromOffsets: IndexSet, toOffset: Int) {
func onServiceItemMove(fromOffsets: IndexSet, toOffset: Int) {
guard fromOffsets.first != toOffset else { return }
var services = services

services.move(fromOffsets: fromOffsets, toOffset: toOffset)
Expand All @@ -100,29 +99,44 @@ private struct ServiceItems: View {

postUpdateServiceNotification()

// Trigger rerender to update view with new position
refresh.objectWillChange.send()
updateServices()

objectWillChange.send()
}

private func postUpdateServiceNotification() {
func postUpdateServiceNotification() {
let userInfo: [String: Any] = [EZWindowTypeKey: windowType.rawValue]
let notification = Notification(name: .serviceHasUpdated, object: nil, userInfo: userInfo)
NotificationCenter.default.post(notification)
}
}

@available(macOS 13.0, *)
private struct ServiceItems: View {
@EnvironmentObject private var viewModel: ServiceTabViewModel

private var servicesWithID: [(QueryService, String)] {
viewModel.services.map { service in
(service, service.name())
}
}

private class RefreshObservableObject: ObservableObject {}
@StateObject private var refresh: RefreshObservableObject = .init()
var body: some View {
ForEach(servicesWithID, id: \.1) { service, _ in
ServiceItemView(service: service, windowType: viewModel.windowType)
.tag(service)
}
.onMove(perform: viewModel.onServiceItemMove)
}
}

@available(macOS 13.0, *)
private struct ServiceItemView: View {
@StateObject private var service: QueryServiceWrapper
@EnvironmentObject private var viewModel: ServiceTabViewModel

@Binding private var selectedService: QueryService?

init(service: QueryService, windowType: EZWindowType, selectedService: Binding<QueryService?>) {
init(service: QueryService, windowType: EZWindowType) {
_service = .init(wrappedValue: .init(queryService: service, windowType: windowType))
_selectedService = selectedService
}

var body: some View {
Expand All @@ -141,10 +155,10 @@ private struct ServiceItemView: View {
.listRowSeparator(.hidden)
.listRowInsets(.init())
.padding(10)
.listRowBackground(selectedService == service.inner ? Color("service_cell_highlight") : tableColor)
.listRowBackground(viewModel.selectedService == service.inner ? Color("service_cell_highlight") : tableColor)
.overlay {
TapHandler {
selectedService = service.inner
viewModel.selectedService = service.inner
}
}
}
Expand Down

0 comments on commit 2e6db53

Please sign in to comment.