Remove Community-tab from Explore-tab (IOS-236) (#1260)
This commit is contained in:
parent
27353a3bdb
commit
83fd4a89fa
|
@ -266,11 +266,6 @@
|
|||
DB3E6FF52807C40300B035AE /* DiscoveryForYouViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */; };
|
||||
DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */; };
|
||||
DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */; };
|
||||
DB3EA8E6281B79E200598866 /* DiscoveryCommunityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8E5281B79E200598866 /* DiscoveryCommunityViewController.swift */; };
|
||||
DB3EA8E9281B7A3700598866 /* DiscoveryCommunityViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8E8281B7A3700598866 /* DiscoveryCommunityViewModel.swift */; };
|
||||
DB3EA8EB281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8EA281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift */; };
|
||||
DB3EA8EF281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8EE281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift */; };
|
||||
DB3EA8F1281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8F0281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift */; };
|
||||
DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; };
|
||||
DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; };
|
||||
DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; };
|
||||
|
@ -913,11 +908,6 @@
|
|||
DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewController.swift; sourceTree = "<group>"; };
|
||||
DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewModel.swift; sourceTree = "<group>"; };
|
||||
DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryForYouViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
||||
DB3EA8E5281B79E200598866 /* DiscoveryCommunityViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryCommunityViewController.swift; sourceTree = "<group>"; };
|
||||
DB3EA8E8281B7A3700598866 /* DiscoveryCommunityViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryCommunityViewModel.swift; sourceTree = "<group>"; };
|
||||
DB3EA8EA281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryCommunityViewModel+State.swift"; sourceTree = "<group>"; };
|
||||
DB3EA8EE281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryCommunityViewController+DataSourceProvider.swift"; sourceTree = "<group>"; };
|
||||
DB3EA8F0281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryCommunityViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
||||
DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DB427DD525BAA00100D1B89D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
DB427DD725BAA00100D1B89D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
|
@ -2060,18 +2050,6 @@
|
|||
path = ForYou;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB3EA8E7281B79E500598866 /* Community */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB3EA8E5281B79E200598866 /* DiscoveryCommunityViewController.swift */,
|
||||
DB3EA8EE281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift */,
|
||||
DB3EA8E8281B7A3700598866 /* DiscoveryCommunityViewModel.swift */,
|
||||
DB3EA8F0281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift */,
|
||||
DB3EA8EA281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift */,
|
||||
);
|
||||
path = Community;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB427DC925BAA00100D1B89D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2860,7 +2838,6 @@
|
|||
DBDFF19828055A0900557A48 /* Posts */,
|
||||
DB3E6FDE2806A41200B035AE /* Hashtags */,
|
||||
DB3E6FED2806D7FC00B035AE /* News */,
|
||||
DB3EA8E7281B79E500598866 /* Community */,
|
||||
DB3E6FF62807C40500B035AE /* ForYou */,
|
||||
DB3E6FE32806A5B800B035AE /* DiscoverySection.swift */,
|
||||
DB3E6FE62806A7A200B035AE /* DiscoveryItem.swift */,
|
||||
|
@ -3599,7 +3576,6 @@
|
|||
D81A94172B07A1D30067A19D /* ProfileCardView+Configuration.swift in Sources */,
|
||||
DB63F7452799056400455B82 /* HashtagTableViewCell.swift in Sources */,
|
||||
D82BD7552ABC73AF009A374A /* NotificationPolicyTableViewCell.swift in Sources */,
|
||||
DB3EA8EB281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift in Sources */,
|
||||
DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */,
|
||||
DB98EB5327B0F9890082E365 /* ReportHeadlineTableViewCell.swift in Sources */,
|
||||
DB5B729C273113C200081888 /* FollowingListViewModel+Diffable.swift in Sources */,
|
||||
|
@ -3700,7 +3676,6 @@
|
|||
DB1E346825F518E20079D7DF /* CategoryPickerSection.swift in Sources */,
|
||||
DB7274F4273BB9B200577D95 /* ListBatchFetchViewModel.swift in Sources */,
|
||||
DB0618052785A73D0030EE79 /* RegisterItem.swift in Sources */,
|
||||
DB3EA8EF281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift in Sources */,
|
||||
DB6B74EF272FB55000C70B6E /* FollowerListViewController.swift in Sources */,
|
||||
DB4AA6B327BA34B6009EC082 /* CellFrameCacheContainer.swift in Sources */,
|
||||
DB0FCB942797E2B0006C02E2 /* SearchResultViewModel+Diffable.swift in Sources */,
|
||||
|
@ -3746,12 +3721,10 @@
|
|||
D8F9170D2A4B3C6F008A5370 /* AboutMastodonTableViewCell.swift in Sources */,
|
||||
DB697DE1278F5296004EF2F7 /* DataSourceFacade+Model.swift in Sources */,
|
||||
DB4F097526A037F500D62E92 /* SearchHistoryViewModel.swift in Sources */,
|
||||
DB3EA8E9281B7A3700598866 /* DiscoveryCommunityViewModel.swift in Sources */,
|
||||
D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */,
|
||||
DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */,
|
||||
DBEFCD71282A12B200C0ABEA /* ReportReasonViewController.swift in Sources */,
|
||||
DB98EB5627B0FF1B0082E365 /* ReportViewControllerAppearance.swift in Sources */,
|
||||
DB3EA8E6281B79E200598866 /* DiscoveryCommunityViewController.swift in Sources */,
|
||||
2D206B8625F5FB0900143C56 /* Double.swift in Sources */,
|
||||
2AB5011C299243FB00346092 /* WidgetExtension.intentdefinition in Sources */,
|
||||
DB9F58F126EF512300E7BBE9 /* AccountListTableViewCell.swift in Sources */,
|
||||
|
@ -3831,7 +3804,6 @@
|
|||
DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */,
|
||||
D8F917112A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift in Sources */,
|
||||
D8B5E4EE2A4EB8930008970C /* NotificationSettingTableViewToggleCell.swift in Sources */,
|
||||
DB3EA8F1281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift in Sources */,
|
||||
D8318A8A2A4468DC00C0FB73 /* AboutViewController.swift in Sources */,
|
||||
85BC11B32932414900E191CD /* AltTextViewController.swift in Sources */,
|
||||
DB63F775279A997D00455B82 /* NotificationTableViewCell+ViewModel.swift in Sources */,
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
//
|
||||
// DiscoveryCommunityViewController+DataSourceProvider.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK on 2022-4-29.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonSDK
|
||||
|
||||
extension DiscoveryCommunityViewController: DataSourceProvider {
|
||||
func item(from source: DataSourceItem.Source) async -> DataSourceItem? {
|
||||
var _indexPath = source.indexPath
|
||||
if _indexPath == nil, let cell = source.tableViewCell {
|
||||
_indexPath = await self.indexPath(for: cell)
|
||||
}
|
||||
guard let indexPath = _indexPath else { return nil }
|
||||
|
||||
guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch item {
|
||||
case .status(let record):
|
||||
return .status(record: record)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func update(status: MastodonStatus, intent: MastodonStatus.UpdateIntent) {
|
||||
viewModel.dataController.update(status: status, intent: intent)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
|
||||
return tableView.indexPath(for: cell)
|
||||
}
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
//
|
||||
// DiscoveryCommunityViewController.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK on 2022-4-29.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
import MastodonCore
|
||||
import MastodonUI
|
||||
|
||||
// Local Timeline
|
||||
final class DiscoveryCommunityViewController: UIViewController, NeedsDependency, MediaPreviewableViewController {
|
||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
var viewModel: DiscoveryCommunityViewModel!
|
||||
|
||||
let mediaPreviewTransitionController = MediaPreviewTransitionController()
|
||||
|
||||
lazy var tableView: UITableView = {
|
||||
let tableView = UITableView()
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 100
|
||||
tableView.separatorStyle = .none
|
||||
tableView.backgroundColor = .clear
|
||||
return tableView
|
||||
}()
|
||||
|
||||
let refreshControl = RefreshControl()
|
||||
}
|
||||
|
||||
extension DiscoveryCommunityViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = .secondarySystemBackground
|
||||
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(tableView)
|
||||
tableView.pinToParent()
|
||||
|
||||
tableView.refreshControl = refreshControl
|
||||
refreshControl.addTarget(self, action: #selector(DiscoveryCommunityViewController.refreshControlValueChanged(_:)), for: .valueChanged)
|
||||
viewModel.didLoadLatest
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.refreshControl.endRefreshing()
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
tableView.delegate = self
|
||||
viewModel.setupDiffableDataSource(
|
||||
tableView: tableView,
|
||||
statusTableViewCellDelegate: self
|
||||
)
|
||||
|
||||
// setup batch fetch
|
||||
viewModel.listBatchFetchViewModel.setup(scrollView: tableView)
|
||||
viewModel.listBatchFetchViewModel.shouldFetch
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
guard self.view.window != nil else { return }
|
||||
self.viewModel.stateMachine.enter(DiscoveryCommunityViewModel.State.Loading.self)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
tableView.deselectRow(with: transitionCoordinator, animated: animated)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
viewModel.viewDidAppeared.send()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension DiscoveryCommunityViewController {
|
||||
|
||||
@objc private func refreshControlValueChanged(_ sender: RefreshControl) {
|
||||
if !viewModel.stateMachine.enter(DiscoveryCommunityViewModel.State.Reloading.self) {
|
||||
refreshControl.endRefreshing()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - AuthContextProvider
|
||||
extension DiscoveryCommunityViewController: AuthContextProvider {
|
||||
var authContext: AuthContext { viewModel.authContext }
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
extension DiscoveryCommunityViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
|
||||
// sourcery:inline:DiscoveryCommunityViewController.AutoGenerateTableViewDelegate
|
||||
|
||||
// Generated using Sourcery
|
||||
// DO NOT EDIT
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
aspectTableView(tableView, didSelectRowAt: indexPath)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
return aspectTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
||||
return aspectTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
|
||||
return aspectTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration)
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
|
||||
aspectTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator)
|
||||
}
|
||||
// sourcery:end
|
||||
}
|
||||
|
||||
// MARK: - StatusTableViewCellDelegate
|
||||
extension DiscoveryCommunityViewController: StatusTableViewCellDelegate { }
|
||||
|
||||
// MARK: ScrollViewContainer
|
||||
extension DiscoveryCommunityViewController: ScrollViewContainer {
|
||||
var scrollView: UIScrollView { tableView }
|
||||
}
|
||||
|
||||
extension DiscoveryCommunityViewController {
|
||||
override var keyCommands: [UIKeyCommand]? {
|
||||
return navigationKeyCommands + statusNavigationKeyCommands
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - StatusTableViewControllerNavigateable
|
||||
extension DiscoveryCommunityViewController: StatusTableViewControllerNavigateable {
|
||||
@objc func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) {
|
||||
navigateKeyCommandHandler(sender)
|
||||
}
|
||||
|
||||
@objc func statusKeyCommandHandlerRelay(_ sender: UIKeyCommand) {
|
||||
statusKeyCommandHandler(sender)
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
//
|
||||
// DiscoveryCommunityViewModel+Diffable.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK on 2022-4-29.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
extension DiscoveryCommunityViewModel {
|
||||
|
||||
func setupDiffableDataSource(
|
||||
tableView: UITableView,
|
||||
statusTableViewCellDelegate: StatusTableViewCellDelegate
|
||||
) {
|
||||
diffableDataSource = StatusSection.diffableDataSource(
|
||||
tableView: tableView,
|
||||
context: context,
|
||||
configuration: StatusSection.Configuration(
|
||||
context: context,
|
||||
authContext: authContext,
|
||||
statusTableViewCellDelegate: statusTableViewCellDelegate,
|
||||
timelineMiddleLoaderTableViewCellDelegate: nil,
|
||||
filterContext: .none,
|
||||
activeFilters: nil
|
||||
)
|
||||
)
|
||||
|
||||
stateMachine.enter(State.Reloading.self)
|
||||
|
||||
dataController.$records
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] records in
|
||||
guard let self = self else { return }
|
||||
guard let diffableDataSource = self.diffableDataSource else { return }
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<StatusSection, StatusItem>()
|
||||
snapshot.appendSections([.main])
|
||||
|
||||
let items = records.map { StatusItem.status(record: $0) }
|
||||
snapshot.appendItems(items, toSection: .main)
|
||||
|
||||
if let currentState = self.stateMachine.currentState {
|
||||
switch currentState {
|
||||
case is State.Initial,
|
||||
is State.Reloading,
|
||||
is State.Loading,
|
||||
is State.Idle,
|
||||
is State.Fail:
|
||||
if !items.isEmpty {
|
||||
snapshot.appendItems([.bottomLoader], toSection: .main)
|
||||
}
|
||||
case is State.NoMore:
|
||||
break
|
||||
default:
|
||||
assertionFailure()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
diffableDataSource.apply(snapshot, animatingDifferences: false)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
//
|
||||
// DiscoveryCommunityViewModel+State.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK on 2022-4-29.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import GameplayKit
|
||||
import MastodonSDK
|
||||
import enum NIOHTTP1.HTTPResponseStatus
|
||||
|
||||
extension DiscoveryCommunityViewModel {
|
||||
class State: GKState {
|
||||
|
||||
let id = UUID()
|
||||
|
||||
weak var viewModel: DiscoveryCommunityViewModel?
|
||||
|
||||
init(viewModel: DiscoveryCommunityViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
override func didEnter(from previousState: GKState?) {
|
||||
super.didEnter(from: previousState)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func enter(state: State.Type) {
|
||||
stateMachine?.enter(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension DiscoveryCommunityViewModel.State {
|
||||
class Initial: DiscoveryCommunityViewModel.State {
|
||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||
switch stateClass {
|
||||
case is Reloading.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Reloading: DiscoveryCommunityViewModel.State {
|
||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||
switch stateClass {
|
||||
case is Loading.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override func didEnter(from previousState: GKState?) {
|
||||
super.didEnter(from: previousState)
|
||||
guard let _ = viewModel, let stateMachine = stateMachine else { return }
|
||||
|
||||
stateMachine.enter(Loading.self)
|
||||
}
|
||||
}
|
||||
|
||||
class Fail: DiscoveryCommunityViewModel.State {
|
||||
|
||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||
switch stateClass {
|
||||
case is Loading.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override func didEnter(from previousState: GKState?) {
|
||||
super.didEnter(from: previousState)
|
||||
guard let _ = viewModel, let stateMachine = stateMachine else { return }
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
stateMachine.enter(Loading.self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Idle: DiscoveryCommunityViewModel.State {
|
||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||
switch stateClass {
|
||||
case is Reloading.Type, is Loading.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Loading: DiscoveryCommunityViewModel.State {
|
||||
|
||||
var maxID: String?
|
||||
|
||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||
switch stateClass {
|
||||
case is Fail.Type:
|
||||
return true
|
||||
case is Idle.Type:
|
||||
return true
|
||||
case is NoMore.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override func didEnter(from previousState: GKState?) {
|
||||
super.didEnter(from: previousState)
|
||||
guard let viewModel else { return }
|
||||
|
||||
switch previousState {
|
||||
case is Reloading:
|
||||
maxID = nil
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
let maxID = self.maxID
|
||||
let isReloading = maxID == nil
|
||||
|
||||
Task {
|
||||
do {
|
||||
let response = try await viewModel.context.apiService.publicTimeline(
|
||||
query: .init(
|
||||
local: true,
|
||||
remote: nil,
|
||||
onlyMedia: nil,
|
||||
maxID: maxID,
|
||||
sinceID: nil,
|
||||
minID: nil,
|
||||
limit: 20
|
||||
),
|
||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
|
||||
let newMaxID = response.link?.maxID
|
||||
let hasMore = newMaxID != nil
|
||||
self.maxID = newMaxID
|
||||
|
||||
var hasNewStatusesAppend = false
|
||||
var statusIDs = isReloading ? [] : await viewModel.dataController.records
|
||||
for status in response.value {
|
||||
guard !statusIDs.contains(where: { $0.id == status.id }) else { continue }
|
||||
statusIDs.append(.fromEntity(status))
|
||||
hasNewStatusesAppend = true
|
||||
}
|
||||
|
||||
if hasNewStatusesAppend, hasMore {
|
||||
self.maxID = response.link?.maxID
|
||||
await enter(state: Idle.self)
|
||||
} else {
|
||||
await enter(state: NoMore.self)
|
||||
}
|
||||
await viewModel.dataController.setRecords(statusIDs)
|
||||
viewModel.didLoadLatest.send()
|
||||
|
||||
} catch {
|
||||
if let error = error as? Mastodon.API.Error,
|
||||
[HTTPResponseStatus.unauthorized, .notFound].contains(error.httpResponseStatus) {
|
||||
await enter(state: NoMore.self)
|
||||
} else {
|
||||
await enter(state: Fail.self)
|
||||
}
|
||||
}
|
||||
} // end Task
|
||||
} // end func
|
||||
}
|
||||
|
||||
class NoMore: DiscoveryCommunityViewModel.State {
|
||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||
switch stateClass {
|
||||
case is Reloading.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override func didEnter(from previousState: GKState?) {
|
||||
super.didEnter(from: previousState)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
//
|
||||
// DiscoveryCommunityViewModel.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK on 2022-4-29.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
import GameplayKit
|
||||
import CoreData
|
||||
import CoreDataStack
|
||||
import MastodonSDK
|
||||
import MastodonCore
|
||||
|
||||
final class DiscoveryCommunityViewModel {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
// input
|
||||
let context: AppContext
|
||||
let authContext: AuthContext
|
||||
let viewDidAppeared = PassthroughSubject<Void, Never>()
|
||||
let dataController: StatusDataController
|
||||
let listBatchFetchViewModel = ListBatchFetchViewModel()
|
||||
|
||||
// output
|
||||
var diffableDataSource: UITableViewDiffableDataSource<StatusSection, StatusItem>?
|
||||
private(set) lazy var stateMachine: GKStateMachine = {
|
||||
let stateMachine = GKStateMachine(states: [
|
||||
State.Initial(viewModel: self),
|
||||
State.Reloading(viewModel: self),
|
||||
State.Fail(viewModel: self),
|
||||
State.Idle(viewModel: self),
|
||||
State.Loading(viewModel: self),
|
||||
State.NoMore(viewModel: self),
|
||||
])
|
||||
stateMachine.enter(State.Initial.self)
|
||||
return stateMachine
|
||||
}()
|
||||
|
||||
let didLoadLatest = PassthroughSubject<Void, Never>()
|
||||
|
||||
@MainActor
|
||||
init(context: AppContext, authContext: AuthContext) {
|
||||
self.context = context
|
||||
self.authContext = authContext
|
||||
self.dataController = StatusDataController()
|
||||
// end init
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ final class DiscoveryViewModel {
|
|||
let discoveryPostsViewController: DiscoveryPostsViewController
|
||||
let discoveryHashtagsViewController: DiscoveryHashtagsViewController
|
||||
let discoveryNewsViewController: DiscoveryNewsViewController
|
||||
let discoveryCommunityViewController: DiscoveryCommunityViewController
|
||||
let discoveryForYouViewController: DiscoveryForYouViewController
|
||||
|
||||
@Published var viewControllers: [ScrollViewContainer & PageViewController]
|
||||
|
@ -55,12 +54,6 @@ final class DiscoveryViewModel {
|
|||
viewController.viewModel = DiscoveryNewsViewModel(context: context, authContext: authContext)
|
||||
return viewController
|
||||
}()
|
||||
discoveryCommunityViewController = {
|
||||
let viewController = DiscoveryCommunityViewController()
|
||||
setupDependency(viewController)
|
||||
viewController.viewModel = DiscoveryCommunityViewModel(context: context, authContext: authContext)
|
||||
return viewController
|
||||
}()
|
||||
discoveryForYouViewController = {
|
||||
let viewController = DiscoveryForYouViewController()
|
||||
setupDependency(viewController)
|
||||
|
@ -71,7 +64,6 @@ final class DiscoveryViewModel {
|
|||
discoveryPostsViewController,
|
||||
discoveryHashtagsViewController,
|
||||
discoveryNewsViewController,
|
||||
discoveryCommunityViewController,
|
||||
discoveryForYouViewController,
|
||||
]
|
||||
// end init
|
||||
|
@ -161,14 +153,6 @@ extension DiscoveryNewsViewController: PageViewController {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - PageViewController
|
||||
extension DiscoveryCommunityViewController: PageViewController {
|
||||
var tabItemTitle: String { L10n.Scene.Discovery.Tabs.community }
|
||||
var tabItem: TMBarItemable {
|
||||
return TMBarItem(title: tabItemTitle)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - PageViewController
|
||||
extension DiscoveryForYouViewController: PageViewController {
|
||||
var tabItemTitle: String { L10n.Scene.Discovery.Tabs.forYou }
|
||||
|
|
Loading…
Reference in New Issue