2
2
mirror of https://github.com/mastodon/mastodon-ios synced 2025-04-11 22:58:02 +02:00
mastodon-ios/Mastodon/Scene/Thread/ThreadViewController.swift
CMK 6153839157
Release v1.3.0 (#347)
* New translations app.json (Thai)

* New translations app.json (Spanish)

* New translations Localizable.stringsdict (Spanish)

* New translations app.json (Thai)

* New translations app.json (Thai)

* feat: adapt the app to async & await. Update timeline UI

* fix: update the Xcode version to fix the CI failure

* fix: remove unavailable framework import

* fix: project dependency issue

* feat: add content warning for post spoiler

* feat: add content warning for post media

* chore: update version to 1.3.0 (92)

* New translations app.json (French)

* New translations Intents.strings (French)

* New translations app.json (Thai)

* feat: update report flow

* feat: update setting scene UI

* feat: update status content warning UI

* feat: add notification gap fetcher

* chore: update version to 1.3.0 (93)

* feat: add video player for audio/video kind media

* chore: update version to 1.3.0 (94)

* fix: text strip wrong color in the Dark Mode issue

* chore: remove spoiler toggle animation for table cell

* fix: add missing shadow for compose publish button

* fix: add missing margin for timeline with horizontal regular size class

* fix: profile segmented controls missing margin issue

* fix: the profile segmented control use wrong selection tint color under force light UI style issue

* fix: add notification count clear logic back

* fix: add missing home timeline bottom fetcher

* fix: [WIP] add suggestion account scene back

* New translations app.json (Kabyle)

* New translations ios-infoPlist.json (Kabyle)

* New translations Localizable.stringsdict (Kabyle)

* New translations Intents.strings (Kabyle)

* New translations Intents.stringsdict (Kabyle)

* feat: make the home timeline readable for VoiceOver

* chore: update version to 1.3.0 (95)

* New translations app.json (French)

* New translations Intents.strings (French)

* New translations app.json (Kabyle)

* New translations ios-infoPlist.json (Kabyle)

* New translations Localizable.stringsdict (Kabyle)

* New translations Intents.strings (Kabyle)

* New translations Intents.stringsdict (Kabyle)

* New translations Localizable.stringsdict (French)

* New translations app.json (Kabyle)

* New translations app.json (French)

* chore: update action toolbar icons

* fix: instal state missing issue

* fix: follow push notification deep-link not works issue

* fix: foreground notification not trigger tab bell icon update issue

* feat: add notification timeline fetcher

* feat: add content warning toggle button

* chore: update version to 1.3.0 (96)

* New translations app.json (Thai)

* New translations app.json (Russian)

* New translations app.json (Kurmanji (Kurdish))

* New translations app.json (Scottish Gaelic)

* New translations app.json (Welsh)

* New translations app.json (Hindi)

* New translations app.json (Spanish, Argentina)

* New translations app.json (Indonesian)

* New translations app.json (Portuguese, Brazilian)

* New translations app.json (English)

* New translations app.json (Chinese Traditional)

* New translations app.json (Chinese Simplified)

* New translations app.json (Swedish)

* New translations app.json (Portuguese)

* New translations app.json (Dutch)

* New translations app.json (Korean)

* New translations app.json (Japanese)

* New translations app.json (Basque)

* New translations app.json (German)

* New translations app.json (Danish)

* New translations app.json (Catalan)

* New translations app.json (Arabic)

* New translations app.json (Spanish)

* New translations app.json (Romanian)

* New translations app.json (Kabyle)

* New translations app.json (French)

* New translations app.json (Swedish, Finland)

* New translations app.json (Spanish, Argentina)

* New translations app.json (Kurmanji (Kurdish))

* fix: notification i18n word typo

* New translations app.json (Thai)

* New translations app.json (Swedish)

* New translations Localizable.stringsdict (Swedish)

* New translations app.json (Swedish, Finland)

* New translations app.json (Kurmanji (Kurdish))

* New translations app.json (Scottish Gaelic)

* New translations app.json (Welsh)

* New translations app.json (Hindi)

* New translations app.json (Indonesian)

* New translations app.json (Portuguese, Brazilian)

* New translations app.json (English)

* New translations app.json (Chinese Traditional)

* New translations app.json (Chinese Simplified)

* New translations app.json (Russian)

* New translations app.json (Portuguese)

* New translations app.json (Dutch)

* New translations app.json (Korean)

* New translations app.json (Japanese)

* New translations app.json (Basque)

* New translations app.json (German)

* New translations app.json (Danish)

* New translations app.json (Catalan)

* New translations app.json (Arabic)

* New translations app.json (Spanish)

* New translations app.json (Romanian)

* New translations app.json (Kabyle)

* New translations app.json (French)

* New translations Intents.strings (Swedish)

* New translations app.json (Swedish)

* New translations Localizable.stringsdict (Japanese)

* New translations app.json (Thai)

* New translations app.json (Thai)

* New translations Localizable.stringsdict (Swedish)

* New translations app.json (Kabyle)

* New translations ios-infoPlist.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (French)

* New translations app.json (French)

* feat: restore scroll-to-top tap gesture for TabBar

* feat: add cell height cache for user timeline

* feat: display no results when profile field empty

* New translations app.json (Chinese Traditional)

* New translations app.json (Chinese Traditional)

* New translations Intents.strings (Japanese)

* feat: make status detail accessible

* chore: restore the appearance settings

* chore: update version to 1.3.0 (97)

* New translations app.json (Kabyle)

* New translations Intents.strings (Japanese)

* New translations app.json (Swedish)

* New translations app.json (Basque)

* New translations app.json (Basque)

* chore: add a11y hint for profile dashboard

* feat: add media interaction for notification timeline

* New translations app.json (Chinese Simplified)

* New translations app.json (Chinese Simplified)

* chore: update i18n strings

* fix: setting switch use wrong tint color issue

* chore: restore RTL layout for post content

* chore: update profile relationship button UI

* chore: update color panel

* fix: post reblog header may display empty reblogger name issue

* fix: wrong reply header redirect logic issue

* feat: restore post filter supports

* chore: update version to 1.3.0 (98)

* chore: update post content sensitive style

* fix: blurhash image not display during image loading issue

* chore: update version to 1.3.0 (99)

* feat: restore user recommend scene

* chore: update badge tint color

* feat: restore keyboard shortcut supports

* chore: update version to 1.3.0 (100)

* fix: relationship background use wrong color when force dark style

* fix: player button icon not reset issue

* chore: update version to 1.3.0 (101)

* fix: profile relationship button fill the width on iPad issue

* fix: inputAssistantItem duplicate setup issue

* chore: update textView minimum height from 88 to 64

* chore: update version to 1.3.0 (102)

* chore: update status timeline margin

* chore: update sidebar background color

* fix: split view column state after size class transition not stable issue

* chore: update notification timeline margin

* chore: update profile header and segmented bar margin

* fix: profile segmented bar use wrong tint color when force Dark Mode issue

* chore: update horizontal compact mode notification timeline margin looks like

* chore: update version to 1.3.0 (103)

* feat: dismiss image preview when tap empty area

* chore: update version to 1.3.0 (104)

* New translations app.json (Italian)

* New translations ios-infoPlist.json (Italian)

* New translations Localizable.stringsdict (Italian)

* New translations Intents.strings (Italian)

* New translations Intents.stringsdict (Italian)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Japanese)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Spanish)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Kabyle)

* New translations ios-infoPlist.json (Kabyle)

* New translations Localizable.stringsdict (Kabyle)

* New translations Localizable.stringsdict (Kabyle)

* New translations Intents.strings (Kabyle)

* New translations app.json (Kabyle)

* New translations Intents.strings (Kabyle)

* New translations Intents.stringsdict (Kabyle)

* New translations app.json (Kabyle)

* New translations app.json (Scottish Gaelic)

* New translations app.json (Scottish Gaelic)

* New translations app.json (Thai)

* New translations app.json (Thai)

* feat: add UITests for snapshots

* feat: add snapshot UITest and document

* New translations app.json (Thai)

* feat: add notification snapshot

* chore: add domain and update guide for the snapshot UITest

* chore: use the first photo for compose snapshot

* New translations app.json (Thai)

* New translations app.json (German)

* New translations app.json (German)

* chore: update settings scene UI

* chore: update i18n for open link words

* chore: update i18n resources

* fix: share extension not accept plaintext content issue. resolve #335

* chore: update version to 1.3.0 (105)

* New translations app.json (Japanese)

* New translations app.json (Japanese)

* New translations app.json (Japanese)

* feat: add onion domain ATS exception rule. resolve #338

* chore: update app version footer and i18n strings

* chore: update version to 1.3.0 (106)

* chore: update version to 1.3.0 (108)

* Handle onboarding authentication errors in /api/v1/instance

* New translations app.json (Kurmanji (Kurdish))

* New translations app.json (Kurmanji (Kurdish))

* chore: update Xcode schemes index

* chore: update the snapshot documents and UITests

* chore: update i18n resources. resolve #343

* chore: retain the API model semantic

* fix: force LTR for some text fields. #318

* fix: textView break IME input issue. resolve #342

* chore: update version to 1.3.0 (109)

* chore: update README

* chore: fix typo

* chore: add bug report template and contributing document

Co-authored-by: Eugen Rochko <eugen@zeonfederated.com>
Co-authored-by: Zac West <zacwest@gmail.com>
2022-03-29 11:51:14 +02:00

197 lines
7.7 KiB
Swift

//
// ThreadViewController.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-4-12.
//
import os.log
import UIKit
import Combine
import CoreData
import AVKit
import MastodonMeta
import MastodonAsset
import MastodonLocalization
final class ThreadViewController: UIViewController, NeedsDependency, MediaPreviewableViewController {
let logger = Logger(subsystem: "ThreadViewController", category: "ViewController")
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
var disposeBag = Set<AnyCancellable>()
var viewModel: ThreadViewModel!
let mediaPreviewTransitionController = MediaPreviewTransitionController()
let titleView = DoubleTitleLabelNavigationBarTitleView()
let replyBarButtonItem = AdaptiveUserInterfaceStyleBarButtonItem(
lightImage: UIImage(systemName: "arrowshape.turn.up.left")!,
darkImage: UIImage(systemName: "arrowshape.turn.up.left.fill")!
)
let tableView: UITableView = {
let tableView = ControlContainableTableView()
tableView.register(StatusTableViewCell.self, forCellReuseIdentifier: String(describing: StatusTableViewCell.self))
tableView.register(TimelineMiddleLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self))
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
tableView.register(ThreadReplyLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: ThreadReplyLoaderTableViewCell.self))
tableView.rowHeight = UITableView.automaticDimension
tableView.separatorStyle = .none
tableView.backgroundColor = .clear
return tableView
}()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", ((#file as NSString).lastPathComponent), #line, #function)
}
}
extension ThreadViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
navigationItem.title = L10n.Scene.Thread.backTitle
navigationItem.titleView = titleView
navigationItem.rightBarButtonItem = replyBarButtonItem
replyBarButtonItem.button.addTarget(self, action: #selector(ThreadViewController.replyBarButtonItemPressed(_:)), for: .touchUpInside)
viewModel.$navigationBarTitle
.receive(on: DispatchQueue.main)
.sink { [weak self] title in
guard let self = self else { return }
guard let title = title else {
self.titleView.update(title: "", subtitle: nil)
return
}
self.titleView.update(titleMetaContent: title, subtitle: nil)
}
.store(in: &disposeBag)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
tableView.delegate = self
viewModel.setupDiffableDataSource(
tableView: tableView,
statusTableViewCellDelegate: self
)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.deselectRow(with: transitionCoordinator, animated: animated)
}
}
extension ThreadViewController {
@objc private func replyBarButtonItemPressed(_ sender: UIBarButtonItem) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
guard case let .root(threadContext) = viewModel.root else { return }
guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
let composeViewModel = ComposeViewModel(
context: context,
composeKind: .reply(status: threadContext.status),
authenticationBox: authenticationBox
)
coordinator.present(
scene: .compose(viewModel: composeViewModel),
from: self,
transition: .modal(animated: true, completion: nil)
)
}
}
//// MARK: - StatusTableViewControllerAspect
//extension ThreadViewController: StatusTableViewControllerAspect { }
// MARK: - UITableViewDelegate
extension ThreadViewController: UITableViewDelegate, AutoGenerateTableViewDelegate {
// sourcery:inline:ThreadViewController.AutoGenerateTableViewDelegate
// Generated using Sourcery
// DO NOT EDIT
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
aspectTableView(tableView, didSelectRowAt: indexPath)
}
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
return aspectTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point)
}
func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
return aspectTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration)
}
func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? {
return aspectTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration)
}
func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
aspectTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator)
}
// sourcery:end
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
guard let diffableDataSource = viewModel.diffableDataSource else { return nil }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil }
switch item {
case .thread(let thread):
switch thread {
case .root:
return nil
default:
return indexPath
}
default:
return indexPath
}
}
}
// MARK: - StatusTableViewCellDelegate
extension ThreadViewController: StatusTableViewCellDelegate { }
extension ThreadViewController {
override var keyCommands: [UIKeyCommand]? {
return navigationKeyCommands + statusNavigationKeyCommands
}
}
// MARK: - StatusTableViewControllerNavigateable
extension ThreadViewController: StatusTableViewControllerNavigateable {
@objc func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) {
navigateKeyCommandHandler(sender)
}
@objc func statusKeyCommandHandlerRelay(_ sender: UIKeyCommand) {
statusKeyCommandHandler(sender)
}
}