Skip to content

Commit

Permalink
Remove NavigationBarTitleView and add first draft of TimelineStatusPi…
Browse files Browse the repository at this point in the history
…ll (IOS-234)
  • Loading branch information
zeitschlag committed Apr 5, 2024
1 parent cc9faf5 commit 6af9435
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 511 deletions.
20 changes: 4 additions & 16 deletions Mastodon.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@
2D7867192625B77500211898 /* NotificationItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7867182625B77500211898 /* NotificationItem.swift */; };
2D82B9FF25E7863200E36F0F /* OnboardingViewControllerAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D82B9FE25E7863200E36F0F /* OnboardingViewControllerAppearance.swift */; };
2D82BA0525E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D82BA0425E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift */; };
2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D8434F425FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift */; };
2D8434FB25FF46B300EECE90 /* HomeTimelineNavigationBarTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D8434FA25FF46B300EECE90 /* HomeTimelineNavigationBarTitleView.swift */; };
2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D84350425FF858100EECE90 /* UIScrollView.swift */; };
2D939AB525EDD8A90076FA61 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D939AB425EDD8A90076FA61 /* String.swift */; };
2DAC9E38262FC2320062E1A6 /* SuggestionAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DAC9E37262FC2320062E1A6 /* SuggestionAccountViewController.swift */; };
Expand Down Expand Up @@ -154,6 +152,7 @@
D8318A882A4468D300C0FB73 /* NotificationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */; };
D8318A8A2A4468DC00C0FB73 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A892A4468DC00C0FB73 /* AboutViewController.swift */; };
D8363B1629469CE200A74079 /* OnboardingNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8363B1529469CE200A74079 /* OnboardingNextView.swift */; };
D84738D42BBD9ABE00ECD52B /* TimelineStatusPill.swift in Sources */ = {isa = PBXBuildFile; fileRef = D84738D32BBD9ABE00ECD52B /* TimelineStatusPill.swift */; };
D84FA0932AE6915800987F47 /* MBProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = D84FA0922AE6915800987F47 /* MBProgressHUD */; };
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */; };
D852C23E2AC5D03300309232 /* InstanceRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23D2AC5D03300309232 /* InstanceRulesViewController.swift */; };
Expand Down Expand Up @@ -715,8 +714,6 @@
2D7867182625B77500211898 /* NotificationItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationItem.swift; sourceTree = "<group>"; };
2D82B9FE25E7863200E36F0F /* OnboardingViewControllerAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewControllerAppearance.swift; sourceTree = "<group>"; };
2D82BA0425E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonResendEmailViewModelNavigationDelegateShim.swift; sourceTree = "<group>"; };
2D8434F425FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineNavigationBarTitleViewModel.swift; sourceTree = "<group>"; };
2D8434FA25FF46B300EECE90 /* HomeTimelineNavigationBarTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineNavigationBarTitleView.swift; sourceTree = "<group>"; };
2D84350425FF858100EECE90 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = "<group>"; };
2D939AB425EDD8A90076FA61 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
2DAC9E37262FC2320062E1A6 /* SuggestionAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -779,6 +776,7 @@
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsViewController.swift; sourceTree = "<group>"; };
D8318A892A4468DC00C0FB73 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
D8363B1529469CE200A74079 /* OnboardingNextView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = OnboardingNextView.swift; sourceTree = "<group>"; tabWidth = 4; };
D84738D32BBD9ABE00ECD52B /* TimelineStatusPill.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStatusPill.swift; sourceTree = "<group>"; };
D84C099D2B0F9E33009E685E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
D84C099F2B0F9E41009E685E /* Setup.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Setup.md; sourceTree = "<group>"; };
D84C09A02B0F9E41009E685E /* How-it-works.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "How-it-works.md"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1501,13 +1499,13 @@
2D38F1D325CD463600561493 /* HomeTimeline */ = {
isa = PBXGroup;
children = (
DB1F239626117C360057430E /* View */,
2D38F1D425CD465300561493 /* HomeTimelineViewController.swift */,
DB697DD8278F4CED004EF2F7 /* HomeTimelineViewController+DataSourceProvider.swift */,
2D38F1E425CD46C100561493 /* HomeTimelineViewModel.swift */,
2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */,
2D38F1EA25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift */,
2D38F1F625CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift */,
D84738D32BBD9ABE00ECD52B /* TimelineStatusPill.swift */,
);
path = HomeTimeline;
sourceTree = "<group>";
Expand Down Expand Up @@ -1983,15 +1981,6 @@
path = TableView;
sourceTree = "<group>";
};
DB1F239626117C360057430E /* View */ = {
isa = PBXGroup;
children = (
2D8434F425FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift */,
2D8434FA25FF46B300EECE90 /* HomeTimelineNavigationBarTitleView.swift */,
);
path = View;
sourceTree = "<group>";
};
DB3D0FF725BAA68500EAA174 /* Supporting Files */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3484,7 +3473,6 @@
DB0617FF27855D6C0030EE79 /* MastodonServerRulesViewModel+Diffable.swift in Sources */,
DBB5255E2611F07A002F1F29 /* ProfileViewModel.swift in Sources */,
DB0FCB982797F6BF006C02E2 /* UserTableViewCell+ViewModel.swift in Sources */,
2D8434FB25FF46B300EECE90 /* HomeTimelineNavigationBarTitleView.swift in Sources */,
DB697DD6278F4C29004EF2F7 /* DataSourceProvider.swift in Sources */,
DB0FCB8E2796C0B7006C02E2 /* TrendCollectionViewCell.swift in Sources */,
0F1E2D0B2615C39400C38565 /* DoubleTitleLabelNavigationBarTitleView.swift in Sources */,
Expand All @@ -3494,7 +3482,6 @@
DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */,
D8FAAE432AD047B200DC1832 /* AboutInstanceTableFooterView.swift in Sources */,
D808B94E296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift in Sources */,
2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift in Sources */,
D852C23E2AC5D03300309232 /* InstanceRulesViewController.swift in Sources */,
DB938F0F2624119800E5B6C1 /* ThreadViewModel+LoadThreadState.swift in Sources */,
DB6180F226391CF40018D199 /* MediaPreviewImageViewModel.swift in Sources */,
Expand Down Expand Up @@ -3763,6 +3750,7 @@
DB6B74FC272FF55800C70B6E /* UserSection.swift in Sources */,
DB0FCB862796BDA1006C02E2 /* SearchSection.swift in Sources */,
DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */,
D84738D42BBD9ABE00ECD52B /* TimelineStatusPill.swift in Sources */,
D8B5E4F42A4ED0240008970C /* NotificationSettingsViewModel.swift in Sources */,
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */,
DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */,
Expand Down
80 changes: 11 additions & 69 deletions Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
return emptyView
}()

let titleView = HomeTimelineNavigationBarTitleView()

lazy var timelineSelectorButton = {
let button = UIButton(type: .custom)
button.setAttributedTitle(
Expand Down Expand Up @@ -101,6 +99,8 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
}()

let refreshControl = RefreshControl()
let timelinePill = TimelineStatusPill()


private func generateTimeSelectorMenu() -> UIMenu {
let showFollowingAction = UIAction(title: L10n.Scene.HomeTimeline.TimelineMenu.following, image: .init(systemName: "house")) { [weak self] _ in
Expand Down Expand Up @@ -170,33 +170,6 @@ extension HomeTimelineViewController {
settingBarButtonItem.action = #selector(HomeTimelineViewController.settingBarButtonItemPressed(_:))

self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: timelineSelectorButton)

// navigationItem.titleView = titleView
// titleView.delegate = self

viewModel?.homeTimelineNavigationBarTitleViewModel.state
.removeDuplicates()
.receive(on: DispatchQueue.main)
.sink { [weak self] state in
guard let self = self else { return }
self.titleView.configure(state: state)
}
.store(in: &disposeBag)

viewModel?.homeTimelineNavigationBarTitleViewModel.state
.removeDuplicates()
.filter { $0 == .publishedButton }
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
guard let self = self else { return }
guard UserDefaults.shared.lastVersionPromptedForReview == nil else { return }
guard UserDefaults.shared.processCompletedCount > 3 else { return }
guard let windowScene = self.view.window?.windowScene else { return }
let version = UIApplication.appVersion()
UserDefaults.shared.lastVersionPromptedForReview = version
SKStoreReviewController.requestReview(in: windowScene)
}
.store(in: &disposeBag)

tableView.refreshControl = refreshControl
refreshControl.addTarget(self, action: #selector(HomeTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged)
Expand Down Expand Up @@ -326,6 +299,15 @@ extension HomeTimelineViewController {
}
.store(in: &disposeBag)

// timelinePill.translatesAutoresizingMaskIntoConstraints = false
// view.addSubview(timelinePill)
//
// // has to up updated and animated
// timelinePill.update(with: .postSent)
// NSLayoutConstraint.activate([
// timelinePill.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
// timelinePill.centerXAnchor.constraint(equalTo: view.centerXAnchor),
// ])
}

override func viewWillAppear(_ animated: Bool) {
Expand Down Expand Up @@ -480,15 +462,6 @@ extension HomeTimelineViewController {
}
// MARK: - UIScrollViewDelegate
extension HomeTimelineViewController {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
switch scrollView {
case tableView:
viewModel?.homeTimelineNavigationBarTitleViewModel.handleScrollViewDidScroll(scrollView)
default:
break
}
}

func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
switch scrollView {
case tableView:
Expand Down Expand Up @@ -644,37 +617,6 @@ extension HomeTimelineViewController: ScrollViewContainer {
// MARK: - StatusTableViewCellDelegate
extension HomeTimelineViewController: StatusTableViewCellDelegate { }

// MARK: - HomeTimelineNavigationBarTitleViewDelegate
extension HomeTimelineViewController: HomeTimelineNavigationBarTitleViewDelegate {
func homeTimelineNavigationBarTitleView(_ titleView: HomeTimelineNavigationBarTitleView, logoButtonDidPressed sender: UIButton) {
if shouldRestoreScrollPosition() {
restorePositionWhenScrollToTop()
} else {
savePositionBeforeScrollToTop()
scrollToTop(animated: true)
}
}

func homeTimelineNavigationBarTitleView(_ titleView: HomeTimelineNavigationBarTitleView, buttonDidPressed sender: UIButton) {
switch titleView.state {
case .newPostButton:
guard let diffableDataSource = viewModel?.diffableDataSource else { return }
let indexPath = IndexPath(row: 0, section: 0)
guard diffableDataSource.itemIdentifier(for: indexPath) != nil else { return }

savePositionBeforeScrollToTop()
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
case .offlineButton:
// TODO: retry
break
case .publishedButton:
break
default:
break
}
}
}

extension HomeTimelineViewController {
override var keyCommands: [UIKeyCommand]? {
return navigationKeyCommands + statusNavigationKeyCommands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,14 @@ extension HomeTimelineViewModel.LoadLatestState {
}

await enter(state: Idle.self)
viewModel.homeTimelineNavigationBarTitleViewModel.receiveLoadingStateCompletion(.finished)

// stop refresher if no new statuses
let statuses = response.value
let newStatuses = statuses.filter { status in !latestStatusIDs.contains(where: { $0 == status.reblog?.id || $0 == status.id }) }

if newStatuses.isEmpty {
viewModel.didLoadLatest.send()
} else {
if !latestStatusIDs.isEmpty {
viewModel.homeTimelineNavigationBarTitleViewModel.newPostsIncoming()
}

} else {
viewModel.dataController.records = {
var newRecords: [MastodonFeed] = newStatuses.map {
MastodonFeed.fromStatus(.fromEntity($0), kind: .home)
Expand All @@ -168,7 +163,6 @@ extension HomeTimelineViewModel.LoadLatestState {
} catch {
await enter(state: Idle.self)
viewModel.didLoadLatest.send()
viewModel.homeTimelineNavigationBarTitleViewModel.receiveLoadingStateCompletion(.failure(error))
}
} // end Task
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,9 @@ extension HomeTimelineViewModel.LoadOldestState {
} else {
await self.enter(state: Idle.self)
}

viewModel.homeTimelineNavigationBarTitleViewModel.receiveLoadingStateCompletion(.finished)


} catch {
await self.enter(state: Fail.self)
viewModel.homeTimelineNavigationBarTitleViewModel.receiveLoadingStateCompletion(.failure(error))
}
} // end Task
}
Expand Down
12 changes: 0 additions & 12 deletions Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ final class HomeTimelineViewModel: NSObject {
let context: AppContext
let authContext: AuthContext
let dataController: FeedDataController
let homeTimelineNavigationBarTitleViewModel: HomeTimelineNavigationBarTitleViewModel
let listBatchFetchViewModel = ListBatchFetchViewModel()

var presentedSuggestions = false
Expand Down Expand Up @@ -81,7 +80,6 @@ final class HomeTimelineViewModel: NSObject {
self.context = context
self.authContext = authContext
self.dataController = FeedDataController(context: context, authContext: authContext)
self.homeTimelineNavigationBarTitleViewModel = HomeTimelineNavigationBarTitleViewModel(context: context)
super.init()
self.dataController.records = (try? FileManager.default.cachedHomeTimeline(for: authContext.mastodonAuthenticationBox).map {
MastodonFeed.fromStatus($0, kind: .home)
Expand All @@ -92,16 +90,6 @@ final class HomeTimelineViewModel: NSObject {
self?.loadLatestStateMachine.enter(LoadLatestState.Loading.self)
}
.store(in: &disposeBag)

// refresh after publish post
homeTimelineNavigationBarTitleViewModel.isPublished
.delay(for: 2, scheduler: DispatchQueue.main)
.sink { [weak self] isPublished in
guard let self = self else { return }
self.homeTimelineNeedRefresh.send()
}
.store(in: &disposeBag)

self.dataController.$records
.removeDuplicates()
.receive(on: DispatchQueue.main)
Expand Down
73 changes: 73 additions & 0 deletions Mastodon/Scene/HomeTimeline/TimelineStatusPill.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright © 2024 Mastodon gGmbH. All rights reserved.

import UIKit
import MastodonAsset

class TimelineStatusPill: UIButton {

func update(with state: State) {
var configuration = UIButton.Configuration.filled()


configuration.attributedTitle = AttributedString(
state.title, attributes: AttributeContainer(
[
.font: UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .bold)),
.foregroundColor: UIColor.white
]
))

let image = state.image?
.withConfiguration(UIImage.SymbolConfiguration(paletteColors: [.white]))
.withConfiguration(UIImage.SymbolConfiguration(textStyle: .subheadline))
.withConfiguration(UIImage.SymbolConfiguration(pointSize: 12, weight: .bold, scale: .medium))

configuration.image = image
configuration.imagePadding = 8
configuration.baseBackgroundColor = state.backgroundColor
configuration.cornerStyle = .capsule

self.configuration = configuration
}

public enum State {
case newPosts
case postSent
case offline

var image: UIImage? {
switch self {
case .newPosts:
return UIImage(systemName: "chevron.up")
case .postSent:
return UIImage(systemName: "checkmark")
case .offline:
return UIImage(systemName: "bolt.horizontal.fill")
}
}

var backgroundColor: UIColor {
switch self {
case .newPosts:
return Asset.Colors.Brand.blurple.color
case .postSent:
return .systemGreen
case .offline:
return .systemGray
}
}

var title: String {
//TODO: Localization
switch self {
case .newPosts:
return "New Posts"
case .postSent:
return "Post Sent"
case .offline:
return "Offline"
}
}
}

}
Loading

0 comments on commit 6af9435

Please sign in to comment.