jsdw_ios/QuickLocation/Section/Schedule/CreateSchedule/CreateScheduleVM.swift

181 lines
5.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// CreateScheduleVM.swift
// QuickLocation
//
// Created by on 2026/6/24.
//
import RxSwift
import RxCocoa
import RxDataSources
import SwiftDate
// MARK: -
struct SchedulePointItem: IdentifiableType, Equatable {
let identity: String = UUID().uuidString
var locationName: String = ""
var address: String = ""
var latitude: Double = 0
var longitude: Double = 0
var province: String = ""
var city: String = ""
var district: String = ""
var street: String = ""
var country: String = ""
var formatted_address: String = ""
var expectedTime: Date?
var remark: String = ""
}
enum SchedulePointRole: Equatable {
case start
case middle
case end
}
enum CreateScheduleListItem: IdentifiableType, Equatable {
case point(index: Int, item: SchedulePointItem, role: SchedulePointRole)
case add
var identity: String {
switch self {
case .point(_, let item, _):
return item.identity
case .add:
return "__add__"
}
}
}
typealias SchedulePointSection = SectionModel<String, CreateScheduleListItem>
class CreateScheduleVM {
let disposeBag = DisposeBag()
let scheduModel: ScheduleModel?
// MARK: - Input
let addPointTapped = PublishSubject<Void>()
let deletePointAt = PublishSubject<Int>()
let movePoint = PublishSubject<(from: Int, to: Int)>()
let updatePoint = PublishSubject<(index: Int, item: SchedulePointItem)>()
let selectedDate = BehaviorRelay<Date>(value: Date())
var selectedGroupKeys: [String] = []
///
func toggleGroupKey(_ key: String) {
if let idx = selectedGroupKeys.firstIndex(of: key) {
selectedGroupKeys.remove(at: idx)
} else {
selectedGroupKeys.append(key)
}
}
/// key
func removeGroupKey(_ key: String) {
selectedGroupKeys.removeAll { $0 == key }
}
// MARK: - Output
let pointsRelay: BehaviorRelay<[SchedulePointItem]>
let listItems: Observable<[CreateScheduleListItem]>
let dateString: Observable<String>
init(_ model: ScheduleModel?) {
self.scheduModel = model
if let m = model, !m.points.isEmpty {
var items = m.points.map { $0.toSchedulePointItem() }
while items.count < 2 {
items.append(SchedulePointItem())
}
pointsRelay = BehaviorRelay<[SchedulePointItem]>(value: items)
selectedDate.accept(Date(timeIntervalSince1970: TimeInterval(m.timestamp) / 1000))
selectedGroupKeys = m.groups.map { $0.group_key }
} else {
pointsRelay = BehaviorRelay<[SchedulePointItem]>(value: [SchedulePointItem(), SchedulePointItem()])
}
dateString = selectedDate
.map { $0.toFormat("yyyy年MM月dd日") }
listItems = pointsRelay.map { Self.buildListItems(from: $0) }
//
addPointTapped
.withLatestFrom(pointsRelay)
.map { list in
var new = list
let insertAt = max(new.count - 1, 1)
new.insert(SchedulePointItem(), at: insertAt)
return new
}
.bind(to: pointsRelay)
.disposed(by: disposeBag)
// +
deletePointAt
.withLatestFrom(pointsRelay) { ($1, $0) }
.subscribe(onNext: { [weak self] list, idx in
guard list.count > 2, idx > 0, idx < list.count - 1 else { return }
var new = list
new.remove(at: idx)
self?.pointsRelay.accept(new)
})
.disposed(by: disposeBag)
// /
movePoint
.withLatestFrom(pointsRelay) { ($1, $0) }
.subscribe(onNext: { [weak self] list, move in
guard list.count > 2 else { return }
let from = move.from
let to = move.to
let middleRange = 1..<(list.count - 1)
guard middleRange.contains(from), middleRange.contains(to), from != to else { return }
var new = list
let item = new.remove(at: from)
new.insert(item, at: to)
self?.pointsRelay.accept(new)
})
.disposed(by: disposeBag)
//
updatePoint
.withLatestFrom(pointsRelay) { ($1, $0) }
.subscribe(onNext: { [weak self] list, update in
guard update.index < list.count else { return }
var new = list
new[update.index] = update.item
self?.pointsRelay.accept(new)
})
.disposed(by: disposeBag)
}
static func buildListItems(from points: [SchedulePointItem]) -> [CreateScheduleListItem] {
guard points.count >= 2 else {
return points.enumerated().map { idx, item in
let role: SchedulePointRole = idx == 0 ? .start : .end
return .point(index: idx, item: item, role: role)
}
}
var rows: [CreateScheduleListItem] = []
rows.append(.point(index: 0, item: points[0], role: .start))
if points.count > 2 {
for i in 1..<(points.count - 1) {
rows.append(.point(index: i, item: points[i], role: .middle))
}
}
rows.append(.add)
rows.append(.point(index: points.count - 1, item: points[points.count - 1], role: .end))
return rows
}
static func role(at index: Int, total: Int) -> SchedulePointRole {
if index == 0 { return .start }
if index == total - 1 { return .end }
return .middle
}
}