Bark/Controller/HomeViewModel.swift

244 lines
9.4 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.

//
// HomeViewModel.swift
// Bark
//
// Created by huangfeng on 2020/11/18.
// Copyright © 2020 Fin. All rights reserved.
//
import Foundation
import RxCocoa
import RxDataSources
import RxSwift
import SwiftyJSON
import UserNotifications
class HomeViewModel: ViewModel, ViewModelType {
struct Input {
let addCustomServerTap: Driver<Void>
let serverListTap: Driver<Void>
let viewDidAppear: Driver<Void>
let start: Driver<Void>
let clientState: Driver<Client.ClienState>
let authorizationStatus: Single<UNAuthorizationStatus>
let startRequestAuthorizationCreator: () -> Observable<Bool>
}
struct Output {
let previews: Driver<[SectionModel<String, PreviewCardCellViewModel>]>
let push: Driver<ViewModel>
let present: Driver<ViewModel>
let title: Driver<String>
let clienStateChanged: Driver<Client.ClienState>
let tableViewHidden: Driver<Bool>
let showSnackbar: Driver<String>
let alertServerError: Driver<String>
let startButtonEnable: Driver<Bool>
let copy: Driver<String>
let preview: Driver<URL>
let reloadData: Driver<Void>
let registerForRemoteNotifications: Driver<Void>
}
let previews: [PreviewModel] = [
PreviewModel(
body: NSLocalizedString("CustomedNotificationContent"),
notice: NSLocalizedString("Notice1")
),
PreviewModel(
title: NSLocalizedString("CustomedNotificationTitle"),
body: NSLocalizedString("CustomedNotificationContent"),
notice: NSLocalizedString("Notice2")
),
PreviewModel(
body: NSLocalizedString("notificationSound"),
notice: NSLocalizedString("setSounds"),
queryParameter: "sound=minuet",
moreInfo: NSLocalizedString("viewAllSounds"),
moreViewModel: SoundsViewModel()
),
PreviewModel(
body: NSLocalizedString("ringtone"),
notice: NSLocalizedString("ringtoneNotice"),
queryParameter: "call=1"
),
PreviewModel(
body: NSLocalizedString("archiveNotificationMessageTitle"),
notice: NSLocalizedString("archiveNotificationMessage"),
queryParameter: "isArchive=1"
),
PreviewModel(
body: NSLocalizedString("notificationIcon"),
notice: NSLocalizedString("notificationIconNotice"),
queryParameter: "icon=https://day.app/assets/images/avatar.jpg",
image: UIImage(named: "icon")
),
PreviewModel(
body: NSLocalizedString("messageGroup"),
notice: NSLocalizedString("groupMessagesNotice"),
queryParameter: "group=groupName",
image: UIImage(named: "group")
),
PreviewModel(
body: NSLocalizedString("pushNotificationEncryption"),
notice: NSLocalizedString("encryptionNotice"),
queryParameter: "ciphertext=ciphertext",
moreInfo: NSLocalizedString("encryptionSettings"),
moreViewModel: CryptoSettingViewModel()
),
PreviewModel(
body: NSLocalizedString("criticalAlert"),
notice: NSLocalizedString("criticalAlertNotice"),
queryParameter: "level=critical&volume=5",
image: UIImage(named: "criticalAlert")
),
PreviewModel(
body: NSLocalizedString("interruptionLevel"),
notice: NSLocalizedString("interruptionLevelNotice"),
queryParameter: "level=timeSensitive"
),
PreviewModel(
body: "URL Test",
notice: NSLocalizedString("urlParameter"),
queryParameter: "url=https://www.baidu.com"
),
PreviewModel(
body: "Copy Test",
notice: NSLocalizedString("copyParameter"),
queryParameter: "copy=test",
image: UIImage(named: "copyTest")
),
PreviewModel(
body: NSLocalizedString("badge"),
notice: NSLocalizedString("badgeNotice"),
queryParameter: "badge=1"
),
PreviewModel(
body: NSLocalizedString("automaticallyCopyTitle"),
notice: NSLocalizedString("automaticallyCopy"),
queryParameter: "autoCopy=1&copy=optional"
)
]
/// 2FAQ
private var serverErrorCount = 0
func transform(input: Input) -> Output {
let title = BehaviorRelay(value: ServerManager.shared.currentServer.host)
let sectionModel = SectionModel(
model: "previews",
items: previews.map { PreviewCardCellViewModel(previewModel: $0, clientState: input.clientState) }
)
//
let customServer = input.addCustomServerTap.map { NewServerViewModel() as ViewModel }
// title
customServer
.flatMapLatest { model -> Driver<String> in
(model as! NewServerViewModel).pop.asDriver(onErrorJustReturn: "")
}
.drive(title)
.disposed(by: rx.disposeBag)
// previewnotice
let noticeTap = Driver.merge(sectionModel.items.map { $0.noticeTap.asDriver(onErrorDriveWith: .empty()) })
//
let clienState = input.viewDidAppear
.asObservable().flatMapLatest { _ -> Observable<Result<JSON, ApiError>> in
BarkApi.provider
.request(.ping(baseURL: ServerManager.shared.currentServer.address))
.filterResponseError()
}
.map { response -> Client.ClienState in
switch response {
case .failure(let error):
return .serverError(error: error)
default:
return .ok
}
}
//
let tableViewHidden = input.authorizationStatus.map { $0 == .authorized }
.asObservable()
.concat(
input.start.asObservable().flatMapLatest { input.startRequestAuthorizationCreator() }
)
.asDriver(onErrorJustReturn: false)
let showSnackbar = PublishRelay<String>()
let alertServerError = PublishRelay<String>()
//
tableViewHidden
.skip(1)
.compactMap { granted -> String? in
if !granted {
return NSLocalizedString("AllowNotifications")
}
return nil
}
.asObservable()
.bind(to: showSnackbar)
.disposed(by: rx.disposeBag)
// viewController
let registerForRemoteNotifications = tableViewHidden
.skip(1)
.filter { $0 }
.map { _ in () }
// client state
input.clientState.drive(onNext: { [weak self] state in
guard let self else { return }
switch state {
case .ok: break
case .serverError(let error):
if serverErrorCount < 2 {
showSnackbar.accept("\(NSLocalizedString("ServerError")): \(error.rawString())")
} else {
alertServerError.accept(error.rawString())
}
serverErrorCount += 1
default: break
}
// url scheme state便
title.accept(ServerManager.shared.currentServer.host)
})
.disposed(by: rx.disposeBag)
let serverList = input.serverListTap.map { ServerListViewModel() as ViewModel }
//
serverList
.flatMapLatest { model -> Driver<Server> in
(model as! ServerListViewModel).currentServerChanged.asDriver(onErrorDriveWith: .empty())
}
.map { server -> String in
server.host
}
.drive(title)
.disposed(by: rx.disposeBag)
return Output(
previews: Driver.just([sectionModel]),
push: Driver<ViewModel>.merge(customServer, noticeTap),
present: serverList.asDriver(),
title: title.asDriver(),
clienStateChanged: clienState.asDriver(onErrorDriveWith: .empty()),
tableViewHidden: tableViewHidden,
showSnackbar: showSnackbar.asDriver(onErrorDriveWith: .empty()),
alertServerError: alertServerError.asDriver(onErrorDriveWith: .empty()),
startButtonEnable: Driver.just(true),
copy: Driver.merge(sectionModel.items.map { $0.copy.asDriver(onErrorDriveWith: .empty()) }),
preview: Driver.merge(sectionModel.items.map { $0.preview.asDriver(onErrorDriveWith: .empty()) }),
reloadData: input.clientState.map { _ in () },
registerForRemoteNotifications: registerForRemoteNotifications
)
}
}