Official account and website in about
This commit is contained in:
parent
8e48a8bab8
commit
187bc42373
|
@ -1,5 +1,6 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
// Copyright © 2020 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import SafariServices
|
||||||
import UIKit
|
import UIKit
|
||||||
import ViewModels
|
import ViewModels
|
||||||
|
|
||||||
|
@ -16,4 +17,26 @@ extension UIViewController {
|
||||||
|
|
||||||
present(alertController, animated: true)
|
present(alertController, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !IS_SHARE_EXTENSION
|
||||||
|
func open(url: URL, identityContext: IdentityContext) {
|
||||||
|
func openWithRegardToBrowserSetting(url: URL) {
|
||||||
|
if identityContext.appPreferences.openLinksInDefaultBrowser || !url.isHTTPURL {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
} else {
|
||||||
|
present(SFSafariViewController(url: url), animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if identityContext.appPreferences.useUniversalLinks {
|
||||||
|
UIApplication.shared.open(url, options: [.universalLinksOnly: true]) { success in
|
||||||
|
if !success {
|
||||||
|
openWithRegardToBrowserSetting(url: url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
openWithRegardToBrowserSetting(url: url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
"about" = "About";
|
"about" = "About";
|
||||||
"about.acknowledgments" = "Acknowledgments";
|
"about.acknowledgments" = "Acknowledgments";
|
||||||
|
"about.made-by-metabolist" = "Made by Metabolist";
|
||||||
|
"about.official-account" = "Official Account";
|
||||||
|
"about.website" = "Website";
|
||||||
"accessibility.activate-link-%@" = "Activate link: %@";
|
"accessibility.activate-link-%@" = "Activate link: %@";
|
||||||
"accessibility.copy-text" = "Copy text";
|
"accessibility.copy-text" = "Copy text";
|
||||||
"account.%@-followers" = "%@'s Followers";
|
"account.%@-followers" = "%@'s Followers";
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0030981250C6C8500EACB32 /* URL+Extensions.swift */; };
|
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0030981250C6C8500EACB32 /* URL+Extensions.swift */; };
|
||||||
D005A1D825EF189A008B2E63 /* ReportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D005A1D725EF189A008B2E63 /* ReportViewController.swift */; };
|
D005A1D825EF189A008B2E63 /* ReportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D005A1D725EF189A008B2E63 /* ReportViewController.swift */; };
|
||||||
D005A1E625EF3D11008B2E63 /* ReportHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D005A1E525EF3D11008B2E63 /* ReportHeaderView.swift */; };
|
D005A1E625EF3D11008B2E63 /* ReportHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D005A1E525EF3D11008B2E63 /* ReportHeaderView.swift */; };
|
||||||
|
D005A20025EF574F008B2E63 /* NavigationHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = D005A1FF25EF574F008B2E63 /* NavigationHandling.swift */; };
|
||||||
|
D005A20125EF574F008B2E63 /* NavigationHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = D005A1FF25EF574F008B2E63 /* NavigationHandling.swift */; };
|
||||||
D00702292555E51200F38136 /* ConversationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702282555E51200F38136 /* ConversationTableViewCell.swift */; };
|
D00702292555E51200F38136 /* ConversationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702282555E51200F38136 /* ConversationTableViewCell.swift */; };
|
||||||
D00702312555F4AE00F38136 /* ConversationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702302555F4AE00F38136 /* ConversationView.swift */; };
|
D00702312555F4AE00F38136 /* ConversationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702302555F4AE00F38136 /* ConversationView.swift */; };
|
||||||
D00702362555F4C500F38136 /* ConversationContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */; };
|
D00702362555F4C500F38136 /* ConversationContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */; };
|
||||||
|
@ -262,6 +264,7 @@
|
||||||
D0030981250C6C8500EACB32 /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = "<group>"; };
|
D0030981250C6C8500EACB32 /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
D005A1D725EF189A008B2E63 /* ReportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportViewController.swift; sourceTree = "<group>"; };
|
D005A1D725EF189A008B2E63 /* ReportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportViewController.swift; sourceTree = "<group>"; };
|
||||||
D005A1E525EF3D11008B2E63 /* ReportHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportHeaderView.swift; sourceTree = "<group>"; };
|
D005A1E525EF3D11008B2E63 /* ReportHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportHeaderView.swift; sourceTree = "<group>"; };
|
||||||
|
D005A1FF25EF574F008B2E63 /* NavigationHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationHandling.swift; sourceTree = "<group>"; };
|
||||||
D00702282555E51200F38136 /* ConversationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationTableViewCell.swift; sourceTree = "<group>"; };
|
D00702282555E51200F38136 /* ConversationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D00702302555F4AE00F38136 /* ConversationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationView.swift; sourceTree = "<group>"; };
|
D00702302555F4AE00F38136 /* ConversationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationView.swift; sourceTree = "<group>"; };
|
||||||
D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationContentConfiguration.swift; sourceTree = "<group>"; };
|
D00702352555F4C500F38136 /* ConversationContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationContentConfiguration.swift; sourceTree = "<group>"; };
|
||||||
|
@ -735,6 +738,7 @@
|
||||||
D0C7D42024F76169001EBDBB /* Views */ = {
|
D0C7D42024F76169001EBDBB /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D005A1FF25EF574F008B2E63 /* NavigationHandling.swift */,
|
||||||
D021A66425C3E170008A0C0D /* SwiftUI */,
|
D021A66425C3E170008A0C0D /* SwiftUI */,
|
||||||
D021A66325C3E167008A0C0D /* UIKit */,
|
D021A66325C3E167008A0C0D /* UIKit */,
|
||||||
D0EA59472522B8B600804347 /* ViewConstants.swift */,
|
D0EA59472522B8B600804347 /* ViewConstants.swift */,
|
||||||
|
@ -1084,6 +1088,7 @@
|
||||||
D0E9F9AA258450B300EF503D /* CompositionInputAccessoryView.swift in Sources */,
|
D0E9F9AA258450B300EF503D /* CompositionInputAccessoryView.swift in Sources */,
|
||||||
D021A60A25C36B32008A0C0D /* IdentityTableViewCell.swift in Sources */,
|
D021A60A25C36B32008A0C0D /* IdentityTableViewCell.swift in Sources */,
|
||||||
D0849C7F25903C4900A5EBCC /* Status+Extensions.swift in Sources */,
|
D0849C7F25903C4900A5EBCC /* Status+Extensions.swift in Sources */,
|
||||||
|
D005A20025EF574F008B2E63 /* NavigationHandling.swift in Sources */,
|
||||||
D0F4362D25C10B9600E4F896 /* AddIdentityViewController.swift in Sources */,
|
D0F4362D25C10B9600E4F896 /* AddIdentityViewController.swift in Sources */,
|
||||||
D035D8F925E4338D00E597C9 /* ImageDiskCache.swift in Sources */,
|
D035D8F925E4338D00E597C9 /* ImageDiskCache.swift in Sources */,
|
||||||
D0625E59250F092900502611 /* StatusTableViewCell.swift in Sources */,
|
D0625E59250F092900502611 /* StatusTableViewCell.swift in Sources */,
|
||||||
|
@ -1203,6 +1208,7 @@
|
||||||
D059373425AAEA7000754FDF /* CompositionPollView.swift in Sources */,
|
D059373425AAEA7000754FDF /* CompositionPollView.swift in Sources */,
|
||||||
D021A67B25C3E32A008A0C0D /* PlayerView.swift in Sources */,
|
D021A67B25C3E32A008A0C0D /* PlayerView.swift in Sources */,
|
||||||
D052DBDD25EAF01800FFB628 /* URL+Extensions.swift in Sources */,
|
D052DBDD25EAF01800FFB628 /* URL+Extensions.swift in Sources */,
|
||||||
|
D005A20125EF574F008B2E63 /* NavigationHandling.swift in Sources */,
|
||||||
D021A69025C3E4B8008A0C0D /* EmojiContentConfiguration.swift in Sources */,
|
D021A69025C3E4B8008A0C0D /* EmojiContentConfiguration.swift in Sources */,
|
||||||
D08E52D2257C811200FA2C5F /* ShareExtensionError+Extensions.swift in Sources */,
|
D08E52D2257C811200FA2C5F /* ShareExtensionError+Extensions.swift in Sources */,
|
||||||
D00CB23D25C9305D008EF267 /* NSMutableAttributedString+Extensions.swift in Sources */,
|
D00CB23D25C9305D008EF267 /* NSMutableAttributedString+Extensions.swift in Sources */,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import UIKit
|
||||||
import ViewModels
|
import ViewModels
|
||||||
|
|
||||||
final class ExploreViewController: UICollectionViewController {
|
final class ExploreViewController: UICollectionViewController {
|
||||||
|
private let webfingerIndicatorView = WebfingerIndicatorView()
|
||||||
private let viewModel: ExploreViewModel
|
private let viewModel: ExploreViewModel
|
||||||
private let rootViewModel: RootViewModel
|
private let rootViewModel: RootViewModel
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
@ -30,6 +31,7 @@ final class ExploreViewController: UICollectionViewController {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable:next function_body_length
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
@ -60,6 +62,9 @@ final class ExploreViewController: UICollectionViewController {
|
||||||
searchController.searchBar.keyboardType = .twitter
|
searchController.searchBar.keyboardType = .twitter
|
||||||
navigationItem.searchController = searchController
|
navigationItem.searchController = searchController
|
||||||
|
|
||||||
|
view.addSubview(webfingerIndicatorView)
|
||||||
|
webfingerIndicatorView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
viewModel.identityContext.$appPreferences.sink { appPreferences in
|
viewModel.identityContext.$appPreferences.sink { appPreferences in
|
||||||
searchController.searchBar.scopeButtonTitles = SearchScope.allCases.map {
|
searchController.searchBar.scopeButtonTitles = SearchScope.allCases.map {
|
||||||
$0.title(statusWord: appPreferences.statusWord)
|
$0.title(statusWord: appPreferences.statusWord)
|
||||||
|
@ -67,6 +72,11 @@ final class ExploreViewController: UICollectionViewController {
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
webfingerIndicatorView.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
|
||||||
|
webfingerIndicatorView.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
viewModel.events.sink { [weak self] in self?.handle(event: $0) }.store(in: &cancellables)
|
viewModel.events.sink { [weak self] in self?.handle(event: $0) }.store(in: &cancellables)
|
||||||
|
|
||||||
viewModel.$loading.sink { [weak self] in
|
viewModel.$loading.sink { [weak self] in
|
||||||
|
@ -126,6 +136,43 @@ extension ExploreViewController: ScrollableToTop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ExploreViewController: NavigationHandling {
|
||||||
|
func handle(navigation: Navigation) {
|
||||||
|
switch navigation {
|
||||||
|
case let .collection(collectionService):
|
||||||
|
let vc = TableViewController(
|
||||||
|
viewModel: CollectionItemsViewModel(
|
||||||
|
collectionService: collectionService,
|
||||||
|
identityContext: viewModel.identityContext),
|
||||||
|
rootViewModel: rootViewModel,
|
||||||
|
parentNavigationController: nil)
|
||||||
|
|
||||||
|
show(vc, sender: self)
|
||||||
|
webfingerIndicatorView.stopAnimating()
|
||||||
|
case let .profile(profileService):
|
||||||
|
let vc = ProfileViewController(
|
||||||
|
viewModel: ProfileViewModel(
|
||||||
|
profileService: profileService,
|
||||||
|
identityContext: viewModel.identityContext),
|
||||||
|
rootViewModel: rootViewModel,
|
||||||
|
identityContext: viewModel.identityContext,
|
||||||
|
parentNavigationController: nil)
|
||||||
|
|
||||||
|
show(vc, sender: self)
|
||||||
|
webfingerIndicatorView.stopAnimating()
|
||||||
|
case let .url(url):
|
||||||
|
open(url: url, identityContext: viewModel.identityContext)
|
||||||
|
webfingerIndicatorView.stopAnimating()
|
||||||
|
case .webfingerStart:
|
||||||
|
webfingerIndicatorView.startAnimating()
|
||||||
|
case .webfingerEnd:
|
||||||
|
webfingerIndicatorView.stopAnimating()
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private extension ExploreViewController {
|
private extension ExploreViewController {
|
||||||
static let bottomInset: CGFloat = .newStatusButtonDimension + .defaultSpacing * 4
|
static let bottomInset: CGFloat = .newStatusButtonDimension + .defaultSpacing * 4
|
||||||
|
|
||||||
|
@ -152,20 +199,4 @@ private extension ExploreViewController {
|
||||||
handle(navigation: navigation)
|
handle(navigation: navigation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle(navigation: Navigation) {
|
|
||||||
switch navigation {
|
|
||||||
case let .collection(collectionService):
|
|
||||||
let vc = TableViewController(
|
|
||||||
viewModel: CollectionItemsViewModel(
|
|
||||||
collectionService: collectionService,
|
|
||||||
identityContext: viewModel.identityContext),
|
|
||||||
rootViewModel: rootViewModel,
|
|
||||||
parentNavigationController: nil)
|
|
||||||
|
|
||||||
show(vc, sender: self)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ final class MainNavigationViewController: UITabBarController {
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
viewModel.navigations
|
viewModel.navigations
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] in self?.handle(navigation: $0) }
|
.sink { [weak self] in self?.handle(navigation: $0) }
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
@ -78,6 +79,30 @@ extension MainNavigationViewController: UITabBarControllerDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension MainNavigationViewController: NavigationHandling {
|
||||||
|
func handle(navigation: Navigation) {
|
||||||
|
switch navigation {
|
||||||
|
case .notification:
|
||||||
|
let index = NavigationViewModel.Tab.notifications.rawValue
|
||||||
|
|
||||||
|
guard let viewControllers = viewControllers,
|
||||||
|
viewControllers.count > index,
|
||||||
|
let notificationsNavigationController = viewControllers[index] as? UINavigationController,
|
||||||
|
let notificationsViewController =
|
||||||
|
notificationsNavigationController.viewControllers.first as? NotificationsViewController
|
||||||
|
else { break }
|
||||||
|
|
||||||
|
selectedIndex = index
|
||||||
|
notificationsNavigationController.popToRootViewController(animated: false)
|
||||||
|
notificationsViewController.handle(navigation: navigation)
|
||||||
|
default:
|
||||||
|
((selectedViewController as? UINavigationController)?
|
||||||
|
.topViewController as? NavigationHandling)?
|
||||||
|
.handle(navigation: navigation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private extension MainNavigationViewController {
|
private extension MainNavigationViewController {
|
||||||
static let secondaryNavigationViewTag = UUID().hashValue
|
static let secondaryNavigationViewTag = UUID().hashValue
|
||||||
static let newStatusViewTag = UUID().hashValue
|
static let newStatusViewTag = UUID().hashValue
|
||||||
|
@ -211,42 +236,4 @@ private extension MainNavigationViewController {
|
||||||
dismiss(animated: true)
|
dismiss(animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle(navigation: Navigation) {
|
|
||||||
switch navigation {
|
|
||||||
case let .collection(collectionService):
|
|
||||||
let vc = TableViewController(
|
|
||||||
viewModel: CollectionItemsViewModel(
|
|
||||||
collectionService: collectionService,
|
|
||||||
identityContext: viewModel.identityContext),
|
|
||||||
rootViewModel: rootViewModel)
|
|
||||||
|
|
||||||
selectedViewController?.show(vc, sender: self)
|
|
||||||
case let .profile(profileService):
|
|
||||||
let vc = ProfileViewController(
|
|
||||||
viewModel: ProfileViewModel(
|
|
||||||
profileService: profileService,
|
|
||||||
identityContext: viewModel.identityContext),
|
|
||||||
rootViewModel: rootViewModel,
|
|
||||||
identityContext: viewModel.identityContext,
|
|
||||||
parentNavigationController: nil)
|
|
||||||
|
|
||||||
selectedViewController?.show(vc, sender: self)
|
|
||||||
case .notification:
|
|
||||||
let index = NavigationViewModel.Tab.notifications.rawValue
|
|
||||||
|
|
||||||
guard let viewControllers = viewControllers,
|
|
||||||
viewControllers.count > index,
|
|
||||||
let notificationsNavigationController = viewControllers[index] as? UINavigationController,
|
|
||||||
let notificationsViewController =
|
|
||||||
notificationsNavigationController.viewControllers.first as? NotificationsViewController
|
|
||||||
else { break }
|
|
||||||
|
|
||||||
selectedIndex = index
|
|
||||||
notificationsNavigationController.popToRootViewController(animated: false)
|
|
||||||
notificationsViewController.handle(navigation: navigation)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ final class NotificationsViewController: UIPageViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationsViewController {
|
extension NotificationsViewController: NavigationHandling {
|
||||||
func handle(navigation: Navigation) {
|
func handle(navigation: Navigation) {
|
||||||
switch navigation {
|
switch navigation {
|
||||||
case .notification:
|
case .notification:
|
||||||
|
@ -81,7 +81,7 @@ extension NotificationsViewController {
|
||||||
setViewControllers([firstViewController], direction: .reverse, animated: false)
|
setViewControllers([firstViewController], direction: .reverse, animated: false)
|
||||||
firstViewController.handle(navigation: navigation)
|
firstViewController.handle(navigation: navigation)
|
||||||
default:
|
default:
|
||||||
break
|
(viewControllers?.first as? TableViewController)?.handle(navigation: navigation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import AVKit
|
import AVKit
|
||||||
import Combine
|
import Combine
|
||||||
import Mastodon
|
import Mastodon
|
||||||
import SafariServices
|
|
||||||
import SDWebImage
|
import SDWebImage
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import ViewModels
|
import ViewModels
|
||||||
|
@ -257,7 +256,9 @@ extension TableViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TableViewController: NavigationHandling {
|
||||||
func handle(navigation: Navigation) {
|
func handle(navigation: Navigation) {
|
||||||
switch navigation {
|
switch navigation {
|
||||||
case let .collection(collectionService):
|
case let .collection(collectionService):
|
||||||
|
@ -273,6 +274,8 @@ extension TableViewController {
|
||||||
} else {
|
} else {
|
||||||
show(vc, sender: self)
|
show(vc, sender: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webfingerIndicatorView.stopAnimating()
|
||||||
case let .profile(profileService):
|
case let .profile(profileService):
|
||||||
let vc = ProfileViewController(
|
let vc = ProfileViewController(
|
||||||
viewModel: ProfileViewModel(
|
viewModel: ProfileViewModel(
|
||||||
|
@ -287,10 +290,13 @@ extension TableViewController {
|
||||||
} else {
|
} else {
|
||||||
show(vc, sender: self)
|
show(vc, sender: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webfingerIndicatorView.stopAnimating()
|
||||||
case let .notification(notificationService):
|
case let .notification(notificationService):
|
||||||
navigate(toNotification: notificationService.notification)
|
navigate(toNotification: notificationService.notification)
|
||||||
case let .url(url):
|
case let .url(url):
|
||||||
open(url: url)
|
open(url: url, identityContext: viewModel.identityContext)
|
||||||
|
webfingerIndicatorView.stopAnimating()
|
||||||
case .searchScope:
|
case .searchScope:
|
||||||
break
|
break
|
||||||
case .webfingerStart:
|
case .webfingerStart:
|
||||||
|
@ -562,26 +568,6 @@ private extension TableViewController {
|
||||||
viewModel.select(indexPath: indexPath)
|
viewModel.select(indexPath: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func open(url: URL) {
|
|
||||||
func openWithRegardToBrowserSetting(url: URL) {
|
|
||||||
if viewModel.identityContext.appPreferences.openLinksInDefaultBrowser || !url.isHTTPURL {
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
} else {
|
|
||||||
present(SFSafariViewController(url: url), animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if viewModel.identityContext.appPreferences.useUniversalLinks {
|
|
||||||
UIApplication.shared.open(url, options: [.universalLinksOnly: true]) { success in
|
|
||||||
if !success {
|
|
||||||
openWithRegardToBrowserSetting(url: url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
openWithRegardToBrowserSetting(url: url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func present(attachmentViewModel: AttachmentViewModel, statusViewModel: StatusViewModel) {
|
func present(attachmentViewModel: AttachmentViewModel, statusViewModel: StatusViewModel) {
|
||||||
switch attachmentViewModel.attachment.type {
|
switch attachmentViewModel.attachment.type {
|
||||||
case .audio, .video:
|
case .audio, .video:
|
||||||
|
|
|
@ -113,3 +113,9 @@ extension TimelinesViewController: ScrollableToTop {
|
||||||
(viewControllers?.first as? TableViewController)?.scrollToTop(animated: animated)
|
(viewControllers?.first as? TableViewController)?.scrollToTop(animated: animated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension TimelinesViewController: NavigationHandling {
|
||||||
|
func handle(navigation: Navigation) {
|
||||||
|
(viewControllers?.first as? TableViewController)?.handle(navigation: navigation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -130,6 +130,14 @@ public extension NavigationViewModel {
|
||||||
titleComponents: ["preferences.blocked-users"])))
|
titleComponents: ["preferences.blocked-users"])))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func navigateToOfficialAccount() {
|
||||||
|
presentingSecondaryNavigation = false
|
||||||
|
presentedNewStatusViewModel = nil
|
||||||
|
identityContext.service.navigationService.item(url: Self.officialAccountURL)
|
||||||
|
.sink { [weak self] in self?.navigationsSubject.send($0) }
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
func navigate(pushNotification: PushNotification) {
|
func navigate(pushNotification: PushNotification) {
|
||||||
switch pushNotification.notificationType {
|
switch pushNotification.notificationType {
|
||||||
case .followRequest:
|
case .followRequest:
|
||||||
|
@ -184,3 +192,7 @@ public extension NavigationViewModel {
|
||||||
return conversationsViewModel
|
return conversationsViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extension NavigationViewModel {
|
||||||
|
static let officialAccountURL = URL(string: "https://mastodon.social/@metabolist")!
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright © 2021 Metabolist. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import ViewModels
|
||||||
|
|
||||||
|
protocol NavigationHandling {
|
||||||
|
func handle(navigation: Navigation)
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
// Copyright © 2021 Metabolist. All rights reserved.
|
// Copyright © 2021 Metabolist. All rights reserved.
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import ViewModels
|
||||||
|
|
||||||
struct AboutView: View {
|
struct AboutView: View {
|
||||||
|
@StateObject var viewModel: NavigationViewModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Form {
|
Form {
|
||||||
Section {
|
Section {
|
||||||
|
@ -14,6 +17,24 @@ struct AboutView: View {
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .center)
|
.frame(maxWidth: .infinity, alignment: .center)
|
||||||
|
Section(header: Text("about.made-by-metabolist")) {
|
||||||
|
Button {
|
||||||
|
viewModel.navigateToOfficialAccount()
|
||||||
|
} label: {
|
||||||
|
Label {
|
||||||
|
Text("about.official-account").foregroundColor(.primary)
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "checkmark.seal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Link(destination: Self.websiteURL) {
|
||||||
|
Label {
|
||||||
|
Text("about.website").foregroundColor(.primary)
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "link")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Section {
|
Section {
|
||||||
NavigationLink(
|
NavigationLink(
|
||||||
destination: AcknowledgmentsView()) {
|
destination: AcknowledgmentsView()) {
|
||||||
|
@ -26,6 +47,7 @@ struct AboutView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension AboutView {
|
private extension AboutView {
|
||||||
|
static let websiteURL = URL(string: "https://metabolist.org")!
|
||||||
static var version: String {
|
static var version: String {
|
||||||
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
|
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""
|
||||||
}
|
}
|
||||||
|
@ -40,7 +62,7 @@ import PreviewViewModels
|
||||||
|
|
||||||
struct AboutView_Previews: PreviewProvider {
|
struct AboutView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
AboutView()
|
AboutView(viewModel: NavigationViewModel(identityContext: .preview))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,7 +70,7 @@ struct SecondaryNavigationView: View {
|
||||||
Label("secondary-navigation.preferences", systemImage: "gear")
|
Label("secondary-navigation.preferences", systemImage: "gear")
|
||||||
}
|
}
|
||||||
NavigationLink(
|
NavigationLink(
|
||||||
destination: AboutView()
|
destination: AboutView(viewModel: viewModel)
|
||||||
.environmentObject(rootViewModel)) {
|
.environmentObject(rootViewModel)) {
|
||||||
Label("secondary-navigation.about", systemImage: "info.circle")
|
Label("secondary-navigation.about", systemImage: "info.circle")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue