Merge pull request #449 from mastodon/feature-following-indicator
Add follows you indicator. resolve #397
This commit is contained in:
commit
08d55dd419
|
@ -24,17 +24,17 @@
|
||||||
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>11</integer>
|
<integer>12</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - Release.xcscheme_^#shared#^_</key>
|
<key>Mastodon - Release.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>4</integer>
|
<integer>5</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - Snapshot.xcscheme_^#shared#^_</key>
|
<key>Mastodon - Snapshot.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>6</integer>
|
<integer>7</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>Mastodon - ar.xcscheme</key>
|
<key>Mastodon - ar.xcscheme</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>30</integer>
|
<integer>23</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -129,12 +129,12 @@
|
||||||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>29</integer>
|
<integer>24</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>31</integer>
|
<integer>22</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
|
|
@ -88,6 +88,13 @@ extension ProfileHeaderView.ViewModel {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
// follows you
|
||||||
|
$relationshipActionOptionSet
|
||||||
|
.map { $0.contains(.followingBy) && !$0.contains(.isMyself) }
|
||||||
|
.sink { isFollowingBy in
|
||||||
|
view.followsYouBlurEffectView.isHidden = !isFollowingBy
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
// avatar
|
// avatar
|
||||||
Publishers.CombineLatest4(
|
Publishers.CombineLatest4(
|
||||||
$avatarImageURL,
|
$avatarImageURL,
|
||||||
|
@ -102,7 +109,7 @@ extension ProfileHeaderView.ViewModel {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
// blur
|
// blur for blocking & blockingBy
|
||||||
$relationshipActionOptionSet
|
$relationshipActionOptionSet
|
||||||
.map { $0.contains(.blocking) || $0.contains(.blockingBy) }
|
.map { $0.contains(.blocking) || $0.contains(.blockingBy) }
|
||||||
.sink { needsImageOverlayBlurred in
|
.sink { needsImageOverlayBlurred in
|
||||||
|
|
|
@ -71,6 +71,16 @@ final class ProfileHeaderView: UIView {
|
||||||
}()
|
}()
|
||||||
var bannerImageViewTopLayoutConstraint: NSLayoutConstraint!
|
var bannerImageViewTopLayoutConstraint: NSLayoutConstraint!
|
||||||
var bannerImageViewBottomLayoutConstraint: 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 avatarImageViewBackgroundView: UIView = {
|
||||||
let view = UIView()
|
let view = UIView()
|
||||||
|
@ -173,9 +183,6 @@ final class ProfileHeaderView: UIView {
|
||||||
button.titleLabel?.minimumScaleFactor = 0.5
|
button.titleLabel?.minimumScaleFactor = 0.5
|
||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// let bioContainerView = UIView()
|
|
||||||
// let fieldContainerStackView = UIStackView()
|
|
||||||
|
|
||||||
let bioMetaText: MetaText = {
|
let bioMetaText: MetaText = {
|
||||||
let metaText = MetaText()
|
let metaText = MetaText()
|
||||||
|
@ -262,7 +269,41 @@ extension ProfileHeaderView {
|
||||||
bannerImageViewOverlayVisualEffectView.trailingAnchor.constraint(equalTo: bannerImageView.trailingAnchor),
|
bannerImageViewOverlayVisualEffectView.trailingAnchor.constraint(equalTo: bannerImageView.trailingAnchor),
|
||||||
bannerImageViewOverlayVisualEffectView.bottomAnchor.constraint(equalTo: bannerImageView.bottomAnchor),
|
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
|
// avatar
|
||||||
avatarImageViewBackgroundView.translatesAutoresizingMaskIntoConstraints = false
|
avatarImageViewBackgroundView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
addSubview(avatarImageViewBackgroundView)
|
addSubview(avatarImageViewBackgroundView)
|
||||||
|
@ -406,6 +447,7 @@ extension ProfileHeaderView {
|
||||||
container.addArrangedSubview(bioMetaText.textView)
|
container.addArrangedSubview(bioMetaText.textView)
|
||||||
|
|
||||||
bringSubviewToFront(bannerContainerView)
|
bringSubviewToFront(bannerContainerView)
|
||||||
|
bringSubviewToFront(followsYouBlurEffectView)
|
||||||
bringSubviewToFront(avatarImageViewBackgroundView)
|
bringSubviewToFront(avatarImageViewBackgroundView)
|
||||||
|
|
||||||
statusDashboardView.delegate = self
|
statusDashboardView.delegate = self
|
||||||
|
|
|
@ -584,6 +584,22 @@ extension ProfileViewController: TabBarPagerDelegate {
|
||||||
progress = 0
|
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
|
// setup titleView offset and fade avatar
|
||||||
profileHeaderViewController.updateHeaderScrollProgress(progress, throttle: throttle)
|
profileHeaderViewController.updateHeaderScrollProgress(progress, throttle: throttle)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue