diff --git a/Localization/app.json b/Localization/app.json
index 2a8634a67..93c3f9955 100644
--- a/Localization/app.json
+++ b/Localization/app.json
@@ -417,6 +417,9 @@
}
},
"profile": {
+ "header": {
+ "follows_you": "Follows You"
+ },
"dashboard": {
"posts": "posts",
"following": "following",
diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index 1c922a0b5..10b782b15 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -24,17 +24,17 @@
Mastodon - RTL.xcscheme_^#shared#^_
orderHint
- 11
+ 12
Mastodon - Release.xcscheme_^#shared#^_
orderHint
- 4
+ 5
Mastodon - Snapshot.xcscheme_^#shared#^_
orderHint
- 6
+ 7
Mastodon - ar.xcscheme
@@ -114,7 +114,7 @@
MastodonIntent.xcscheme_^#shared#^_
orderHint
- 30
+ 23
MastodonIntents.xcscheme_^#shared#^_
@@ -129,12 +129,12 @@
NotificationService.xcscheme_^#shared#^_
orderHint
- 29
+ 24
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 31
+ 22
SuppressBuildableAutocreation
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift
index 808e1d7ba..b57bf95a5 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift
@@ -88,6 +88,13 @@ extension ProfileHeaderView.ViewModel {
)
}
.store(in: &disposeBag)
+ // follows you
+ $relationshipActionOptionSet
+ .map { $0.contains(.followingBy) && !$0.contains(.isMyself) }
+ .sink { isFollowingBy in
+ view.followsYouBlurEffectView.isHidden = !isFollowingBy
+ }
+ .store(in: &disposeBag)
// avatar
Publishers.CombineLatest4(
$avatarImageURL,
@@ -102,7 +109,7 @@ extension ProfileHeaderView.ViewModel {
))
}
.store(in: &disposeBag)
- // blur
+ // blur for blocking & blockingBy
$relationshipActionOptionSet
.map { $0.contains(.blocking) || $0.contains(.blockingBy) }
.sink { needsImageOverlayBlurred in
diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
index 7257333d0..d99b90bc4 100644
--- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
+++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift
@@ -71,6 +71,16 @@ final class ProfileHeaderView: UIView {
}()
var bannerImageViewTopLayoutConstraint: NSLayoutConstraint!
var bannerImageViewBottomLayoutConstraint: NSLayoutConstraint!
+
+ let followsYouBlurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
+ let followsYouVibrantEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .regular), style: .label))
+ let followsYouLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.systemFont(ofSize: 15, weight: .regular)
+ label.text = "Follows You" // TODO: i18n
+ return label
+ }()
+ let followsYouMaskView = UIView()
let avatarImageViewBackgroundView: UIView = {
let view = UIView()
@@ -173,9 +183,6 @@ final class ProfileHeaderView: UIView {
button.titleLabel?.minimumScaleFactor = 0.5
return button
}()
-
- // let bioContainerView = UIView()
- // let fieldContainerStackView = UIStackView()
let bioMetaText: MetaText = {
let metaText = MetaText()
@@ -262,7 +269,41 @@ extension ProfileHeaderView {
bannerImageViewOverlayVisualEffectView.trailingAnchor.constraint(equalTo: bannerImageView.trailingAnchor),
bannerImageViewOverlayVisualEffectView.bottomAnchor.constraint(equalTo: bannerImageView.bottomAnchor),
])
+
+ // follows you
+ followsYouBlurEffectView.translatesAutoresizingMaskIntoConstraints = false
+ addSubview(followsYouBlurEffectView)
+ NSLayoutConstraint.activate([
+ layoutMarginsGuide.trailingAnchor.constraint(equalTo: followsYouBlurEffectView.trailingAnchor),
+ bannerContainerView.bottomAnchor.constraint(equalTo: followsYouBlurEffectView.bottomAnchor, constant: 16),
+ ])
+ followsYouBlurEffectView.layer.masksToBounds = true
+ followsYouBlurEffectView.layer.cornerRadius = 8
+ followsYouBlurEffectView.layer.cornerCurve = .continuous
+ followsYouBlurEffectView.isHidden = true
+ followsYouVibrantEffectView.translatesAutoresizingMaskIntoConstraints = false
+ followsYouBlurEffectView.contentView.addSubview(followsYouVibrantEffectView)
+ NSLayoutConstraint.activate([
+ followsYouVibrantEffectView.topAnchor.constraint(equalTo: followsYouBlurEffectView.topAnchor),
+ followsYouVibrantEffectView.leadingAnchor.constraint(equalTo: followsYouBlurEffectView.leadingAnchor),
+ followsYouVibrantEffectView.trailingAnchor.constraint(equalTo: followsYouBlurEffectView.trailingAnchor),
+ followsYouVibrantEffectView.bottomAnchor.constraint(equalTo: followsYouBlurEffectView.bottomAnchor),
+ ])
+
+ followsYouLabel.translatesAutoresizingMaskIntoConstraints = false
+ followsYouVibrantEffectView.contentView.addSubview(followsYouLabel)
+ NSLayoutConstraint.activate([
+ followsYouLabel.topAnchor.constraint(equalTo: followsYouVibrantEffectView.topAnchor, constant: 4),
+ followsYouLabel.leadingAnchor.constraint(equalTo: followsYouVibrantEffectView.leadingAnchor, constant: 6),
+ followsYouVibrantEffectView.trailingAnchor.constraint(equalTo: followsYouLabel.trailingAnchor, constant: 6),
+ followsYouVibrantEffectView.bottomAnchor.constraint(equalTo: followsYouLabel.bottomAnchor, constant: 4),
+ ])
+
+ followsYouMaskView.frame = CGRect(x: 0, y: 0, width: 1000, height: 1000)
+ followsYouMaskView.backgroundColor = .red
+ followsYouBlurEffectView.mask = followsYouMaskView
+
// avatar
avatarImageViewBackgroundView.translatesAutoresizingMaskIntoConstraints = false
addSubview(avatarImageViewBackgroundView)
@@ -406,6 +447,7 @@ extension ProfileHeaderView {
container.addArrangedSubview(bioMetaText.textView)
bringSubviewToFront(bannerContainerView)
+ bringSubviewToFront(followsYouBlurEffectView)
bringSubviewToFront(avatarImageViewBackgroundView)
statusDashboardView.delegate = self
diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift
index 6a51ff599..4c77a4458 100644
--- a/Mastodon/Scene/Profile/ProfileViewController.swift
+++ b/Mastodon/Scene/Profile/ProfileViewController.swift
@@ -584,6 +584,22 @@ extension ProfileViewController: TabBarPagerDelegate {
progress = 0
}
+ // setup follows you mask
+ // 1. set mask size
+ profileHeaderViewController.profileHeaderView.followsYouMaskView.frame = profileHeaderViewController.profileHeaderView.followsYouBlurEffectView.bounds
+ // 2. check follows you view overflow navigation bar or not
+ let followsYouBlurEffectViewInWindow = profileHeaderViewController.profileHeaderView.convert(
+ profileHeaderViewController.profileHeaderView.followsYouBlurEffectView.frame,
+ to: nil
+ )
+ if followsYouBlurEffectViewInWindow.minY < tabBarPagerController.containerScrollView.safeAreaInsets.top {
+ let offestY = tabBarPagerController.containerScrollView.safeAreaInsets.top - followsYouBlurEffectViewInWindow.minY
+ let height = profileHeaderViewController.profileHeaderView.followsYouMaskView.frame.height
+ profileHeaderViewController.profileHeaderView.followsYouMaskView.frame.origin.y = min(offestY, height)
+ } else {
+ profileHeaderViewController.profileHeaderView.followsYouMaskView.frame.origin.y = .zero
+ }
+
// setup titleView offset and fade avatar
profileHeaderViewController.updateHeaderScrollProgress(progress, throttle: throttle)