mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2025-01-25 13:38:43 +01:00
commit
30618dd687
@ -55,7 +55,6 @@
|
||||
2D34D9DB261494120081BFC0 /* APIService+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9DA261494120081BFC0 /* APIService+Search.swift */; };
|
||||
2D34D9E226149C920081BFC0 /* SearchRecommendTagsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9E126149C920081BFC0 /* SearchRecommendTagsCollectionViewCell.swift */; };
|
||||
2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D35237926256D920031AF25 /* NotificationSection.swift */; };
|
||||
2D35238126256F690031AF25 /* NotificationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D35238026256F690031AF25 /* NotificationTableViewCell.swift */; };
|
||||
2D364F7225E66D7500204FDC /* MastodonResendEmailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D364F7125E66D7500204FDC /* MastodonResendEmailViewController.swift */; };
|
||||
2D364F7825E66D8300204FDC /* MastodonResendEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D364F7725E66D8300204FDC /* MastodonResendEmailViewModel.swift */; };
|
||||
2D38F1C625CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38F1C525CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift */; };
|
||||
@ -243,6 +242,7 @@
|
||||
DB427DF825BAA00100D1B89D /* MastodonUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DF725BAA00100D1B89D /* MastodonUITests.swift */; };
|
||||
DB44384F25E8C1FA008912A2 /* CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB44384E25E8C1FA008912A2 /* CALayer.swift */; };
|
||||
DB443CD22694326A00159B29 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DB443CD0269415D200159B29 /* Localizable.stringsdict */; };
|
||||
DB443CD42694627B00159B29 /* AppearanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB443CD32694627B00159B29 /* AppearanceView.swift */; };
|
||||
DB44767B260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB44767A260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift */; };
|
||||
DB447681260B3ED600B66B82 /* CustomEmojiPickerSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB447680260B3ED600B66B82 /* CustomEmojiPickerSection.swift */; };
|
||||
DB44768B260B3F2100B66B82 /* CustomEmojiPickerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB44768A260B3F2100B66B82 /* CustomEmojiPickerItem.swift */; };
|
||||
@ -666,7 +666,6 @@
|
||||
2D34D9DA261494120081BFC0 /* APIService+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Search.swift"; sourceTree = "<group>"; };
|
||||
2D34D9E126149C920081BFC0 /* SearchRecommendTagsCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchRecommendTagsCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
2D35237926256D920031AF25 /* NotificationSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSection.swift; sourceTree = "<group>"; };
|
||||
2D35238026256F690031AF25 /* NotificationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationTableViewCell.swift; sourceTree = "<group>"; };
|
||||
2D364F7125E66D7500204FDC /* MastodonResendEmailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonResendEmailViewController.swift; sourceTree = "<group>"; };
|
||||
2D364F7725E66D8300204FDC /* MastodonResendEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonResendEmailViewModel.swift; sourceTree = "<group>"; };
|
||||
2D38F1C525CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentOffsetAdjustableTimelineViewControllerDelegate.swift; sourceTree = "<group>"; };
|
||||
@ -878,6 +877,7 @@
|
||||
DB44384E25E8C1FA008912A2 /* CALayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CALayer.swift; sourceTree = "<group>"; };
|
||||
DB443CCF269415D200159B29 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
DB443CD1269415D800159B29 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ar; path = ar.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
DB443CD32694627B00159B29 /* AppearanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceView.swift; sourceTree = "<group>"; };
|
||||
DB44767A260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomEmojiPickerInputView.swift; sourceTree = "<group>"; };
|
||||
DB447680260B3ED600B66B82 /* CustomEmojiPickerSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomEmojiPickerSection.swift; sourceTree = "<group>"; };
|
||||
DB44768A260B3F2100B66B82 /* CustomEmojiPickerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomEmojiPickerItem.swift; sourceTree = "<group>"; };
|
||||
@ -1362,7 +1362,6 @@
|
||||
2D35237F26256F470031AF25 /* TableViewCell */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2D35238026256F690031AF25 /* NotificationTableViewCell.swift */,
|
||||
2D24E11C2626D8B100A59D4F /* NotificationStatusTableViewCell.swift */,
|
||||
);
|
||||
path = TableViewCell;
|
||||
@ -1725,6 +1724,7 @@
|
||||
children = (
|
||||
5B90C458262599800002E742 /* Cell */,
|
||||
5B90C45C262599800002E742 /* SettingsSectionHeader.swift */,
|
||||
DB443CD32694627B00159B29 /* AppearanceView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -3203,6 +3203,7 @@
|
||||
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */,
|
||||
DBD376AA2692EA4F007FEC24 /* Theme.swift in Sources */,
|
||||
0FAA101225E105390017CCDE /* PrimaryActionButton.swift in Sources */,
|
||||
DB443CD42694627B00159B29 /* AppearanceView.swift in Sources */,
|
||||
DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */,
|
||||
DB92CF7225E7BB98002C1017 /* PollOptionTableViewCell.swift in Sources */,
|
||||
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */,
|
||||
@ -3278,7 +3279,6 @@
|
||||
DBF9814A265E24F500E4BA07 /* ProfileFieldCollectionViewHeaderFooterView.swift in Sources */,
|
||||
2D939AB525EDD8A90076FA61 /* String.swift in Sources */,
|
||||
DB4481B925EE289600BEFB67 /* UITableView.swift in Sources */,
|
||||
2D35238126256F690031AF25 /* NotificationTableViewCell.swift in Sources */,
|
||||
DBE3CDBB261C427900430CC6 /* TimelineHeaderTableViewCell.swift in Sources */,
|
||||
DBCBCBFF2680AE98000F5B51 /* AsyncHomeTimelineViewModel.swift in Sources */,
|
||||
0FAA101C25E10E760017CCDE /* UIFont.swift in Sources */,
|
||||
@ -4829,7 +4829,7 @@
|
||||
repositoryURL = "https://github.com/TwidereProject/MetaTextView.git";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 1.2.4;
|
||||
version = 1.2.5;
|
||||
};
|
||||
};
|
||||
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = {
|
||||
|
@ -12,7 +12,7 @@
|
||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>20</integer>
|
||||
<integer>21</integer>
|
||||
</dict>
|
||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
@ -37,7 +37,7 @@
|
||||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>21</integer>
|
||||
<integer>20</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
@ -114,8 +114,8 @@
|
||||
"repositoryURL": "https://github.com/TwidereProject/MetaTextView.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "28e53130d16f12e0eeb479d83b77a0a718ef2088",
|
||||
"version": "1.2.4"
|
||||
"revision": "9ba4027ed0a88185ce95bb1773620c2ceaa9f3bb",
|
||||
"version": "1.2.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -46,10 +46,6 @@ extension NotificationSection {
|
||||
),
|
||||
into: cell.avatarImageView
|
||||
)
|
||||
cell.avatarImageView.gesture().sink { [weak cell] _ in
|
||||
cell?.delegate?.userAvatarDidPressed(notification: notification)
|
||||
}
|
||||
.store(in: &cell.disposeBag)
|
||||
cell.actionImageView.image = UIImage(
|
||||
systemName: notification.notificationType.actionImageName,
|
||||
withConfiguration: UIImage.SymbolConfiguration(
|
||||
|
@ -144,13 +144,12 @@ extension ComposeViewController {
|
||||
self.title = title
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
|
||||
self.setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.view.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
self.tableView.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
navigationItem.leftBarButtonItem = cancelBarButtonItem
|
||||
@ -607,6 +606,11 @@ extension ComposeViewController {
|
||||
// })
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
tableView.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewController {
|
||||
@ -809,7 +813,11 @@ extension ComposeViewController: ComposeToolbarViewDelegate {
|
||||
}
|
||||
|
||||
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: UIButton) {
|
||||
// toggle poll composing state
|
||||
viewModel.isPollComposing.value.toggle()
|
||||
|
||||
// cancel custom picker input
|
||||
viewModel.isCustomEmojiComposing.value = false
|
||||
|
||||
// setup initial poll option if needs
|
||||
if viewModel.isPollComposing.value, viewModel.pollOptionAttributes.value.isEmpty {
|
||||
@ -831,6 +839,9 @@ extension ComposeViewController: ComposeToolbarViewDelegate {
|
||||
}
|
||||
|
||||
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) {
|
||||
// cancel custom picker input
|
||||
viewModel.isCustomEmojiComposing.value = false
|
||||
|
||||
// restore first responder for text editor when content warning dismiss
|
||||
if viewModel.isContentWarningComposing.value {
|
||||
if contentWarningEditorTextView()?.isFirstResponder == true {
|
||||
@ -860,20 +871,45 @@ extension ComposeViewController {
|
||||
|
||||
let repliedToCellFrame = viewModel.repliedToCellFrame.value
|
||||
guard repliedToCellFrame != .zero else { return }
|
||||
let throttle = viewModel.repliedToCellFrame.value.height - scrollView.adjustedContentInset.top
|
||||
// print("\(throttle) - \(scrollView.contentOffset.y)")
|
||||
|
||||
// try to find some patterns:
|
||||
// print("""
|
||||
// repliedToCellFrame: \(viewModel.repliedToCellFrame.value.height)
|
||||
// scrollView.contentOffset.y: \(scrollView.contentOffset.y)
|
||||
// scrollView.contentSize.height: \(scrollView.contentSize.height)
|
||||
// scrollView.frame: \(scrollView.frame)
|
||||
// scrollView.adjustedContentInset.top: \(scrollView.adjustedContentInset.top)
|
||||
// scrollView.adjustedContentInset.bottom: \(scrollView.adjustedContentInset.bottom)
|
||||
// """)
|
||||
|
||||
switch viewModel.collectionViewState.value {
|
||||
case .fold:
|
||||
if scrollView.contentOffset.y < throttle {
|
||||
os_log("%{public}s[%{public}ld], %{public}s: fold", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
guard velocity.y < 0 else { return }
|
||||
let offsetY = scrollView.contentOffset.y + scrollView.adjustedContentInset.top
|
||||
if offsetY < -44 {
|
||||
tableView.contentInset.top = 0
|
||||
targetContentOffset.pointee = CGPoint(x: 0, y: -scrollView.adjustedContentInset.top)
|
||||
viewModel.collectionViewState.value = .expand
|
||||
}
|
||||
os_log("%{public}s[%{public}ld], %{public}s: fold", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
|
||||
case .expand:
|
||||
if scrollView.contentOffset.y > -44 {
|
||||
os_log("%{public}s[%{public}ld], %{public}s: expand", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
guard velocity.y > 0 else { return }
|
||||
// check if top across
|
||||
let topOffset = (scrollView.contentOffset.y + scrollView.adjustedContentInset.top) - repliedToCellFrame.height
|
||||
|
||||
// check if bottom bounce
|
||||
let bottomOffsetY = scrollView.contentOffset.y + (scrollView.frame.height - scrollView.adjustedContentInset.bottom)
|
||||
let bottomOffset = bottomOffsetY - scrollView.contentSize.height
|
||||
|
||||
if topOffset > 44 {
|
||||
// do not interrupt user scrolling
|
||||
viewModel.collectionViewState.value = .fold
|
||||
} else if bottomOffset > 44 {
|
||||
tableView.contentInset.top = -repliedToCellFrame.height
|
||||
targetContentOffset.pointee = CGPoint(x: 0, y: -repliedToCellFrame.height)
|
||||
viewModel.collectionViewState.value = .fold
|
||||
os_log("%{public}s[%{public}ld], %{public}s: expand", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -910,7 +946,8 @@ extension ComposeViewController: UICollectionViewDelegate {
|
||||
extension ComposeViewController: UIAdaptivePresentationControllerDelegate {
|
||||
|
||||
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
|
||||
return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic
|
||||
return .fullScreen
|
||||
//return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic
|
||||
}
|
||||
|
||||
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
|
||||
|
@ -253,6 +253,8 @@ extension ComposeViewModel: UITableViewDataSource {
|
||||
cell.statusContentWarningEditorView.alpha = 0
|
||||
UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseOut]) {
|
||||
cell.statusContentWarningEditorView.alpha = 1
|
||||
tableView.beginUpdates()
|
||||
tableView.endUpdates()
|
||||
} completion: { _ in
|
||||
// do nothing
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ final class ComposeViewModel: NSObject {
|
||||
let selectedStatusVisibility: CurrentValueSubject<ComposeToolbarView.VisibilitySelectionType, Never>
|
||||
let activeAuthentication: CurrentValueSubject<MastodonAuthentication?, Never>
|
||||
let activeAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
|
||||
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make intial event emit
|
||||
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make initial event emit
|
||||
let repliedToCellFrame = CurrentValueSubject<CGRect, Never>(.zero)
|
||||
let autoCompleteRetryLayoutTimes = CurrentValueSubject<Int, Never>(0)
|
||||
let autoCompleteInfo = CurrentValueSubject<ComposeViewController.AutoCompleteInfo?, Never>(nil)
|
||||
|
@ -13,7 +13,7 @@ final class StatusContentWarningEditorView: UIView {
|
||||
// default hidden
|
||||
let containerBackgroundView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
return view
|
||||
}()
|
||||
|
||||
@ -57,29 +57,43 @@ extension StatusContentWarningEditorView {
|
||||
containerBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 1024),
|
||||
containerBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
|
||||
iconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(iconImageView)
|
||||
|
||||
let containerStackView = UIStackView()
|
||||
containerStackView.axis = .horizontal
|
||||
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(containerStackView)
|
||||
NSLayoutConstraint.activate([
|
||||
iconImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar
|
||||
])
|
||||
iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal)
|
||||
|
||||
textView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(textView)
|
||||
NSLayoutConstraint.activate([
|
||||
textView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
textView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 6).priority(.required - 1),
|
||||
textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset
|
||||
textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
bottomAnchor.constraint(greaterThanOrEqualTo: textView.bottomAnchor, constant: 6).priority(.required - 1),
|
||||
//textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
|
||||
containerStackView.topAnchor.constraint(equalTo: topAnchor, constant: 6),
|
||||
containerStackView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
containerStackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 6),
|
||||
])
|
||||
|
||||
textView.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
containerStackView.addArrangedSubview(iconImageView)
|
||||
iconImageView.setContentHuggingPriority(.required - 1, for: .horizontal)
|
||||
containerStackView.addArrangedSubview(textView)
|
||||
|
||||
// iconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// addSubview(iconImageView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
// iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar
|
||||
// ])
|
||||
// iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal)
|
||||
//
|
||||
// textView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// addSubview(textView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// textView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
// textView.topAnchor.constraint(equalTo: topAnchor, constant: 6),
|
||||
// textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset
|
||||
// textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
// bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: 6),
|
||||
// textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
|
||||
// ])
|
||||
//
|
||||
// textView.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
// textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,8 @@ extension HashtagTimelineViewController {
|
||||
title = "#\(viewModel.hashtag)"
|
||||
titleView.update(title: viewModel.hashtag, subtitle: nil, emojiDict: [:])
|
||||
navigationItem.titleView = titleView
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
@ -80,8 +80,8 @@ extension HomeTimelineViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
title = L10n.Scene.HomeTimeline.title
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
@ -12,6 +12,7 @@ import GameplayKit
|
||||
import MastodonSDK
|
||||
import OSLog
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
import Meta
|
||||
import MetaTextView
|
||||
|
||||
@ -47,7 +48,8 @@ final class NotificationViewController: UIViewController, NeedsDependency {
|
||||
extension NotificationViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
@ -277,6 +279,35 @@ extension NotificationViewController: ContentOffsetAdjustableTimelineViewControl
|
||||
// MARK: - NotificationTableViewCellDelegate
|
||||
extension NotificationViewController: NotificationTableViewCellDelegate {
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, avatarImageViewDidPressed imageView: UIImageView) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
guard let indexPath = tableView.indexPath(for: cell) else { return }
|
||||
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||
switch item {
|
||||
case .notification(let objectID, _):
|
||||
guard let notification = try? viewModel.fetchedResultsController.managedObjectContext.existingObject(with: objectID) as? MastodonNotification else { return }
|
||||
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||
coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: ActiveLabel) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
guard let indexPath = tableView.indexPath(for: cell) else { return }
|
||||
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||
switch item {
|
||||
case .notification(let objectID, _):
|
||||
guard let notification = try? viewModel.fetchedResultsController.managedObjectContext.existingObject(with: objectID) as? MastodonNotification else { return }
|
||||
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||
coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton) {
|
||||
viewModel.acceptFollowRequest(notification: notification)
|
||||
}
|
||||
@ -284,13 +315,6 @@ extension NotificationViewController: NotificationTableViewCellDelegate {
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, rejectButtonDidPressed button: UIButton) {
|
||||
viewModel.rejectFollowRequest(notification: notification)
|
||||
}
|
||||
|
||||
func userAvatarDidPressed(notification: MastodonNotification) {
|
||||
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||
DispatchQueue.main.async {
|
||||
self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||
}
|
||||
}
|
||||
|
||||
func userNameLabelDidPressed(notification: MastodonNotification) {
|
||||
let viewModel = CachedProfileViewModel(context: context, mastodonUser: notification.account)
|
||||
|
@ -5,8 +5,10 @@
|
||||
// Created by sxiaojian on 2021/4/14.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import Combine
|
||||
import Foundation
|
||||
import CoreDataStack
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
import MetaTextView
|
||||
@ -14,6 +16,23 @@ import Meta
|
||||
import FLAnimatedImage
|
||||
import Nuke
|
||||
|
||||
protocol NotificationTableViewCellDelegate: AnyObject {
|
||||
var context: AppContext! { get }
|
||||
func parent() -> UIViewController
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, avatarImageViewDidPressed imageView: UIImageView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: ActiveLabel)
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
|
||||
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton)
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, rejectButtonDidPressed button: UIButton)
|
||||
|
||||
}
|
||||
|
||||
final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
|
||||
|
||||
static let actionImageBorderWidth: CGFloat = 2
|
||||
@ -219,13 +238,12 @@ extension NotificationStatusTableViewCell {
|
||||
statusView.bottomAnchor.constraint(equalTo: statusContainerView.layoutMarginsGuide.bottomAnchor),
|
||||
])
|
||||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.statusContainerView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
|
||||
})
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
// remove item don't display
|
||||
@ -246,7 +264,14 @@ extension NotificationStatusTableViewCell {
|
||||
])
|
||||
|
||||
statusView.delegate = self
|
||||
|
||||
|
||||
let avatarImageViewTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
avatarImageViewTapGestureRecognizer.addTarget(self, action: #selector(NotificationStatusTableViewCell.avatarImageViewTapGestureRecognizerHandler(_:)))
|
||||
avatarImageView.addGestureRecognizer(avatarImageViewTapGestureRecognizer)
|
||||
let authorNameLabelTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
authorNameLabelTapGestureRecognizer.addTarget(self, action: #selector(NotificationStatusTableViewCell.authorNameLabelTapGestureRecognizerHandler(_:)))
|
||||
nameLabel.addGestureRecognizer(authorNameLabelTapGestureRecognizer)
|
||||
|
||||
resetSeparatorLineLayout()
|
||||
}
|
||||
|
||||
@ -260,6 +285,28 @@ extension NotificationStatusTableViewCell {
|
||||
|
||||
}
|
||||
|
||||
extension NotificationStatusTableViewCell {
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
statusContainerView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NotificationStatusTableViewCell {
|
||||
@objc private func avatarImageViewTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
delegate?.notificationStatusTableViewCell(self, avatarImageViewDidPressed: avatarImageView)
|
||||
}
|
||||
|
||||
@objc private func authorNameLabelTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
delegate?.notificationStatusTableViewCell(self, authorNameLabelDidPressed: nameLabel)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - StatusViewDelegate
|
||||
extension NotificationStatusTableViewCell: StatusViewDelegate {
|
||||
|
||||
|
@ -1,265 +0,0 @@
|
||||
//
|
||||
// NotificationTableViewCell.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by sxiaojian on 2021/4/13.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import CoreDataStack
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Meta
|
||||
import MetaTextView
|
||||
import ActiveLabel
|
||||
import FLAnimatedImage
|
||||
import Nuke
|
||||
|
||||
protocol NotificationTableViewCellDelegate: AnyObject {
|
||||
var context: AppContext! { get }
|
||||
|
||||
func parent() -> UIViewController
|
||||
|
||||
func userAvatarDidPressed(notification: MastodonNotification)
|
||||
func userNameLabelDidPressed(notification: MastodonNotification)
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
|
||||
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton)
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, rejectButtonDidPressed button: UIButton)
|
||||
|
||||
}
|
||||
|
||||
//final class NotificationTableViewCell: UITableViewCell {
|
||||
// static let actionImageBorderWidth: CGFloat = 2
|
||||
//
|
||||
// var disposeBag = Set<AnyCancellable>()
|
||||
//
|
||||
// var delegate: NotificationTableViewCellDelegate?
|
||||
//
|
||||
// var avatarImageViewTask: ImageTask?
|
||||
// let avatarImageView: UIImageView = {
|
||||
// let imageView = FLAnimatedImageView()
|
||||
// imageView.layer.cornerRadius = 4
|
||||
// imageView.layer.cornerCurve = .continuous
|
||||
// imageView.clipsToBounds = true
|
||||
// return imageView
|
||||
// }()
|
||||
//
|
||||
// let actionImageView: UIImageView = {
|
||||
// let imageView = UIImageView()
|
||||
// imageView.tintColor = Asset.Colors.Background.systemBackground.color
|
||||
// return imageView
|
||||
// }()
|
||||
//
|
||||
// let actionImageBackground: UIView = {
|
||||
// let view = UIView()
|
||||
// view.layer.cornerRadius = (24 + NotificationTableViewCell.actionImageBorderWidth) / 2
|
||||
// view.layer.cornerCurve = .continuous
|
||||
// view.clipsToBounds = true
|
||||
// view.layer.borderWidth = NotificationTableViewCell.actionImageBorderWidth
|
||||
// view.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
|
||||
// view.tintColor = Asset.Colors.Background.systemBackground.color
|
||||
// return view
|
||||
// }()
|
||||
//
|
||||
// let avatarContainer: UIView = {
|
||||
// let view = UIView()
|
||||
// return view
|
||||
// }()
|
||||
//
|
||||
// let actionLabel: UILabel = {
|
||||
// let label = UILabel()
|
||||
// label.textColor = Asset.Colors.Label.secondary.color
|
||||
// label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20)
|
||||
// label.lineBreakMode = .byTruncatingTail
|
||||
// return label
|
||||
// }()
|
||||
//
|
||||
// let nameLabel: ActiveLabel = {
|
||||
// let label = ActiveLabel()
|
||||
// label.textColor = Asset.Colors.brandBlue.color
|
||||
// label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20)
|
||||
// label.lineBreakMode = .byTruncatingTail
|
||||
// return label
|
||||
// }()
|
||||
//
|
||||
// let acceptButton: UIButton = {
|
||||
// let button = UIButton(type: .custom)
|
||||
// let actionImage = UIImage(systemName: "checkmark.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28, weight: .semibold))?.withRenderingMode(.alwaysTemplate)
|
||||
// button.setImage(actionImage, for: .normal)
|
||||
// button.tintColor = Asset.Colors.Label.secondary.color
|
||||
// return button
|
||||
// }()
|
||||
//
|
||||
// let rejectButton: UIButton = {
|
||||
// let button = UIButton(type: .custom)
|
||||
// let actionImage = UIImage(systemName: "xmark.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28, weight: .semibold))?.withRenderingMode(.alwaysTemplate)
|
||||
// button.setImage(actionImage, for: .normal)
|
||||
// button.tintColor = Asset.Colors.Label.secondary.color
|
||||
// return button
|
||||
// }()
|
||||
//
|
||||
// let buttonStackView = UIStackView()
|
||||
//
|
||||
// let separatorLine = UIView.separatorLine
|
||||
//
|
||||
// var separatorLineToEdgeLeadingLayoutConstraint: NSLayoutConstraint!
|
||||
// var separatorLineToEdgeTrailingLayoutConstraint: NSLayoutConstraint!
|
||||
//
|
||||
// var separatorLineToMarginLeadingLayoutConstraint: NSLayoutConstraint!
|
||||
// var separatorLineToMarginTrailingLayoutConstraint: NSLayoutConstraint!
|
||||
//
|
||||
// override func prepareForReuse() {
|
||||
// super.prepareForReuse()
|
||||
// avatarImageViewTask?.cancel()
|
||||
// avatarImageViewTask = nil
|
||||
// disposeBag.removeAll()
|
||||
// }
|
||||
//
|
||||
// override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
// super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
// configure()
|
||||
// }
|
||||
//
|
||||
// required init?(coder: NSCoder) {
|
||||
// super.init(coder: coder)
|
||||
// configure()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//extension NotificationTableViewCell {
|
||||
// func configure() {
|
||||
// backgroundColor = Asset.Colors.Background.systemBackground.color
|
||||
// selectedBackgroundView = {
|
||||
// let view = UIView()
|
||||
// view.backgroundColor = Asset.Colors.Background.Cell.highlight.color
|
||||
// return view
|
||||
// }()
|
||||
//
|
||||
// let containerStackView = UIStackView()
|
||||
// containerStackView.axis = .vertical
|
||||
// containerStackView.alignment = .fill
|
||||
// containerStackView.layoutMargins = UIEdgeInsets(top: 14, left: 0, bottom: 12, right: 0)
|
||||
// containerStackView.isLayoutMarginsRelativeArrangement = true
|
||||
// containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// contentView.addSubview(containerStackView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||
// containerStackView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
|
||||
// contentView.readableContentGuide.trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
|
||||
// contentView.bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
|
||||
// ])
|
||||
//
|
||||
// let horizontalStackView = UIStackView()
|
||||
// horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// horizontalStackView.axis = .horizontal
|
||||
// horizontalStackView.spacing = 6
|
||||
//
|
||||
// horizontalStackView.addArrangedSubview(avatarContainer)
|
||||
// avatarContainer.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// avatarContainer.heightAnchor.constraint(equalToConstant: 47).priority(.required - 1),
|
||||
// avatarContainer.widthAnchor.constraint(equalToConstant: 47).priority(.required - 1)
|
||||
// ])
|
||||
//
|
||||
// avatarContainer.addSubview(avatarImageView)
|
||||
// avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// avatarImageView.heightAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
||||
// avatarImageView.widthAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
||||
// avatarImageView.topAnchor.constraint(equalTo: avatarContainer.topAnchor),
|
||||
// avatarImageView.leadingAnchor.constraint(equalTo: avatarContainer.leadingAnchor)
|
||||
// ])
|
||||
//
|
||||
// avatarContainer.addSubview(actionImageBackground)
|
||||
// actionImageBackground.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// actionImageBackground.heightAnchor.constraint(equalToConstant: 24 + NotificationTableViewCell.actionImageBorderWidth).priority(.required - 1),
|
||||
// actionImageBackground.widthAnchor.constraint(equalToConstant: 24 + NotificationTableViewCell.actionImageBorderWidth).priority(.required - 1),
|
||||
// actionImageBackground.bottomAnchor.constraint(equalTo: avatarContainer.bottomAnchor),
|
||||
// actionImageBackground.trailingAnchor.constraint(equalTo: avatarContainer.trailingAnchor)
|
||||
// ])
|
||||
//
|
||||
// avatarContainer.addSubview(actionImageView)
|
||||
// actionImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// actionImageView.centerXAnchor.constraint(equalTo: actionImageBackground.centerXAnchor),
|
||||
// actionImageView.centerYAnchor.constraint(equalTo: actionImageBackground.centerYAnchor)
|
||||
// ])
|
||||
//
|
||||
// nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
// horizontalStackView.addArrangedSubview(nameLabel)
|
||||
// actionLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
// horizontalStackView.addArrangedSubview(actionLabel)
|
||||
// nameLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
|
||||
// nameLabel.setContentHuggingPriority(.required - 1, for: .horizontal)
|
||||
// actionLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||
//
|
||||
// containerStackView.addArrangedSubview(horizontalStackView)
|
||||
//
|
||||
// buttonStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// buttonStackView.axis = .horizontal
|
||||
// buttonStackView.distribution = .fillEqually
|
||||
// acceptButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
// rejectButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
// buttonStackView.addArrangedSubview(acceptButton)
|
||||
// buttonStackView.addArrangedSubview(rejectButton)
|
||||
// containerStackView.addArrangedSubview(buttonStackView)
|
||||
//
|
||||
// separatorLine.translatesAutoresizingMaskIntoConstraints = false
|
||||
// contentView.addSubview(separatorLine)
|
||||
// separatorLineToEdgeLeadingLayoutConstraint = separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
|
||||
// separatorLineToEdgeTrailingLayoutConstraint = separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
|
||||
// separatorLineToMarginLeadingLayoutConstraint = separatorLine.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor)
|
||||
// separatorLineToMarginTrailingLayoutConstraint = separatorLine.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor)
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
// separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)),
|
||||
// ])
|
||||
// resetSeparatorLineLayout()
|
||||
// }
|
||||
//
|
||||
// override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
// super.traitCollectionDidChange(previousTraitCollection)
|
||||
//
|
||||
// actionImageBackground.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
|
||||
// resetSeparatorLineLayout()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//extension NotificationTableViewCell {
|
||||
//
|
||||
// private func resetSeparatorLineLayout() {
|
||||
// separatorLineToEdgeLeadingLayoutConstraint.isActive = false
|
||||
// separatorLineToEdgeTrailingLayoutConstraint.isActive = false
|
||||
// separatorLineToMarginLeadingLayoutConstraint.isActive = false
|
||||
// separatorLineToMarginTrailingLayoutConstraint.isActive = false
|
||||
//
|
||||
// if traitCollection.userInterfaceIdiom == .phone {
|
||||
// // to edge
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLineToEdgeLeadingLayoutConstraint,
|
||||
// separatorLineToEdgeTrailingLayoutConstraint,
|
||||
// ])
|
||||
// } else {
|
||||
// if traitCollection.horizontalSizeClass == .compact {
|
||||
// // to edge
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLineToEdgeLeadingLayoutConstraint,
|
||||
// separatorLineToEdgeTrailingLayoutConstraint,
|
||||
// ])
|
||||
// } else {
|
||||
// // to margin
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLineToMarginLeadingLayoutConstraint,
|
||||
// separatorLineToMarginTrailingLayoutConstraint,
|
||||
// ])
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
@ -88,6 +88,7 @@ extension ProfileHeaderViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
@ -222,13 +223,18 @@ extension ProfileHeaderViewController {
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
Publishers.CombineLatest(
|
||||
Publishers.CombineLatest3(
|
||||
viewModel.isEditing,
|
||||
viewModel.displayProfileInfo.fields
|
||||
viewModel.displayProfileInfo.fields,
|
||||
viewModel.needsFiledCollectionViewHidden
|
||||
)
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] isEditing, fields in
|
||||
.sink { [weak self] isEditing, fields, needsHidden in
|
||||
guard let self = self else { return }
|
||||
guard !needsHidden else {
|
||||
self.profileHeaderView.fieldCollectionView.isHidden = true
|
||||
return
|
||||
}
|
||||
self.profileHeaderView.fieldCollectionView.isHidden = isEditing ? false : fields.isEmpty
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
@ -22,6 +22,7 @@ final class ProfileHeaderViewModel {
|
||||
let isEditing = CurrentValueSubject<Bool, Never>(false)
|
||||
let viewDidAppear = CurrentValueSubject<Bool, Never>(false)
|
||||
let needsSetupBottomShadow = CurrentValueSubject<Bool, Never>(true)
|
||||
let needsFiledCollectionViewHidden = CurrentValueSubject<Bool, Never>(false)
|
||||
let isTitleViewContentOffsetSet = CurrentValueSubject<Bool, Never>(false)
|
||||
let emojiDict = CurrentValueSubject<MastodonStatusContent.EmojiDict, Never>([:])
|
||||
let accountForEdit = CurrentValueSubject<Mastodon.Entity.Account?, Never>(nil)
|
||||
|
@ -218,7 +218,7 @@ final class ProfileHeaderView: UIView {
|
||||
collectionView.isScrollEnabled = false
|
||||
return collectionView
|
||||
}()
|
||||
var fieldCollectionViewHeightLaoutConstraint: NSLayoutConstraint!
|
||||
var fieldCollectionViewHeightLayoutConstraint: NSLayoutConstraint!
|
||||
var fieldCollectionViewHeightObservation: NSKeyValueObservation?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
@ -239,6 +239,8 @@ final class ProfileHeaderView: UIView {
|
||||
|
||||
extension ProfileHeaderView {
|
||||
private func _init() {
|
||||
backgroundColor = ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
|
||||
fieldCollectionView.backgroundColor = ThemeService.shared.currentTheme.value.profileFieldCollectionViewBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
@ -427,17 +429,17 @@ extension ProfileHeaderView {
|
||||
|
||||
fieldCollectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
metaContainerStackView.addArrangedSubview(fieldCollectionView)
|
||||
fieldCollectionViewHeightLaoutConstraint = fieldCollectionView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh)
|
||||
fieldCollectionViewHeightLayoutConstraint = fieldCollectionView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh)
|
||||
NSLayoutConstraint.activate([
|
||||
fieldCollectionViewHeightLaoutConstraint,
|
||||
fieldCollectionViewHeightLayoutConstraint,
|
||||
])
|
||||
fieldCollectionViewHeightObservation = fieldCollectionView.observe(\.contentSize, options: .new, changeHandler: { [weak self] tableView, _ in
|
||||
guard let self = self else { return }
|
||||
guard self.fieldCollectionView.contentSize.height != .zero else {
|
||||
self.fieldCollectionViewHeightLaoutConstraint.constant = 44
|
||||
self.fieldCollectionViewHeightLayoutConstraint.constant = 44
|
||||
return
|
||||
}
|
||||
self.fieldCollectionViewHeightLaoutConstraint.constant = self.fieldCollectionView.contentSize.height
|
||||
self.fieldCollectionViewHeightLayoutConstraint.constant = self.fieldCollectionView.contentSize.height
|
||||
})
|
||||
|
||||
bringSubviewToFront(bannerContainerView)
|
||||
|
@ -141,7 +141,8 @@ extension ProfileViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
@ -495,7 +496,8 @@ extension ProfileViewController {
|
||||
let isNeedSetHidden = isBlocking || isBlockedBy || suspended
|
||||
self.profileHeaderViewController.viewModel.needsSetupBottomShadow.value = !isNeedSetHidden
|
||||
self.profileHeaderViewController.profileHeaderView.bioContainerView.isHidden = isNeedSetHidden
|
||||
self.profileHeaderViewController.pageSegmentedControl.isHidden = isNeedSetHidden
|
||||
self.profileHeaderViewController.viewModel.needsFiledCollectionViewHidden.value = isNeedSetHidden
|
||||
self.profileHeaderViewController.pageSegmentedControl.isEnabled = !isNeedSetHidden
|
||||
self.viewModel.needsPagePinToTop.value = isNeedSetHidden
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
@ -530,7 +532,7 @@ extension ProfileViewController {
|
||||
self.profileHeaderViewController.profileHeaderView.statusDashboardView.followersDashboardMeterView.accessibilityLabel = L10n.Scene.Profile.Dashboard.Accessibility.countFollowers(count ?? 0)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
viewModel.needsPaingEnabled
|
||||
viewModel.needsPagingEnabled
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] needsPaingEnabled in
|
||||
guard let self = self else { return }
|
||||
|
@ -63,7 +63,7 @@ class ProfileViewModel: NSObject {
|
||||
let isMeBarButtonItemsHidden = CurrentValueSubject<Bool, Never>(true)
|
||||
|
||||
let needsPagePinToTop = CurrentValueSubject<Bool, Never>(false)
|
||||
let needsPaingEnabled = CurrentValueSubject<Bool, Never>(true)
|
||||
let needsPagingEnabled = CurrentValueSubject<Bool, Never>(true)
|
||||
let needsImageOverlayBlurred = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
init(context: AppContext, optionalMastodonUser mastodonUser: MastodonUser?) {
|
||||
@ -161,7 +161,7 @@ class ProfileViewModel: NSObject {
|
||||
|
||||
isBlockingOrBlocked
|
||||
.map { !$0 }
|
||||
.assign(to: \.value, on: needsPaingEnabled)
|
||||
.assign(to: \.value, on: needsPagingEnabled)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
isBlockingOrBlocked
|
||||
|
@ -135,14 +135,12 @@ extension SearchViewController {
|
||||
navigationItem.compactAppearance = barAppearance
|
||||
navigationItem.scrollEdgeAppearance = barAppearance
|
||||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.view.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
self.searchHeader.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
self.searchingTableView.backgroundColor = theme.systemBackgroundColor
|
||||
self.statusBar.backgroundColor = theme.navigationBarBackgroundColor
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
@ -171,6 +169,13 @@ extension SearchViewController {
|
||||
viewModel.viewDidAppeared.send()
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
searchHeader.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
searchingTableView.backgroundColor = theme.systemBackgroundColor
|
||||
statusBar.backgroundColor = theme.navigationBarBackgroundColor
|
||||
}
|
||||
|
||||
func setupSearchBar() {
|
||||
searchBar.delegate = self
|
||||
view.addSubview(searchBar)
|
||||
|
@ -205,27 +205,12 @@ class SettingsViewController: UIViewController, NeedsDependency {
|
||||
}
|
||||
|
||||
private func setupView() {
|
||||
self.view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
switch traitCollection.userInterfaceLevel {
|
||||
case .elevated where traitCollection.userInterfaceStyle == .dark:
|
||||
return ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
|
||||
default:
|
||||
return ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
}
|
||||
})
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
switch traitCollection.userInterfaceLevel {
|
||||
case .elevated where traitCollection.userInterfaceStyle == .dark:
|
||||
return theme.systemElevatedBackgroundColor
|
||||
default:
|
||||
return theme.secondarySystemBackgroundColor
|
||||
}
|
||||
})
|
||||
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
@ -241,6 +226,17 @@ class SettingsViewController: UIViewController, NeedsDependency {
|
||||
|
||||
updateSectionHeaderStackViewLayout()
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
switch traitCollection.userInterfaceLevel {
|
||||
case .elevated where traitCollection.userInterfaceStyle == .dark:
|
||||
return theme.systemElevatedBackgroundColor
|
||||
default:
|
||||
return theme.secondarySystemBackgroundColor
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func setupNavigation() {
|
||||
navigationController?.navigationBar.prefersLargeTitles = true
|
||||
|
102
Mastodon/Scene/Settings/View/AppearanceView.swift
Normal file
102
Mastodon/Scene/Settings/View/AppearanceView.swift
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// AppearanceView.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-6.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AppearanceView: UIView {
|
||||
lazy var imageView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
// accessibility
|
||||
view.accessibilityIgnoresInvertColors = true
|
||||
return view
|
||||
}()
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 12, weight: .regular)
|
||||
label.textColor = Asset.Colors.Label.primary.color
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
lazy var checkBox: UIButton = {
|
||||
let button = UIButton()
|
||||
button.isUserInteractionEnabled = false
|
||||
button.setImage(UIImage(systemName: "circle"), for: .normal)
|
||||
button.setImage(UIImage(systemName: "checkmark.circle.fill"), for: .selected)
|
||||
button.imageView?.preferredSymbolConfiguration = UIImage.SymbolConfiguration(textStyle: .body)
|
||||
button.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
button.imageView?.contentMode = .scaleAspectFill
|
||||
return button
|
||||
}()
|
||||
lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.spacing = 10
|
||||
view.distribution = .equalSpacing
|
||||
return view
|
||||
}()
|
||||
|
||||
var selected: Bool = false {
|
||||
didSet {
|
||||
checkBox.isSelected = selected
|
||||
if selected {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.brandBlue.color
|
||||
} else {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
init(image: UIImage?, title: String) {
|
||||
super.init(frame: .zero)
|
||||
setupUI()
|
||||
|
||||
imageView.image = image
|
||||
titleLabel.text = title
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func setupUI() {
|
||||
stackView.addArrangedSubview(imageView)
|
||||
stackView.addArrangedSubview(titleLabel)
|
||||
stackView.addArrangedSubview(checkBox)
|
||||
|
||||
addSubview(stackView)
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.topAnchor.constraint(equalTo: self.topAnchor),
|
||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
||||
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 218.0 / 100.0),
|
||||
])
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
self.alpha = 0.5
|
||||
}
|
||||
|
||||
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesEnded(touches, with: event)
|
||||
UIView.animate(withDuration: 0.33) {
|
||||
self.alpha = 1
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesCancelled(touches, with: event)
|
||||
UIView.animate(withDuration: 0.33) {
|
||||
self.alpha = 1
|
||||
}
|
||||
}
|
||||
}
|
@ -12,81 +12,6 @@ protocol SettingsAppearanceTableViewCellDelegate: AnyObject {
|
||||
func settingsAppearanceCell(_ cell: SettingsAppearanceTableViewCell, didSelectAppearanceMode appearanceMode: SettingsItem.AppearanceMode)
|
||||
}
|
||||
|
||||
class AppearanceView: UIView {
|
||||
lazy var imageView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
// accessibility
|
||||
view.accessibilityIgnoresInvertColors = true
|
||||
return view
|
||||
}()
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 12, weight: .regular)
|
||||
label.textColor = Asset.Colors.Label.primary.color
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
lazy var checkBox: UIButton = {
|
||||
let button = UIButton()
|
||||
button.isUserInteractionEnabled = false
|
||||
button.setImage(UIImage(systemName: "circle"), for: .normal)
|
||||
button.setImage(UIImage(systemName: "checkmark.circle.fill"), for: .selected)
|
||||
button.imageView?.preferredSymbolConfiguration = UIImage.SymbolConfiguration(textStyle: .body)
|
||||
button.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
button.imageView?.contentMode = .scaleAspectFill
|
||||
return button
|
||||
}()
|
||||
lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.spacing = 10
|
||||
view.distribution = .equalSpacing
|
||||
return view
|
||||
}()
|
||||
|
||||
var selected: Bool = false {
|
||||
didSet {
|
||||
checkBox.isSelected = selected
|
||||
if selected {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.brandBlue.color
|
||||
} else {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
init(image: UIImage?, title: String) {
|
||||
super.init(frame: .zero)
|
||||
setupUI()
|
||||
|
||||
imageView.image = image
|
||||
titleLabel.text = title
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func setupUI() {
|
||||
stackView.addArrangedSubview(imageView)
|
||||
stackView.addArrangedSubview(titleLabel)
|
||||
stackView.addArrangedSubview(checkBox)
|
||||
|
||||
addSubview(stackView)
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.topAnchor.constraint(equalTo: self.topAnchor),
|
||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
||||
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 218.0 / 100.0),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsAppearanceTableViewCell: UITableViewCell {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
@ -51,7 +51,8 @@ extension ThreadViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
Loading…
x
Reference in New Issue
Block a user