chore: add publishing state in navigationBar

This commit is contained in:
sunxiaojian 2021-03-16 11:45:30 +08:00
parent 50a30cd18e
commit b60fe36b25
5 changed files with 117 additions and 7 deletions

View File

@ -49,6 +49,7 @@
2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D42FF8E25C8228A004A627A /* UIButton.swift */; };
2D45E5BF25C9549700A6D639 /* PublicTimelineViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D45E5BE25C9549700A6D639 /* PublicTimelineViewModel+State.swift */; };
2D46975E25C2A54100CF4AA9 /* NSLayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */; };
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D571B2E26004EC000540450 /* NavigationBarProgressView.swift */; };
2D59819B25E4A581000FB903 /* MastodonConfirmEmailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D59819A25E4A581000FB903 /* MastodonConfirmEmailViewController.swift */; };
2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5981A025E4A593000FB903 /* MastodonConfirmEmailViewModel.swift */; };
2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */ = {isa = PBXBuildFile; productRef = 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */; };
@ -300,6 +301,7 @@
2D42FF8E25C8228A004A627A /* UIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = "<group>"; };
2D45E5BE25C9549700A6D639 /* PublicTimelineViewModel+State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewModel+State.swift"; sourceTree = "<group>"; };
2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraint.swift; sourceTree = "<group>"; };
2D571B2E26004EC000540450 /* NavigationBarProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarProgressView.swift; sourceTree = "<group>"; };
2D59819A25E4A581000FB903 /* MastodonConfirmEmailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonConfirmEmailViewController.swift; sourceTree = "<group>"; };
2D5981A025E4A593000FB903 /* MastodonConfirmEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonConfirmEmailViewModel.swift; sourceTree = "<group>"; };
2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlContainableScrollViews.swift; sourceTree = "<group>"; };
@ -593,6 +595,7 @@
children = (
2D152A8B25C295CC009AA50C /* StatusView.swift */,
2D694A7325F9EB4E0038ADDC /* ContentWarningOverlayView.swift */,
2D571B2E26004EC000540450 /* NavigationBarProgressView.swift */,
);
path = Content;
sourceTree = "<group>";
@ -1605,6 +1608,7 @@
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */,
DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */,
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */,
0FAA101225E105390017CCDE /* PrimaryActionButton.swift in Sources */,
DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */,
DB92CF7225E7BB98002C1017 /* PollOptionTableViewCell.swift in Sources */,

View File

@ -9,20 +9,25 @@ import Combine
import Foundation
import UIKit
final class HomeTimelineNavigationBarState {
static let errorCountMax: Int = 3
var disposeBag = Set<AnyCancellable>()
var errorCountDownDispose: AnyCancellable?
var timerDispose: AnyCancellable?
var networkErrorCountSubject = PassthroughSubject<Bool, Never>()
var titleViewBeforePublishing: UIView? // used for restore titleView after published
var newTopContent = CurrentValueSubject<Bool, Never>(false)
var newBottomContent = CurrentValueSubject<Bool, Never>(false)
var hasContentBeforeFetching: Bool = true
weak var viewController: HomeTimelineViewController?
let timestampUpdatePublisher = Timer.publish(every: NavigationBarProgressView.progressAnimationDuration, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
init() {
reCountdown()
subscribeNewContent()
@ -40,15 +45,42 @@ extension HomeTimelineNavigationBarState {
}
func showPublishingNewPostInNavigationBar() {
titleViewBeforePublishing = viewController?.navigationItem.titleView
let progressView = HomeTimelineNavigationBarView.progressView
if let navigationBar = viewController?.navigationBar(), progressView.superview == nil {
navigationBar.addSubview(progressView)
NSLayoutConstraint.activate([
progressView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor),
progressView.leadingAnchor.constraint(equalTo: navigationBar.leadingAnchor),
progressView.trailingAnchor.constraint(equalTo: navigationBar.trailingAnchor),
progressView.heightAnchor.constraint(equalToConstant: 3)
])
}
progressView.layoutIfNeeded()
progressView.progress = 0
viewController?.navigationItem.titleView = HomeTimelineNavigationBarView.publishingLabel
var times: Int = 0
timerDispose = timestampUpdatePublisher
.map { _ in
times += 1
return Double(times)
}
.scan(0) { value,count in
value + 1 / pow(Double(2), count)
}
.receive(on: DispatchQueue.main)
.sink { value in
print(value)
progressView.progress = CGFloat(value)
}
}
func showPublishedInNavigationBar() {
timerDispose = nil
HomeTimelineNavigationBarView.progressView.removeFromSuperview()
viewController?.navigationItem.titleView = HomeTimelineNavigationBarView.publishedView
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
if let titleView = self.titleViewBeforePublishing, let navigationItem = self.viewController?.navigationItem {
navigationItem.titleView = titleView
}
self.showMastodonLogoInNavigationBar()
}
}
@ -60,7 +92,10 @@ extension HomeTimelineNavigationBarState {
extension HomeTimelineNavigationBarState {
func handleScrollViewDidScroll(_ scrollView: UIScrollView) {
let contentOffsetY = scrollView.contentOffset.y
print(contentOffsetY)
let isShowingNewPostsNew = viewController?.navigationItem.titleView === HomeTimelineNavigationBarView.newPostsView
if !isShowingNewPostsNew {
return
}
let isTop = contentOffsetY < -scrollView.contentInset.top
if isTop {
newTopContent.value = false
@ -138,6 +173,7 @@ extension HomeTimelineNavigationBarState {
networkErrorCountSubject.send(false)
case .finished:
reCountdown()
showPublishingNewPostInNavigationBar()
}
}
}

View File

@ -36,6 +36,19 @@ final class HomeTimelineNavigationBarView {
return view
}()
static var progressView: NavigationBarProgressView = {
let view = NavigationBarProgressView()
return view
}()
static var publishingLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .black
label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold))
label.text = L10n.Scene.HomeTimeline.NavigationBarState.publishing
return label
}()
static func addLabelToView(label: UILabel,view:UIView) {
view.addSubview(label)

View File

@ -58,6 +58,7 @@ extension HomeTimelineViewModel.LoadOldestState {
.delay(for: .seconds(1), scheduler: DispatchQueue.main)
.receive(on: DispatchQueue.main)
.sink { completion in
viewModel.homeTimelineNavigationBarState.receiveCompletion(completion: completion)
switch completion {
case .failure(let error):
os_log("%{public}s[%{public}ld], %{public}s: fetch toots failed. %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)

View File

@ -0,0 +1,56 @@
//
// NavigationBarProgressView.swift
// Mastodon
//
// Created by sxiaojian on 2021/3/16.
//
import UIKit
class NavigationBarProgressView: UIView {
static let progressAnimationDuration: TimeInterval = 0.3
let sliderView: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.buttonDefault.color
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
var sliderTrailingAnchor: NSLayoutConstraint!
var progress: CGFloat = 0 {
willSet(value) {
sliderTrailingAnchor.constant = (1 - progress) * bounds.width
UIView.animate(withDuration: NavigationBarProgressView.progressAnimationDuration) {
self.setNeedsLayout()
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension NavigationBarProgressView {
func _init() {
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = .clear
addSubview(sliderView)
sliderTrailingAnchor = trailingAnchor.constraint(equalTo: sliderView.trailingAnchor)
NSLayoutConstraint.activate([
sliderView.topAnchor.constraint(equalTo: topAnchor),
sliderView.leadingAnchor.constraint(equalTo: leadingAnchor),
sliderView.bottomAnchor.constraint(equalTo: bottomAnchor),
sliderTrailingAnchor
])
}
}