Merge branch 'develop' into feature/profile
This commit is contained in:
commit
bd89b19724
|
@ -172,6 +172,8 @@
|
||||||
"title": "Some ground rules.",
|
"title": "Some ground rules.",
|
||||||
"subtitle": "These rules are set by the admins of %s.",
|
"subtitle": "These rules are set by the admins of %s.",
|
||||||
"prompt": "By continuing, you're subject to the terms of service and privacy policy for %s.",
|
"prompt": "By continuing, you're subject to the terms of service and privacy policy for %s.",
|
||||||
|
"terms_of_service": "terms of service",
|
||||||
|
"privacy_policy": "privacy policy",
|
||||||
"button": {
|
"button": {
|
||||||
"confirm": "I Agree"
|
"confirm": "I Agree"
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,8 @@
|
||||||
2DF75BB925D1474100694EC8 /* ManagedObjectObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF75BB825D1474100694EC8 /* ManagedObjectObserver.swift */; };
|
2DF75BB925D1474100694EC8 /* ManagedObjectObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF75BB825D1474100694EC8 /* ManagedObjectObserver.swift */; };
|
||||||
2DF75BC725D1475D00694EC8 /* ManagedObjectContextObjectsDidChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF75BC625D1475D00694EC8 /* ManagedObjectContextObjectsDidChange.swift */; };
|
2DF75BC725D1475D00694EC8 /* ManagedObjectContextObjectsDidChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF75BC625D1475D00694EC8 /* ManagedObjectContextObjectsDidChange.swift */; };
|
||||||
2DFF41892614A4DC00F776A4 /* UIView+Constraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DFF41882614A4DC00F776A4 /* UIView+Constraint.swift */; };
|
2DFF41892614A4DC00F776A4 /* UIView+Constraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DFF41882614A4DC00F776A4 /* UIView+Constraint.swift */; };
|
||||||
|
5D0393902612D259007FE196 /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D03938F2612D259007FE196 /* WebViewController.swift */; };
|
||||||
|
5D0393962612D266007FE196 /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0393952612D266007FE196 /* WebViewModel.swift */; };
|
||||||
5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 5D526FE125BE9AC400460CB9 /* MastodonSDK */; };
|
5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 5D526FE125BE9AC400460CB9 /* MastodonSDK */; };
|
||||||
5DF1054125F886D400D6C0D4 /* ViedeoPlaybackService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DF1054025F886D400D6C0D4 /* ViedeoPlaybackService.swift */; };
|
5DF1054125F886D400D6C0D4 /* ViedeoPlaybackService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DF1054025F886D400D6C0D4 /* ViedeoPlaybackService.swift */; };
|
||||||
5DF1054725F8870E00D6C0D4 /* VideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DF1054625F8870E00D6C0D4 /* VideoPlayerViewModel.swift */; };
|
5DF1054725F8870E00D6C0D4 /* VideoPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DF1054625F8870E00D6C0D4 /* VideoPlayerViewModel.swift */; };
|
||||||
|
@ -437,6 +439,8 @@
|
||||||
3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.debug.xcconfig"; sourceTree = "<group>"; };
|
459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
5D03938F2612D259007FE196 /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = "<group>"; };
|
||||||
|
5D0393952612D266007FE196 /* WebViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewModel.swift; sourceTree = "<group>"; };
|
||||||
5DF1054025F886D400D6C0D4 /* ViedeoPlaybackService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViedeoPlaybackService.swift; sourceTree = "<group>"; };
|
5DF1054025F886D400D6C0D4 /* ViedeoPlaybackService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViedeoPlaybackService.swift; sourceTree = "<group>"; };
|
||||||
5DF1054625F8870E00D6C0D4 /* VideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerViewModel.swift; sourceTree = "<group>"; };
|
5DF1054625F8870E00D6C0D4 /* VideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayerViewModel.swift; sourceTree = "<group>"; };
|
||||||
5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayer.swift; sourceTree = "<group>"; };
|
5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayer.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1006,6 +1010,15 @@
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
5D03938E2612D200007FE196 /* Webview */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5D03938F2612D259007FE196 /* WebViewController.swift */,
|
||||||
|
5D0393952612D266007FE196 /* WebViewModel.swift */,
|
||||||
|
);
|
||||||
|
path = Webview;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
DB01409B25C40BB600F9F3CF /* Onboarding */ = {
|
DB01409B25C40BB600F9F3CF /* Onboarding */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1387,6 +1400,7 @@
|
||||||
DB8AF55525C1379F002E6C99 /* Scene */ = {
|
DB8AF55525C1379F002E6C99 /* Scene */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
5D03938E2612D200007FE196 /* Webview */,
|
||||||
2D7631A425C1532200929FB9 /* Share */,
|
2D7631A425C1532200929FB9 /* Share */,
|
||||||
DB8AF54E25C13703002E6C99 /* MainTab */,
|
DB8AF54E25C13703002E6C99 /* MainTab */,
|
||||||
DB01409B25C40BB600F9F3CF /* Onboarding */,
|
DB01409B25C40BB600F9F3CF /* Onboarding */,
|
||||||
|
@ -1995,6 +2009,7 @@
|
||||||
DBB525502611ED6D002F1F29 /* ProfileHeaderView.swift in Sources */,
|
DBB525502611ED6D002F1F29 /* ProfileHeaderView.swift in Sources */,
|
||||||
0FB3D33225E5F50E00AAD544 /* PickServerSearchCell.swift in Sources */,
|
0FB3D33225E5F50E00AAD544 /* PickServerSearchCell.swift in Sources */,
|
||||||
DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */,
|
DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */,
|
||||||
|
5D0393962612D266007FE196 /* WebViewModel.swift in Sources */,
|
||||||
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
|
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
|
||||||
DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */,
|
DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */,
|
||||||
DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */,
|
DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */,
|
||||||
|
@ -2082,6 +2097,7 @@
|
||||||
2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */,
|
2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */,
|
||||||
2D694A7425F9EB4E0038ADDC /* ContentWarningOverlayView.swift in Sources */,
|
2D694A7425F9EB4E0038ADDC /* ContentWarningOverlayView.swift in Sources */,
|
||||||
DB9A486C26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift in Sources */,
|
DB9A486C26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift in Sources */,
|
||||||
|
5D0393902612D259007FE196 /* WebViewController.swift in Sources */,
|
||||||
DB4481CC25EE2AFE00BEFB67 /* PollItem.swift in Sources */,
|
DB4481CC25EE2AFE00BEFB67 /* PollItem.swift in Sources */,
|
||||||
DB44767B260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift in Sources */,
|
DB44767B260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift in Sources */,
|
||||||
DB4563BD25E11A24004DA0B9 /* KeyboardResponderService.swift in Sources */,
|
DB4563BD25E11A24004DA0B9 /* KeyboardResponderService.swift in Sources */,
|
||||||
|
|
|
@ -46,6 +46,7 @@ extension SceneCoordinator {
|
||||||
case mastodonServerRules(viewModel: MastodonServerRulesViewModel)
|
case mastodonServerRules(viewModel: MastodonServerRulesViewModel)
|
||||||
case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel)
|
case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel)
|
||||||
case mastodonResendEmail(viewModel: MastodonResendEmailViewModel)
|
case mastodonResendEmail(viewModel: MastodonResendEmailViewModel)
|
||||||
|
case mastodonWebView(viewModel:WebViewModel)
|
||||||
|
|
||||||
// compose
|
// compose
|
||||||
case compose(viewModel: ComposeViewModel)
|
case compose(viewModel: ComposeViewModel)
|
||||||
|
@ -200,6 +201,10 @@ private extension SceneCoordinator {
|
||||||
let _viewController = MastodonResendEmailViewController()
|
let _viewController = MastodonResendEmailViewController()
|
||||||
_viewController.viewModel = viewModel
|
_viewController.viewModel = viewModel
|
||||||
viewController = _viewController
|
viewController = _viewController
|
||||||
|
case .mastodonWebView(let viewModel):
|
||||||
|
let _viewController = WebViewController()
|
||||||
|
_viewController.viewModel = viewModel
|
||||||
|
viewController = _viewController
|
||||||
case .compose(let viewModel):
|
case .compose(let viewModel):
|
||||||
let _viewController = ComposeViewController()
|
let _viewController = ComposeViewController()
|
||||||
_viewController.viewModel = viewModel
|
_viewController.viewModel = viewModel
|
||||||
|
|
|
@ -446,6 +446,8 @@ internal enum L10n {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal enum ServerRules {
|
internal enum ServerRules {
|
||||||
|
/// privacy policy
|
||||||
|
internal static let privacyPolicy = L10n.tr("Localizable", "Scene.ServerRules.PrivacyPolicy")
|
||||||
/// By continuing, you're subject to the terms of service and privacy policy for %@.
|
/// By continuing, you're subject to the terms of service and privacy policy for %@.
|
||||||
internal static func prompt(_ p1: Any) -> String {
|
internal static func prompt(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "Scene.ServerRules.Prompt", String(describing: p1))
|
return L10n.tr("Localizable", "Scene.ServerRules.Prompt", String(describing: p1))
|
||||||
|
@ -454,6 +456,8 @@ internal enum L10n {
|
||||||
internal static func subtitle(_ p1: Any) -> String {
|
internal static func subtitle(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "Scene.ServerRules.Subtitle", String(describing: p1))
|
return L10n.tr("Localizable", "Scene.ServerRules.Subtitle", String(describing: p1))
|
||||||
}
|
}
|
||||||
|
/// terms of service
|
||||||
|
internal static let termsOfService = L10n.tr("Localizable", "Scene.ServerRules.TermsOfService")
|
||||||
/// Some ground rules.
|
/// Some ground rules.
|
||||||
internal static let title = L10n.tr("Localizable", "Scene.ServerRules.Title")
|
internal static let title = L10n.tr("Localizable", "Scene.ServerRules.Title")
|
||||||
internal enum Button {
|
internal enum Button {
|
||||||
|
|
|
@ -143,8 +143,10 @@ tap the link to confirm your account.";
|
||||||
"Scene.ServerPicker.Title" = "Pick a Server,
|
"Scene.ServerPicker.Title" = "Pick a Server,
|
||||||
any server.";
|
any server.";
|
||||||
"Scene.ServerRules.Button.Confirm" = "I Agree";
|
"Scene.ServerRules.Button.Confirm" = "I Agree";
|
||||||
|
"Scene.ServerRules.PrivacyPolicy" = "privacy policy";
|
||||||
"Scene.ServerRules.Prompt" = "By continuing, you're subject to the terms of service and privacy policy for %@.";
|
"Scene.ServerRules.Prompt" = "By continuing, you're subject to the terms of service and privacy policy for %@.";
|
||||||
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";
|
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";
|
||||||
|
"Scene.ServerRules.TermsOfService" = "terms of service";
|
||||||
"Scene.ServerRules.Title" = "Some ground rules.";
|
"Scene.ServerRules.Title" = "Some ground rules.";
|
||||||
"Scene.Welcome.Slogan" = "Social networking
|
"Scene.Welcome.Slogan" = "Social networking
|
||||||
back in your hands.";
|
back in your hands.";
|
|
@ -8,6 +8,8 @@
|
||||||
import os.log
|
import os.log
|
||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
import Combine
|
||||||
|
import MastodonSDK
|
||||||
|
import SafariServices
|
||||||
|
|
||||||
final class MastodonServerRulesViewController: UIViewController, NeedsDependency {
|
final class MastodonServerRulesViewController: UIViewController, NeedsDependency {
|
||||||
|
|
||||||
|
@ -44,19 +46,20 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let bottonContainerView: UIView = {
|
let bottomContainerView: UIView = {
|
||||||
let view = UIView()
|
let view = UIView()
|
||||||
view.backgroundColor = Asset.Colors.Background.onboardingBackground.color
|
view.backgroundColor = Asset.Colors.Background.onboardingBackground.color
|
||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private(set) lazy var bottomPromptLabel: UILabel = {
|
private(set) lazy var bottomPromptTextView: UITextView = {
|
||||||
let label = UILabel()
|
let textView = UITextView()
|
||||||
label.font = .preferredFont(forTextStyle: .body)
|
textView.font = .preferredFont(forTextStyle: .body)
|
||||||
label.textColor = .label
|
textView.textColor = .label
|
||||||
label.text = L10n.Scene.ServerRules.prompt(viewModel.domain)
|
textView.isSelectable = true
|
||||||
label.numberOfLines = 0
|
textView.isEditable = false
|
||||||
return label
|
textView.backgroundColor = Asset.Colors.Background.onboardingBackground.color
|
||||||
|
return textView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let confirmButton: PrimaryActionButton = {
|
let confirmButton: PrimaryActionButton = {
|
||||||
|
@ -90,36 +93,39 @@ extension MastodonServerRulesViewController {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
setupOnboardingAppearance()
|
setupOnboardingAppearance()
|
||||||
|
configTextView()
|
||||||
|
|
||||||
defer { setupNavigationBarBackgroundView() }
|
defer { setupNavigationBarBackgroundView() }
|
||||||
|
|
||||||
bottonContainerView.translatesAutoresizingMaskIntoConstraints = false
|
bottomContainerView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(bottonContainerView)
|
view.addSubview(bottomContainerView)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
view.bottomAnchor.constraint(equalTo: bottonContainerView.bottomAnchor),
|
view.bottomAnchor.constraint(equalTo: bottomContainerView.bottomAnchor),
|
||||||
bottonContainerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
bottomContainerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||||
bottonContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
bottomContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||||
])
|
])
|
||||||
bottonContainerView.preservesSuperviewLayoutMargins = true
|
bottomContainerView.preservesSuperviewLayoutMargins = true
|
||||||
defer {
|
defer {
|
||||||
view.bringSubviewToFront(bottonContainerView)
|
view.bringSubviewToFront(bottomContainerView)
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmButton.translatesAutoresizingMaskIntoConstraints = false
|
confirmButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
bottonContainerView.addSubview(confirmButton)
|
bottomContainerView.addSubview(confirmButton)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
bottonContainerView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: confirmButton.bottomAnchor, constant: MastodonServerRulesViewController.viewBottomPaddingHeight),
|
bottomContainerView.layoutMarginsGuide.bottomAnchor.constraint(equalTo: confirmButton.bottomAnchor, constant: MastodonServerRulesViewController.viewBottomPaddingHeight),
|
||||||
confirmButton.leadingAnchor.constraint(equalTo: bottonContainerView.readableContentGuide.leadingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin),
|
confirmButton.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin),
|
||||||
bottonContainerView.readableContentGuide.trailingAnchor.constraint(equalTo: confirmButton.trailingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin),
|
bottomContainerView.readableContentGuide.trailingAnchor.constraint(equalTo: confirmButton.trailingAnchor, constant: MastodonServerRulesViewController.actionButtonMargin),
|
||||||
confirmButton.heightAnchor.constraint(equalToConstant: MastodonServerRulesViewController.actionButtonHeight).priority(.defaultHigh),
|
confirmButton.heightAnchor.constraint(equalToConstant: MastodonServerRulesViewController.actionButtonHeight).priority(.defaultHigh),
|
||||||
])
|
])
|
||||||
|
|
||||||
bottomPromptLabel.translatesAutoresizingMaskIntoConstraints = false
|
bottomPromptTextView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
bottonContainerView.addSubview(bottomPromptLabel)
|
bottomContainerView.addSubview(bottomPromptTextView)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
bottomPromptLabel.topAnchor.constraint(equalTo: bottonContainerView.topAnchor, constant: 20),
|
bottomPromptTextView.frameLayoutGuide.topAnchor.constraint(equalTo: bottomContainerView.topAnchor, constant: 20),
|
||||||
bottomPromptLabel.leadingAnchor.constraint(equalTo: bottonContainerView.readableContentGuide.leadingAnchor),
|
bottomPromptTextView.frameLayoutGuide.leadingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.leadingAnchor),
|
||||||
bottomPromptLabel.trailingAnchor.constraint(equalTo: bottonContainerView.readableContentGuide.trailingAnchor),
|
bottomPromptTextView.frameLayoutGuide.trailingAnchor.constraint(equalTo: bottomContainerView.readableContentGuide.trailingAnchor),
|
||||||
confirmButton.topAnchor.constraint(equalTo: bottomPromptLabel.bottomAnchor, constant: 20),
|
bottomPromptTextView.frameLayoutGuide.heightAnchor.constraint(equalToConstant: 50),
|
||||||
|
confirmButton.topAnchor.constraint(equalTo: bottomPromptTextView.frameLayoutGuide.bottomAnchor, constant: 20),
|
||||||
])
|
])
|
||||||
|
|
||||||
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
@ -169,8 +175,32 @@ extension MastodonServerRulesViewController {
|
||||||
extension MastodonServerRulesViewController {
|
extension MastodonServerRulesViewController {
|
||||||
func updateScrollViewContentInset() {
|
func updateScrollViewContentInset() {
|
||||||
view.layoutIfNeeded()
|
view.layoutIfNeeded()
|
||||||
scrollView.contentInset.bottom = bottonContainerView.frame.height
|
scrollView.contentInset.bottom = bottomContainerView.frame.height
|
||||||
scrollView.verticalScrollIndicatorInsets.bottom = bottonContainerView.frame.height
|
scrollView.verticalScrollIndicatorInsets.bottom = bottomContainerView.frame.height
|
||||||
|
}
|
||||||
|
|
||||||
|
func configTextView() {
|
||||||
|
let linkColor = Asset.Colors.Button.normal.color
|
||||||
|
|
||||||
|
let str = NSString(string: L10n.Scene.ServerRules.prompt(viewModel.domain))
|
||||||
|
let termsOfServiceRange = str.range(of: L10n.Scene.ServerRules.termsOfService)
|
||||||
|
let privacyRange = str.range(of: L10n.Scene.ServerRules.privacyPolicy)
|
||||||
|
let attributeString = NSMutableAttributedString(string: L10n.Scene.ServerRules.prompt(viewModel.domain), attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body), NSAttributedString.Key.foregroundColor: UIColor.label])
|
||||||
|
attributeString.addAttribute(.link, value: Mastodon.API.serverRulesURL(domain: viewModel.domain), range: termsOfServiceRange)
|
||||||
|
attributeString.addAttribute(.link, value: Mastodon.API.privacyURL(domain: viewModel.domain), range: privacyRange)
|
||||||
|
let linkAttributes = [NSAttributedString.Key.foregroundColor:linkColor]
|
||||||
|
bottomPromptTextView.attributedText = attributeString
|
||||||
|
bottomPromptTextView.linkTextAttributes = linkAttributes
|
||||||
|
bottomPromptTextView.delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MastodonServerRulesViewController: UITextViewDelegate {
|
||||||
|
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
|
||||||
|
let safariVC = SFSafariViewController(url: URL)
|
||||||
|
self.present(safariVC, animated: true, completion: nil)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,13 +35,16 @@ final class MastodonServerRulesViewModel {
|
||||||
|
|
||||||
var rulesAttributedString: NSAttributedString {
|
var rulesAttributedString: NSAttributedString {
|
||||||
let attributedString = NSMutableAttributedString(string: "\n")
|
let attributedString = NSMutableAttributedString(string: "\n")
|
||||||
|
let configuration = UIImage.SymbolConfiguration(font: .preferredFont(forTextStyle: .title3))
|
||||||
for (i, rule) in rules.enumerated() {
|
for (i, rule) in rules.enumerated() {
|
||||||
let index = String(i + 1)
|
let imageName = String(i + 1) + ".circle.fill"
|
||||||
let indexString = NSAttributedString(string: index + ". ", attributes: [
|
let image = UIImage(systemName: imageName, withConfiguration: configuration)!
|
||||||
NSAttributedString.Key.foregroundColor: UIColor.secondaryLabel
|
let attachment = NSTextAttachment()
|
||||||
])
|
attachment.image = image.withTintColor(.black)
|
||||||
let ruleString = NSAttributedString(string: rule.text + "\n\n")
|
let imageAttribute = NSAttributedString(attachment: attachment)
|
||||||
attributedString.append(indexString)
|
|
||||||
|
let ruleString = NSAttributedString(string: " " + rule.text + "\n\n")
|
||||||
|
attributedString.append(imageAttribute)
|
||||||
attributedString.append(ruleString)
|
attributedString.append(ruleString)
|
||||||
}
|
}
|
||||||
return attributedString
|
return attributedString
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
//
|
||||||
|
// WebViewController.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by xiaojian sun on 2021/3/30.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
import os.log
|
||||||
|
import UIKit
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
final class WebViewController: UIViewController, NeedsDependency {
|
||||||
|
|
||||||
|
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||||
|
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||||
|
|
||||||
|
var disposeBag = Set<AnyCancellable>()
|
||||||
|
var viewModel: WebViewModel!
|
||||||
|
|
||||||
|
let webView: WKWebView = {
|
||||||
|
let configuration = WKWebViewConfiguration()
|
||||||
|
configuration.processPool = WKProcessPool()
|
||||||
|
let webView = WKWebView(frame: .zero, configuration: configuration)
|
||||||
|
return webView
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", (#file as NSString).lastPathComponent, #line, #function)
|
||||||
|
|
||||||
|
// cleanup cookie
|
||||||
|
let httpCookieStore = webView.configuration.websiteDataStore.httpCookieStore
|
||||||
|
httpCookieStore.getAllCookies { cookies in
|
||||||
|
for cookie in cookies {
|
||||||
|
httpCookieStore.delete(cookie, completionHandler: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension WebViewController {
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(WebViewController.cancelBarButtonItemPressed(_:)))
|
||||||
|
|
||||||
|
webView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
view.addSubview(webView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
webView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||||
|
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||||
|
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||||
|
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||||
|
])
|
||||||
|
|
||||||
|
let request = URLRequest(url: viewModel.url)
|
||||||
|
webView.load(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension WebViewController {
|
||||||
|
@objc private func cancelBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||||
|
dismiss(animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// WebViewModel.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by xiaojian sun on 2021/3/30.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
final class WebViewModel {
|
||||||
|
public init(url: URL) {
|
||||||
|
self.url = url
|
||||||
|
}
|
||||||
|
|
||||||
|
// input
|
||||||
|
let url: URL
|
||||||
|
}
|
|
@ -89,6 +89,13 @@ extension Mastodon.API {
|
||||||
return URL(string: "https://" + domain + "/auth/confirmation/new")!
|
return URL(string: "https://" + domain + "/auth/confirmation/new")!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func serverRulesURL(domain: String) -> URL {
|
||||||
|
return URL(string: "https://" + domain + "/about/more")!
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func privacyURL(domain: String) -> URL {
|
||||||
|
return URL(string: "https://" + domain + "/terms")!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Mastodon.API {
|
extension Mastodon.API {
|
||||||
|
|
Loading…
Reference in New Issue