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

IOS-174: Don't persist followers #1137

Merged
merged 8 commits into from
Nov 10, 2023
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
4 changes: 0 additions & 4 deletions Mastodon.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@
DB6180FA26391F2E0018D199 /* MediaPreviewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6180F926391F2E0018D199 /* MediaPreviewViewModel.swift */; };
DB63F7452799056400455B82 /* HashtagTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63F7442799056400455B82 /* HashtagTableViewCell.swift */; };
DB63F74727990B0600455B82 /* DataSourceFacade+Hashtag.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63F74627990B0600455B82 /* DataSourceFacade+Hashtag.swift */; };
DB63F7492799126300455B82 /* FollowerListViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63F7482799126300455B82 /* FollowerListViewController+DataSourceProvider.swift */; };
DB63F74D27993F5B00455B82 /* SearchHistoryUserCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63F74C27993F5B00455B82 /* SearchHistoryUserCollectionViewCell.swift */; };
DB63F74F2799405600455B82 /* SearchHistoryViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63F74E2799405600455B82 /* SearchHistoryViewModel+Diffable.swift */; };
DB63F752279944AA00455B82 /* SearchHistorySectionHeaderCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB63F751279944AA00455B82 /* SearchHistorySectionHeaderCollectionReusableView.swift */; };
Expand Down Expand Up @@ -1021,7 +1020,6 @@
DB6180F926391F2E0018D199 /* MediaPreviewViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewViewModel.swift; sourceTree = "<group>"; };
DB63F7442799056400455B82 /* HashtagTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTableViewCell.swift; sourceTree = "<group>"; };
DB63F74627990B0600455B82 /* DataSourceFacade+Hashtag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+Hashtag.swift"; sourceTree = "<group>"; };
DB63F7482799126300455B82 /* FollowerListViewController+DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowerListViewController+DataSourceProvider.swift"; sourceTree = "<group>"; };
DB63F74C27993F5B00455B82 /* SearchHistoryUserCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryUserCollectionViewCell.swift; sourceTree = "<group>"; };
DB63F74E2799405600455B82 /* SearchHistoryViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SearchHistoryViewModel+Diffable.swift"; sourceTree = "<group>"; };
DB63F751279944AA00455B82 /* SearchHistorySectionHeaderCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistorySectionHeaderCollectionReusableView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2494,7 +2492,6 @@
isa = PBXGroup;
children = (
DB6B74EE272FB55000C70B6E /* FollowerListViewController.swift */,
DB63F7482799126300455B82 /* FollowerListViewController+DataSourceProvider.swift */,
DB6B74F1272FB67600C70B6E /* FollowerListViewModel.swift */,
DB6B74F3272FBAE700C70B6E /* FollowerListViewModel+Diffable.swift */,
DB6B74F5272FBCDB00C70B6E /* FollowerListViewModel+State.swift */,
Expand Down Expand Up @@ -3738,7 +3735,6 @@
DBA5E7AB263BD3F5004598BB /* TimelineTableViewCellContextMenuConfiguration.swift in Sources */,
DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */,
2AE244482927831100BDBF7C /* UIImage+SFSymbols.swift in Sources */,
DB63F7492799126300455B82 /* FollowerListViewController+DataSourceProvider.swift in Sources */,
2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */,
2DAC9E38262FC2320062E1A6 /* SuggestionAccountViewController.swift in Sources */,
DB6180E02639194B0018D199 /* MediaPreviewPagingViewController.swift in Sources */,
Expand Down
67 changes: 29 additions & 38 deletions Mastodon/Coordinator/SceneCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -222,43 +222,35 @@ extension SceneCoordinator {

func setup() {
let rootViewController: UIViewController

let _authentication = AuthenticationServiceProvider.shared.authenticationSortedByActivation().first
let _authContext = _authentication.flatMap { AuthContext(authentication: $0) }
self.authContext = _authContext

switch UIDevice.current.userInterfaceIdiom {
case .phone:
let viewController = MainTabBarController(context: appContext, coordinator: self, authContext: _authContext)
self.splitViewController = nil
self.tabBarController = viewController
rootViewController = viewController
default:
let splitViewController = RootSplitViewController(context: appContext, coordinator: self, authContext: _authContext)
self.splitViewController = splitViewController
self.tabBarController = splitViewController.contentSplitViewController.mainTabBarController
rootViewController = splitViewController
}

do {
let _authentication = AuthenticationServiceProvider.shared.authenticationSortedByActivation().first
let _authContext = _authentication.flatMap { AuthContext(authentication: $0) }
self.authContext = _authContext

switch UIDevice.current.userInterfaceIdiom {
case .phone:
let viewController = MainTabBarController(context: appContext, coordinator: self, authContext: _authContext)
self.splitViewController = nil
self.tabBarController = viewController
rootViewController = viewController
default:
let splitViewController = RootSplitViewController(context: appContext, coordinator: self, authContext: _authContext)
self.splitViewController = splitViewController
self.tabBarController = splitViewController.contentSplitViewController.mainTabBarController
rootViewController = splitViewController
}
sceneDelegate.window?.rootViewController = rootViewController // base: main
self.rootViewController = rootViewController

if _authContext == nil { // entry #1: welcome
DispatchQueue.main.async {
_ = self.present(
scene: .welcome,
from: self.sceneDelegate.window?.rootViewController,
transition: .modal(animated: true, completion: nil)
)
}
sceneDelegate.window?.rootViewController = rootViewController // base: main
self.rootViewController = rootViewController

if _authContext == nil { // entry #1: welcome
DispatchQueue.main.async {
_ = self.present(
scene: .welcome,
from: self.sceneDelegate.window?.rootViewController,
transition: .modal(animated: true, completion: nil)
)
}

} catch {
assertionFailure(error.localizedDescription)
Task {
try? await Task.sleep(nanoseconds: .second * 2)
setup() // entry #2: retry
} // end Task
}
}

Expand Down Expand Up @@ -464,9 +456,8 @@ private extension SceneCoordinator {
_viewController.viewModel = viewModel
viewController = _viewController
case .follower(let viewModel):
let _viewController = FollowerListViewController()
_viewController.viewModel = viewModel
viewController = _viewController
let followerListViewController = FollowerListViewController(viewModel: viewModel, coordinator: self, context: appContext)
viewController = followerListViewController
case .following(let viewModel):
let followingListViewController = FollowingListViewController(viewModel: viewModel, coordinator: self, context: appContext)
viewController = followingListViewController
Expand Down
7 changes: 4 additions & 3 deletions Mastodon/Protocol/Provider/DataSourceFacade+Translate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ private extension DataSourceFacade {
authenticationBox: provider.authContext.mastodonAuthenticationBox
).value

guard let content = value.content else {
if value.content != nil {
return value
} else {
return nil
}

return value

} catch {
throw TranslationFailure.emptyOrInvalidResponse
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ extension MastodonRegisterViewController {
return "en"
}
let fallbackLanguageCode: String = {
let code = Locale.current.languageCode ?? "en"
let code = Locale.current.language.languageCode?.identifier ?? "en"
guard localCode[code] != nil else { return "en" }
return code
}()
Expand All @@ -161,7 +161,7 @@ extension MastodonRegisterViewController {
}
// prepare languageCode and validate then return fallback if needs
let local = Locale(identifier: identifier)
guard let languageCode = local.languageCode,
guard let languageCode = local.language.languageCode?.identifier,
localCode[languageCode] != nil
else {
return fallbackLanguageCode
Expand All @@ -170,10 +170,10 @@ extension MastodonRegisterViewController {
let extendCodes: [String] = {
let locales = Locale.preferredLanguages.map { Locale(identifier: $0) }
return locales.compactMap { locale in
guard let languageCode = locale.languageCode,
let regionCode = locale.regionCode
guard let languageCode = locale.language.languageCode?.identifier,
let regionIdentifier = locale.region?.identifier
else { return nil }
return languageCode + "-" + regionCode
return languageCode + "-" + regionIdentifier
}
}()
let _firstMatchExtendCode = extendCodes.first { code in
Expand Down

This file was deleted.

116 changes: 94 additions & 22 deletions Mastodon/Scene/Profile/Follower/FollowerListViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,67 @@ import Combine
import MastodonCore
import MastodonUI
import MastodonLocalization
import CoreDataStack

final class FollowerListViewController: UIViewController, NeedsDependency {

weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
weak var context: AppContext!
weak var coordinator: SceneCoordinator!

var disposeBag = Set<AnyCancellable>()
var viewModel: FollowerListViewModel!
var viewModel: FollowerListViewModel

lazy var tableView: UITableView = {
let tableView = UITableView()
let tableView: UITableView
let refreshControl: UIRefreshControl

init(viewModel: FollowerListViewModel, coordinator: SceneCoordinator, context: AppContext) {

self.context = context
self.coordinator = coordinator
self.viewModel = viewModel

tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(UserTableViewCell.self, forCellReuseIdentifier: String(describing: UserTableViewCell.self))
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
tableView.register(TimelineFooterTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineFooterTableViewCell.self))
tableView.rowHeight = UITableView.automaticDimension
tableView.separatorStyle = .none
tableView.backgroundColor = .clear
return tableView
}()



refreshControl = UIRefreshControl()
tableView.refreshControl = refreshControl

super.init(nibName: nil, bundle: nil)

title = L10n.Scene.Follower.title

view.backgroundColor = .secondarySystemBackground

view.addSubview(tableView)
tableView.pinToParent()
tableView.delegate = self
tableView.refreshControl?.addTarget(self, action: #selector(FollowerListViewController.refresh(_:)), for: .valueChanged)

viewModel.tableView = tableView

refreshControl.addTarget(self, action: #selector(FollowerListViewController.refresh(_:)), for: .valueChanged)
}

required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

extension FollowerListViewController {

override func viewDidLoad() {
super.viewDidLoad()

title = L10n.Scene.Follower.title

view.backgroundColor = .secondarySystemBackground

tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
tableView.pinToParent()

tableView.delegate = self
viewModel.setupDiffableDataSource(
tableView: tableView,
userTableViewCellDelegate: self
)

// setup batch fetch
viewModel.listBatchFetchViewModel.setup(scrollView: tableView)
viewModel.listBatchFetchViewModel.shouldFetch
viewModel.shouldFetch
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
guard let self = self else { return }
Expand All @@ -75,14 +90,22 @@ extension FollowerListViewController {
self.viewModel.stateMachine.enter(FollowerListViewModel.State.Reloading.self)
}
.store(in: &disposeBag)

tableView.refreshControl = UIRefreshControl()
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)

tableView.deselectRow(with: transitionCoordinator, animated: animated)
}


//MARK: - Actions

@objc
func refresh(_ sender: UIRefreshControl) {
viewModel.stateMachine.enter(FollowerListViewModel.State.Reloading.self)
}
}

// MARK: - AuthContextProvider
Expand All @@ -107,3 +130,52 @@ extension FollowerListViewController: UITableViewDelegate, AutoGenerateTableView

// MARK: - UserTableViewCellDelegate
extension FollowerListViewController: UserTableViewCellDelegate {}


// MARK: - DataSourceProvider
extension FollowerListViewController: 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 .account(let account, let relationship):
return .account(account: account, relationship: relationship)
default:
return nil
}
}

@MainActor
private func indexPath(for cell: UITableViewCell) async -> IndexPath? {
return tableView.indexPath(for: cell)
}
}

//MARK: - UIScrollViewDelegate

extension FollowerListViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {

if scrollView.isDragging || scrollView.isTracking { return }

let frame = scrollView.frame
let contentOffset = scrollView.contentOffset
let contentSize = scrollView.contentSize

let visibleBottomY = contentOffset.y + frame.height
let offset = 2 * frame.height
let fetchThrottleOffsetY = contentSize.height - offset

if visibleBottomY > fetchThrottleOffsetY {
viewModel.shouldFetch.send()
}
}
}
Loading