1
0
mirror of https://github.com/mastodon/mastodon-ios.git synced 2025-01-25 13:38:43 +01:00

Merge pull request #207 from tootsuite/fix/UI-issues

Fix UI issues
This commit is contained in:
CMK 2021-07-06 18:26:03 +08:00 committed by GitHub
commit 30618dd687
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 330 additions and 434 deletions

View File

@ -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" */ = {

View File

@ -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>

View File

@ -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"
}
},
{

View File

@ -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(

View File

@ -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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 {

View File

@ -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,
// ])
// }
// }
// }
//
//}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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 }

View File

@ -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

View File

@ -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)

View File

@ -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

View 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
}
}
}

View File

@ -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>()

View File

@ -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