Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Community tab into discovery scene #400

Merged
merged 3 commits into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions AppShared/AppSecret.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ import Foundation
import CryptoKit
import KeychainAccess
import Keys

enum AppName {
public static let groupID = "group.org.joinmastodon.app"
}
import MastodonCommon

public final class AppSecret {

Expand Down
340 changes: 132 additions & 208 deletions Mastodon.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1330"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1330"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1330"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>19</integer>
<integer>6</integer>
</dict>
<key>Mastodon - Release.xcscheme_^#shared#^_</key>
<dict>
Expand Down Expand Up @@ -109,7 +109,7 @@
<key>MastodonIntent.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>24</integer>
<integer>21</integer>
</dict>
<key>MastodonIntents.xcscheme_^#shared#^_</key>
<dict>
Expand All @@ -124,12 +124,12 @@
<key>NotificationService.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>22</integer>
<integer>19</integer>
</dict>
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>23</integer>
<integer>20</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
Expand Down
19 changes: 11 additions & 8 deletions Mastodon/Generated/AutoGenerateTableViewDelegate.generated.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
// Generated using Sourcery 1.6.1 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT








// sourcery:inline:UserTimelineViewController.AutoGenerateTableViewDelegate
// sourcery:inline:DiscoveryCommunityViewController.AutoGenerateTableViewDelegate

// Generated using Sourcery
// DO NOT EDIT
Expand All @@ -33,3 +26,13 @@ func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith con
}
// sourcery:end











64 changes: 64 additions & 0 deletions Mastodon/Scene/Discovery/Community/CommunityViewViewModel.swift
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)
}

}
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)
}
}
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
}
}
Loading