feat: add discovery intro banner

This commit is contained in:
CMK 2022-04-19 21:34:49 +08:00
parent 1d96609003
commit d70f734957
5 changed files with 159 additions and 1 deletions

View File

@ -499,7 +499,8 @@
"hashtags": "Hashtags",
"news": "News",
"for_you": "For You"
}
},
"intro": "These are the posts gaining traction in your corner of Mastodon."
},
"favorite": {
"title": "Your Favorites"

View File

@ -148,6 +148,7 @@
DB0618072785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */; };
DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */; };
DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; };
DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */; };
DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; };
DB0C946526A6FD4D0088FB11 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB0C946426A6FD4D0088FB11 /* AlamofireImage */; };
DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */; };
@ -870,6 +871,7 @@
DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonRegisterViewModel+Diffable.swift"; sourceTree = "<group>"; };
DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterAvatarTableViewCell.swift; sourceTree = "<group>"; };
DB084B5625CBC56C00F898ED /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = "<group>"; };
DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryIntroBannerView.swift; sourceTree = "<group>"; };
DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = "<group>"; };
DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAvatarButton.swift; sourceTree = "<group>"; };
DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListCollectionViewCell.swift; sourceTree = "<group>"; };
@ -2023,6 +2025,14 @@
path = CoreDataStack;
sourceTree = "<group>";
};
DB0A322F280EEA00001729D2 /* View */ = {
isa = PBXGroup;
children = (
DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */,
);
path = View;
sourceTree = "<group>";
};
DB0C947826A7FE950088FB11 /* Button */ = {
isa = PBXGroup;
children = (
@ -3108,6 +3118,7 @@
DBDFF1912805544800557A48 /* Discovery */ = {
isa = PBXGroup;
children = (
DB0A322F280EEA00001729D2 /* View */,
DBDFF19828055A0900557A48 /* Posts */,
DB3E6FDE2806A41200B035AE /* Hashtags */,
DB3E6FED2806D7FC00B035AE /* News */,
@ -4085,6 +4096,7 @@
DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */,
DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */,
DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */,
DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */,
2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */,
5DDDF1992617447F00311060 /* Mastodon+Entity+Tag.swift in Sources */,
5B90C45F262599800002E742 /* SettingsToggleTableViewCell.swift in Sources */,

View File

@ -8,6 +8,7 @@
import os.log
import UIKit
import Combine
import MastodonUI
final class DiscoveryPostsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController {
@ -31,6 +32,8 @@ final class DiscoveryPostsViewController: UIViewController, NeedsDependency, Med
}()
let refreshControl = UIRefreshControl()
let discoveryIntroBannerView = DiscoveryIntroBannerView()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
@ -60,6 +63,21 @@ extension DiscoveryPostsViewController {
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
discoveryIntroBannerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(discoveryIntroBannerView)
NSLayoutConstraint.activate([
discoveryIntroBannerView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
discoveryIntroBannerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
discoveryIntroBannerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
discoveryIntroBannerView.delegate = self
discoveryIntroBannerView.isHidden = UserDefaults.shared.discoveryIntroBannerNeedsHidden
UserDefaults.shared.publisher(for: \.discoveryIntroBannerNeedsHidden)
.receive(on: DispatchQueue.main)
.assign(to: \.isHidden, on: discoveryIntroBannerView)
.store(in: &disposeBag)
tableView.delegate = self
viewModel.setupDiffableDataSource(
@ -146,3 +164,10 @@ extension DiscoveryPostsViewController: ScrollViewContainer {
tableView
}
}
// MARK: - DiscoveryIntroBannerViewDelegate
extension DiscoveryPostsViewController: DiscoveryIntroBannerViewDelegate {
func discoveryIntroBannerView(_ bannerView: DiscoveryIntroBannerView, closeButtonDidPressed button: UIButton) {
UserDefaults.shared.discoveryIntroBannerNeedsHidden = true
}
}

View File

@ -0,0 +1,101 @@
//
// DiscoveryIntroBannerView.swift
// Mastodon
//
// Created by MainasuK on 2022-4-19.
//
import os.log
import UIKit
import Combine
import MastodonAsset
public protocol DiscoveryIntroBannerViewDelegate: AnyObject {
func discoveryIntroBannerView(_ bannerView: DiscoveryIntroBannerView, closeButtonDidPressed button: UIButton)
}
public final class DiscoveryIntroBannerView: UIView {
let logger = Logger(subsystem: "DiscoveryIntroBannerView", category: "View")
var _disposeBag = Set<AnyCancellable>()
public weak var delegate: DiscoveryIntroBannerViewDelegate?
let label: UILabel = {
let label = UILabel()
label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 16, weight: .regular))
label.textColor = Asset.Colors.Label.primary.color
label.text = "These are the posts gaining traction in your corner of Mastodon." // TODO: i18n
label.numberOfLines = 0
return label
}()
let closeButton: HitTestExpandedButton = {
let button = HitTestExpandedButton(type: .system)
button.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal)
button.tintColor = Asset.Colors.Label.secondary.color
return button
}()
public override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension DiscoveryIntroBannerView {
private func _init() {
preservesSuperviewLayoutMargins = true
setupAppearance(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.setupAppearance(theme: theme)
}
.store(in: &_disposeBag)
closeButton.translatesAutoresizingMaskIntoConstraints = false
addSubview(closeButton)
NSLayoutConstraint.activate([
closeButton.topAnchor.constraint(equalTo: topAnchor, constant: 16).priority(.required - 1),
layoutMarginsGuide.trailingAnchor.constraint(equalTo: closeButton.trailingAnchor),
closeButton.heightAnchor.constraint(equalToConstant: 20).priority(.required - 1),
closeButton.widthAnchor.constraint(equalToConstant: 20).priority(.required - 1),
])
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: topAnchor, constant: 16).priority(.required - 1),
label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
closeButton.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 10),
bottomAnchor.constraint(equalTo: label.bottomAnchor, constant: 16).priority(.required - 1),
])
closeButton.addTarget(self, action: #selector(DiscoveryIntroBannerView.closeButtonDidPressed(_:)), for: .touchUpInside)
}
}
extension DiscoveryIntroBannerView {
@objc private func closeButtonDidPressed(_ sender: UIButton) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
delegate?.discoveryIntroBannerView(self, closeButtonDidPressed: sender)
}
}
extension DiscoveryIntroBannerView {
private func setupAppearance(theme: Theme) {
backgroundColor = theme.systemBackgroundColor
}
}

View File

@ -0,0 +1,19 @@
//
// Preference+Discovery.swift
//
//
// Created by MainasuK on 2022-4-19.
//
import Foundation
extension UserDefaults {
@objc public dynamic var discoveryIntroBannerNeedsHidden: Bool {
get {
return bool(forKey: #function)
}
set { self[#function] = newValue }
}
}