添加 iPad 支持

This commit is contained in:
sidguan 2024-08-17 17:04:10 +08:00 committed by Feng
parent c18403e845
commit c00fe98b8d
10 changed files with 377 additions and 46 deletions

View File

@ -184,6 +184,9 @@
06F11E7727D9D5FB00F00298 /* QRScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F11E7627D9D5FB00F00298 /* QRScannerViewController.swift */; };
06FB04042C53575400F3A213 /* SharedDefines.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06FB04032C53575400F3A213 /* SharedDefines.swift */; };
06FB04052C53575400F3A213 /* SharedDefines.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06FB04032C53575400F3A213 /* SharedDefines.swift */; };
1E73F99E2C282822002BF649 /* SectionViewController-iPad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E73F99D2C282822002BF649 /* SectionViewController-iPad.swift */; };
1EFB545D2C314A6800B8E51B /* BarkSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFB545C2C314A6800B8E51B /* BarkSplitViewController.swift */; };
1EFB545F2C32514000B8E51B /* SectionViewModel-iPad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFB545E2C32514000B8E51B /* SectionViewModel-iPad.swift */; };
3428272069AFAFE2C683FEB0 /* libPods-Bark.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CCC722470308049D180876C7 /* libPods-Bark.a */; };
879AE4D4178855A9672009E4 /* libPods-NotificationServiceExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B7F8BDFAA047451561798F58 /* libPods-NotificationServiceExtension.a */; };
B963F7D5BA7AC2571E71EF66 /* libPods-BarkTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 76381A752CCCD4DA6BB2A566 /* libPods-BarkTests.a */; };
@ -375,6 +378,9 @@
06FB04032C53575400F3A213 /* SharedDefines.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDefines.swift; sourceTree = "<group>"; };
121D9B1ED4E8D26F345BC5C0 /* Pods-BarkTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BarkTests.release.xcconfig"; path = "Target Support Files/Pods-BarkTests/Pods-BarkTests.release.xcconfig"; sourceTree = "<group>"; };
138CE8CB688587E893BC5C44 /* Pods-Bark.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bark.debug.xcconfig"; path = "Target Support Files/Pods-Bark/Pods-Bark.debug.xcconfig"; sourceTree = "<group>"; };
1E73F99D2C282822002BF649 /* SectionViewController-iPad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionViewController-iPad.swift"; sourceTree = "<group>"; };
1EFB545C2C314A6800B8E51B /* BarkSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarkSplitViewController.swift; sourceTree = "<group>"; };
1EFB545E2C32514000B8E51B /* SectionViewModel-iPad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionViewModel-iPad.swift"; sourceTree = "<group>"; };
519481D715B40109627E1B49 /* Pods-NotificationServiceExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.release.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.release.xcconfig"; sourceTree = "<group>"; };
76381A752CCCD4DA6BB2A566 /* libPods-BarkTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-BarkTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
A69B47DA6DB3B168D5770B45 /* Pods-Bark.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bark.release.xcconfig"; path = "Target Support Files/Pods-Bark/Pods-Bark.release.xcconfig"; sourceTree = "<group>"; };
@ -447,6 +453,9 @@
06EEF332291CCFF400CA228A /* CryptoSettingController.swift */,
06EEF334291CD00000CA228A /* CryptoSettingViewModel.swift */,
06787C3A2AB82BDB008ABDD7 /* CrashReportViewController.swift */,
1E73F99D2C282822002BF649 /* SectionViewController-iPad.swift */,
1EFB545E2C32514000B8E51B /* SectionViewModel-iPad.swift */,
1EFB545C2C314A6800B8E51B /* BarkSplitViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
@ -1098,6 +1107,7 @@
06840DBB272298FB001B3193 /* BKColor.swift in Sources */,
06C2CF232685B88D0034B127 /* TextCell.swift in Sources */,
06BBB896256518760076F63E /* NewServerViewModel.swift in Sources */,
1EFB545D2C314A6800B8E51B /* BarkSplitViewController.swift in Sources */,
06BBB8C92567B6730076F63E /* Operators.swift in Sources */,
0603706920E1F89500F4CA05 /* PreviewCardCell.swift in Sources */,
0627DABB298B6EA2002F3F69 /* DropBoxView.swift in Sources */,
@ -1161,12 +1171,14 @@
06C2CF252685BDB80034B127 /* SpacerCell.swift in Sources */,
06BBB8BC2567B3AD0076F63E /* ArchiveSettingCellViewModel.swift in Sources */,
0642B55A27EB13F100453D91 /* MutableTextCell.swift in Sources */,
1EFB545F2C32514000B8E51B /* SectionViewModel-iPad.swift in Sources */,
06EEF335291CD00000CA228A /* CryptoSettingViewModel.swift in Sources */,
0637FA8020E0981E00E80174 /* BarkSettings.swift in Sources */,
065BE4402563D649002A8CA4 /* SoundsViewModel.swift in Sources */,
065BE4462563D7E5002A8CA4 /* ViewModelType.swift in Sources */,
0603706B20E20A7C00F4CA05 /* String+Extension.swift in Sources */,
068F66B3247BD84C00DAD25A /* MessageListViewController.swift in Sources */,
1E73F99E2C282822002BF649 /* SectionViewController-iPad.swift in Sources */,
06BBB8B72567AC140076F63E /* MessageSettingsViewModel.swift in Sources */,
06BBB8C12567B3EF0076F63E /* BaseTableViewCell.swift in Sources */,
0661A543204FDA4100965E4E /* AppDelegate.swift in Sources */,
@ -1433,8 +1445,10 @@
PRODUCT_BUNDLE_IDENTIFIER = me.fin.bark;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match Development me.fin.bark";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@ -1455,8 +1469,10 @@
PRODUCT_BUNDLE_IDENTIFIER = me.fin.bark;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.fin.bark";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};

View File

@ -78,25 +78,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
setupRealm()
IQKeyboardManager.shared.enable = true
let tabBarController = StateStorageTabBarController()
tabBarController.tabBar.tintColor = BKColor.grey.darken4
self.window?.rootViewController = BarkSnackbarController(
rootViewController: tabBarController
)
tabBarController.viewControllers = [
BarkNavigationController(rootViewController: HomeViewController(viewModel: HomeViewModel())),
BarkNavigationController(rootViewController: MessageListViewController(viewModel: MessageListViewModel())),
BarkNavigationController(rootViewController: MessageSettingsViewController(viewModel: MessageSettingsViewModel()))
]
let tabBarItems = [UITabBarItem(title: NSLocalizedString("service"), image: UIImage(named: "baseline_gite_black_24pt"), tag: 0),
UITabBarItem(title: NSLocalizedString("historyMessage"), image: Icon.history, tag: 1),
UITabBarItem(title: NSLocalizedString("settings"), image: UIImage(named: "baseline_manage_accounts_black_24pt"), tag: 2)]
for (index, viewController) in tabBarController.viewControllers!.enumerated() {
viewController.tabBarItem = tabBarItems[index]
if #available(iOS 14, *), UIDevice.current.userInterfaceIdiom == .pad {
let splitViewController = BarkSplitViewController.init(style: .doubleColumn)
splitViewController.initViewControllers()
self.window?.rootViewController = splitViewController;
} else {
let tabBarController = StateStorageTabBarController()
tabBarController.tabBar.tintColor = BKColor.grey.darken4
self.window?.rootViewController = BarkSnackbarController(
rootViewController: tabBarController
)
tabBarController.viewControllers = [
BarkNavigationController(rootViewController: HomeViewController(viewModel: HomeViewModel())),
BarkNavigationController(rootViewController: MessageListViewController(viewModel: MessageListViewModel())),
BarkNavigationController(rootViewController: MessageSettingsViewController(viewModel: MessageSettingsViewModel()))
]
let tabBarItems = [UITabBarItem(title: NSLocalizedString("service"), image: UIImage(named: "baseline_gite_black_24pt"), tag: 0),
UITabBarItem(title: NSLocalizedString("historyMessage"), image: Icon.history, tag: 1),
UITabBarItem(title: NSLocalizedString("settings"), image: UIImage(named: "baseline_manage_accounts_black_24pt"), tag: 2)]
for (index, viewController) in tabBarController.viewControllers!.enumerated() {
viewController.tabBarItem = tabBarItems[index]
}
}
// tabBarController viewControllers

View File

@ -0,0 +1,68 @@
//
// BarkSplitViewController.swift
// Bark
//
// Created by sidguan on 2024/6/30.
// Copyright © 2024 Fin. All rights reserved.
//
import UIKit
import Material
class BarkSplitViewController: UISplitViewController {
override func viewDidLoad() {
super.viewDidLoad()
// self.displayModeButtonItem.tintColor = BKColor.grey.darken4
// self.delegate = self
// Do any additional setup after loading the view.
}
func initViewControllers() {
if #available(iOS 14, *) {
let sectionViewController = BarkNavigationController(rootViewController: SectionViewController_iPad(viewModel: SectionViewModel()));
let homeViewController = BarkNavigationController(rootViewController: HomeViewController(viewModel: HomeViewModel()));
let tabBarController = StateStorageTabBarController()
tabBarController.tabBar.tintColor = BKColor.grey.darken4
let snackBarController = BarkSnackbarController(
rootViewController: tabBarController
)
tabBarController.viewControllers = [
BarkNavigationController(rootViewController: HomeViewController(viewModel: HomeViewModel())),
BarkNavigationController(rootViewController: MessageListViewController(viewModel: MessageListViewModel())),
BarkNavigationController(rootViewController: MessageSettingsViewController(viewModel: MessageSettingsViewModel()))
]
let tabBarItems = [
UITabBarItem(title: NSLocalizedString("service"), image: UIImage(named: "baseline_gite_black_24pt"), tag: 0),
UITabBarItem(title: NSLocalizedString("historyMessage"), image: Icon.history, tag: 1),
UITabBarItem(title: NSLocalizedString("settings"), image: UIImage(named: "baseline_manage_accounts_black_24pt"), tag: 2)
]
for (index, viewController) in tabBarController.viewControllers!.enumerated() {
viewController.tabBarItem = tabBarItems[index]
}
self.setViewController(sectionViewController, for: .primary)
self.setViewController(homeViewController, for: .secondary)
self.setViewController(snackBarController, for: .compact)
}
}
// func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
// return true
// }
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

View File

@ -28,7 +28,11 @@ class BaseViewController<T>: UIViewController where T: ViewModel {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.largeTitleDisplayMode = .automatic
if UIDevice.current.userInterfaceIdiom == .pad {
navigationItem.largeTitleDisplayMode = .never
} else {
navigationItem.largeTitleDisplayMode = .automatic
}
makeUI()
}

View File

@ -31,18 +31,18 @@ enum MessageDeleteType: Int {
}
class MessageListViewController: BaseViewController<MessageListViewModel> {
let deleteButton: BKButton = {
let deleteButton: UIBarButtonItem = {
let btn = BKButton()
btn.setImage(UIImage(named: "baseline_delete_outline_black_24pt"), for: .normal)
btn.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
return btn
return UIBarButtonItem(customView: btn)
}()
let groupButton: BKButton = {
let groupButton: UIBarButtonItem = {
let btn = BKButton()
btn.setImage(UIImage(named: "baseline_folder_open_black_24pt"), for: .normal)
btn.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
return btn
return UIBarButtonItem(customView: btn)
}()
let tableView: UITableView = {
@ -59,7 +59,7 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
navigationItem.searchController?.obscuresBackgroundDuringPresentation = false
navigationItem.searchController?.delegate = self
navigationItem.setBarButtonItems(items: [UIBarButtonItem(customView: deleteButton), UIBarButtonItem(customView: groupButton)], position: .right)
navigationItem.setBarButtonItems(items: [deleteButton, groupButton], position: .right)
self.view.addSubview(tableView)
tableView.snp.makeConstraints { make in
@ -96,9 +96,12 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
}
override func bindViewModel() {
let batchDelete = deleteButton.rx
guard let deleteBtn = deleteButton.customView as? BKButton else {
return;
}
let batchDelete = deleteBtn.rx
.tap
.flatMapLatest { _ -> PublishRelay<MessageDeleteType> in
.flatMapLatest {_ -> PublishRelay<MessageDeleteType> in
let relay = PublishRelay<MessageDeleteType>()
func alert(_ type: MessageDeleteType) {
@ -124,19 +127,31 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
alert(.allTime)
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel"), style: .cancel, handler: nil))
if UIDevice.current.userInterfaceIdiom == .pad {
alertController.modalPresentationStyle = .popover
if #available(iOS 16.0, *) {
alertController.popoverPresentationController?.sourceItem = self.deleteButton
} else {
alertController.popoverPresentationController?.barButtonItem = self.deleteButton
}
}
self.navigationController?.present(alertController, animated: true, completion: nil)
return relay
}
guard let groupBtn = groupButton.customView as? BKButton else {
return;
}
let output = viewModel.transform(
input: MessageListViewModel.Input(
refresh: tableView.refreshControl!.rx.controlEvent(.valueChanged).asDriver(),
loadMore: tableView.mj_footer!.rx.refresh.asDriver(),
itemDelete: tableView.rx.itemDeleted.asDriver(),
itemSelected: tableView.rx.modelSelected(MessageTableViewCellViewModel.self).asDriver(),
itemSelected: tableView.rx.itemSelected.asDriver(),
delete: batchDelete.asDriver(onErrorDriveWith: .empty()),
groupTap: groupButton.rx.tap.asDriver(),
groupTap: groupBtn.rx.tap.asDriver(),
searchText: navigationItem.searchController!.searchBar.rx.text.asObservable()))
// tableView
@ -166,7 +181,7 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
// messagealert
output.alertMessage.drive(onNext: { [weak self] message in
self?.alertMessage(message: message)
self?.alertMessage(message: message.0, indexPath: message.1)
}).disposed(by: rx.disposeBag)
//
@ -183,7 +198,7 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
self.scrollToTop()
}
func alertMessage(message: String) {
func alertMessage(message: String, indexPath: IndexPath) {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let copyAction = UIAlertAction(title: NSLocalizedString("CopyAll"), style: .default, handler: { [weak self]
(_: UIAlertAction) -> Void in
@ -195,6 +210,13 @@ class MessageListViewController: BaseViewController<MessageListViewModel> {
alertController.addAction(copyAction)
alertController.addAction(cancelAction)
if UIDevice.current.userInterfaceIdiom == .pad {
alertController.modalPresentationStyle = .popover
if let cell = self.tableView.cellForRow(at: indexPath) {
alertController.popoverPresentationController?.sourceView = self.tableView
alertController.popoverPresentationController?.sourceRect = cell.frame
}
}
self.navigationController?.present(alertController, animated: true, completion: nil)
}

View File

@ -11,13 +11,14 @@ import RealmSwift
import RxCocoa
import RxDataSources
import RxSwift
import UIKit
class MessageListViewModel: ViewModel, ViewModelType {
struct Input {
var refresh: Driver<Void>
var loadMore: Driver<Void>
var itemDelete: Driver<IndexPath>
var itemSelected: Driver<MessageTableViewCellViewModel>
var itemSelected: Driver<IndexPath>
var delete: Driver<MessageDeleteType>
var groupTap: Driver<Void>
var searchText: Observable<String?>
@ -26,7 +27,7 @@ class MessageListViewModel: ViewModel, ViewModelType {
struct Output {
var messages: Driver<[MessageSection]>
var refreshAction: Driver<MJRefreshAction>
var alertMessage: Driver<String>
var alertMessage: Driver<(String, IndexPath)>
var groupFilter: Driver<GroupFilterViewModel>
var title: Driver<String>
}
@ -70,8 +71,12 @@ class MessageListViewModel: ViewModel, ViewModelType {
}
func transform(input: Input) -> Output {
let alertMessage = input.itemSelected.map { model -> String in
let message = model.message
let alertMessage = input.itemSelected.map({ [weak self] indexPath in
guard let results = self?.results else {
return ("", IndexPath(row: 0, section: 0));
}
let message = results[indexPath.row]
// let message = model.message
var copyContent: String = ""
if let title = message.title {
@ -85,8 +90,8 @@ class MessageListViewModel: ViewModel, ViewModelType {
}
copyContent = String(copyContent.prefix(copyContent.count - 1))
return copyContent
}
return (copyContent, indexPath)
})
//
let titleRelay = BehaviorRelay<String>(value: NSLocalizedString("historyMessage"))
//

View File

@ -64,14 +64,18 @@ class MessageSettingsViewController: BaseViewController<MessageSettingsViewModel
///
func getBackupOrRestoreAction() -> (Driver<Void>, Driver<Data>) {
let backupOrRestoreAction = self.tableView.rx
.modelSelected(MessageSettingItem.self)
.filter { item in
if case MessageSettingItem.backup = item {
// .modelSelected(MessageSettingItem.self)
.itemSelected
.filter { indexPath in
guard let viewModel: MessageSettingItem = try? self.tableView.rx.model(at: indexPath) else {
return false;
}
if case MessageSettingItem.backup = viewModel {
return true
}
return false
}
.flatMapLatest { [weak self] _ in
.flatMapLatest { [weak self] indexPath in
guard let strongSelf = self else {
return Observable<BackupOrRestoreActionEnum>.empty()
}
@ -91,7 +95,15 @@ class MessageSettingsViewController: BaseViewController<MessageSettingsViewModel
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel"), style: .cancel, handler: nil))
strongSelf.navigationController?.present(alertController, animated: true, completion: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
alertController.modalPresentationStyle = .popover
if let cell = strongSelf.tableView.cellForRow(at: indexPath) {
alertController.popoverPresentationController?.sourceView = strongSelf.tableView
alertController.popoverPresentationController?.sourceRect = cell.frame
}
}
strongSelf.present(alertController, animated: true, completion: nil)
return strongSelf.backupOrRestoreActionRelay.asObservable()
}
@ -210,6 +222,10 @@ class MessageSettingsViewController: BaseViewController<MessageSettingsViewModel
}
let activityController = UIActivityViewController(activityItems: [linkURL], applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
activityController.popoverPresentationController?.sourceView = self?.view
activityController.popoverPresentationController?.sourceRect = self?.view.frame ?? .zero
}
self?.navigationController?.present(activityController, animated: true, completion: nil)
}.disposed(by: rx.disposeBag)

View File

@ -0,0 +1,134 @@
//
// SectionTableViewController-iPad.swift
// Bark
//
// Created by sidguan on 2024/6/23.
// Copyright © 2024 Fin. All rights reserved.
//
import UIKit
import NSObject_Rx
import RxCocoa
import RxDataSources
import RxSwift
class SectionViewController_iPad: BaseViewController<SectionViewModel>, UITableViewDelegate {
let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "\(UITableViewCell.self)")
tableView.backgroundColor = BKColor.background.primary
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Bark"
navigationItem.largeTitleDisplayMode = .automatic
}
override func makeUI() {
self.view.addSubview(tableView)
tableView.delegate = self
tableView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
override func bindViewModel() {
let output = viewModel.transform(input: SectionViewModel.Input())
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, SectionItem>> {
_, tableView, _, item -> UITableViewCell in
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(UITableViewCell.self)") else {
return UITableViewCell()
}
if #available(iOS 14, *) {
cell.backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
}
cell.selectionStyle = .gray
cell.imageView?.image = item.image
cell.imageView?.tintColor = BKColor.grey.darken4
cell.textLabel?.text = item.title
return cell
}
tableView.rx
.itemSelected
.flatMapLatest { indexPath -> Observable<IndexPath> in
return Observable.just(indexPath)
}
.subscribe { indexPath in
if #available(iOS 14, *) {
if indexPath.row == 0 {
self.splitViewController?.setViewController(
BarkNavigationController(rootViewController: HomeViewController(viewModel: HomeViewModel())), for: .secondary)
} else if indexPath.row == 1 {
self.splitViewController?.setViewController(
BarkNavigationController(rootViewController: MessageListViewController(viewModel: MessageListViewModel())), for: .secondary)
} else if (indexPath.row == 2) {
self.splitViewController?.setViewController(
BarkNavigationController(rootViewController: MessageSettingsViewController(viewModel: MessageSettingsViewModel())), for: .secondary)
}
} else {
//
}
}.disposed(by: rx.disposeBag)
output.items
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: rx.disposeBag)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 55
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

View File

@ -0,0 +1,50 @@
//
// SectionViewModel-iPad.swift
// Bark
//
// Created by sidguan on 2024/7/1.
// Copyright © 2024 Fin. All rights reserved.
//
import Foundation
import RxCocoa
import RxDataSources
import RxSwift
import Material
struct SectionItem {
let image: UIImage?
let title: String
}
class SectionViewModel: ViewModel, ViewModelType {
struct Input {
// var sectionSelected: Driver<SectionItem>
}
struct Output {
var items: Observable<[SectionModel<String, SectionItem>]>
// var selectedItem: Observable<SectionItem?>
}
func initSectionItems() -> Observable<[SectionModel<String, SectionItem>]> {
return Observable.create { (observer) -> Disposable in
let sectionItems = [
SectionItem(image: UIImage(named: "baseline_gite_black_24pt"), title: NSLocalizedString("service")),
SectionItem(image: Icon.history, title: NSLocalizedString("historyMessage")),
SectionItem(image: UIImage(named: "baseline_manage_accounts_black_24pt"), title: NSLocalizedString("settings")),
]
let section = [SectionModel(model: "", items: sectionItems)]
observer.onNext(section)
observer.onCompleted()
return Disposables.create()
}
}
func transform(input: Input) -> Output {
let sectionItems = initSectionItems()
return Output(
items: sectionItems
)
}
}

View File

@ -124,9 +124,12 @@ class ServerListViewController: BaseViewController<ServerListViewModel> {
func getServerAction() -> Driver<(Server, ServerActionType)> {
return tableView.rx
.modelSelected(ServerListTableViewCellViewModel.self)
.flatMapLatest { viewModel -> PublishRelay<(Server, ServerActionType)> in
.itemSelected
.flatMapLatest { indexPath in
let relay = PublishRelay<(Server, ServerActionType)>()
guard let viewModel: ServerListTableViewCellViewModel = try? self.tableView.rx.model(at: indexPath) else {
return relay;
}
let alertController = UIAlertController(title: nil, message: "\(viewModel.address.value)", preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: NSLocalizedString("copyAddressAndKey"), style: .default, handler: { _ in
@ -157,6 +160,14 @@ class ServerListViewController: BaseViewController<ServerListViewModel> {
}))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel"), style: .cancel, handler: nil))
if UIDevice.current.userInterfaceIdiom == .pad {
alertController.modalPresentationStyle = .popover
if let cell = self.tableView.cellForRow(at: indexPath) {
alertController.popoverPresentationController?.sourceView = self.tableView
alertController.popoverPresentationController?.sourceRect = cell.frame
}
}
self.navigationController?.present(alertController, animated: true, completion: nil)
return relay