-
-
Notifications
You must be signed in to change notification settings - Fork 282
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #400 from mastodon/feature-local-timeline
Add Community tab into discovery scene
- Loading branch information
Showing
26 changed files
with
899 additions
and
268 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Snapshot.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
Mastodon/Scene/Discovery/Community/CommunityViewViewModel.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// | ||
// DiscoveryCommunityViewViewModel.swift | ||
// Mastodon | ||
// | ||
// Created by MainasuK on 2022-4-29. | ||
// | ||
|
||
import os.log | ||
import UIKit | ||
import Combine | ||
import GameplayKit | ||
import CoreData | ||
import CoreDataStack | ||
import MastodonSDK | ||
|
||
final class DiscoveryCommunityViewViewModel { | ||
|
||
let logger = Logger(subsystem: "DiscoveryCommunityViewViewModel", category: "ViewModel") | ||
|
||
var disposeBag = Set<AnyCancellable>() | ||
|
||
// input | ||
let context: AppContext | ||
let viewDidAppeared = PassthroughSubject<Void, Never>() | ||
let statusFetchedResultsController: StatusFetchedResultsController | ||
|
||
// 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>() | ||
|
||
init(context: AppContext) { | ||
self.context = context | ||
self.statusFetchedResultsController = StatusFetchedResultsController( | ||
managedObjectContext: context.managedObjectContext, | ||
domain: nil, | ||
additionalTweetPredicate: nil | ||
) | ||
// end init | ||
|
||
context.authenticationService.activeMastodonAuthentication | ||
.map { $0?.domain } | ||
.assign(to: \.value, on: statusFetchedResultsController.domain) | ||
.store(in: &disposeBag) | ||
|
||
} | ||
|
||
deinit { | ||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) | ||
} | ||
|
||
} |
34 changes: 34 additions & 0 deletions
34
Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// DiscoveryCommunityViewController+DataSourceProvider.swift | ||
// Mastodon | ||
// | ||
// Created by MainasuK on 2022-4-29. | ||
// | ||
|
||
import UIKit | ||
|
||
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 | ||
} | ||
} | ||
|
||
@MainActor | ||
private func indexPath(for cell: UITableViewCell) async -> IndexPath? { | ||
return tableView.indexPath(for: cell) | ||
} | ||
} |
154 changes: 154 additions & 0 deletions
154
Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// | ||
// DiscoveryCommunityViewController.swift | ||
// Mastodon | ||
// | ||
// Created by MainasuK on 2022-4-29. | ||
// | ||
|
||
import os.log | ||
import UIKit | ||
import Combine | ||
import MastodonUI | ||
|
||
// Local Timeline | ||
final class DiscoveryCommunityViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { | ||
|
||
let logger = Logger(subsystem: "DiscoveryCommunityViewController", category: "ViewController") | ||
|
||
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 = UIRefreshControl() | ||
|
||
deinit { | ||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) | ||
} | ||
|
||
} | ||
|
||
extension DiscoveryCommunityViewController { | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
|
||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor | ||
ThemeService.shared.currentTheme | ||
.receive(on: DispatchQueue.main) | ||
.sink { [weak self] theme in | ||
guard let self = self else { return } | ||
self.view.backgroundColor = theme.secondarySystemBackgroundColor | ||
} | ||
.store(in: &disposeBag) | ||
|
||
tableView.translatesAutoresizingMaskIntoConstraints = false | ||
view.addSubview(tableView) | ||
NSLayoutConstraint.activate([ | ||
tableView.topAnchor.constraint(equalTo: view.topAnchor), | ||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), | ||
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), | ||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), | ||
]) | ||
|
||
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: UIRefreshControl) { | ||
if !viewModel.stateMachine.enter(DiscoveryCommunityViewModel.State.Reloading.self) { | ||
refreshControl.endRefreshing() | ||
} | ||
} | ||
|
||
} | ||
|
||
// MARK: - UITableViewDelegate | ||
extension DiscoveryCommunityViewController: UITableViewDelegate, AutoGenerateTableViewDelegate { | ||
// sourcery:inline:CommunityViewController.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 | ||
} | ||
} |
Oops, something went wrong.