mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-25 09:41:00 +00:00
Bell button
This commit is contained in:
parent
2bab10b0fb
commit
5749225786
7 changed files with 77 additions and 8 deletions
|
@ -290,6 +290,12 @@ extension ContentDatabase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
migrator.registerMigration("1.0.0-notifying") { db in
|
||||||
|
try db.alter(table: "relationship") { t in
|
||||||
|
t.add(column: "notifying", .boolean)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return migrator
|
return migrator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"account.mute.confirm.duration" = "Duration";
|
"account.mute.confirm.duration" = "Duration";
|
||||||
"account.mute.target-%@" = "Mute %@";
|
"account.mute.target-%@" = "Mute %@";
|
||||||
"account.muted" = "Muted";
|
"account.muted" = "Muted";
|
||||||
|
"account.notify" = "Turn on notifications";
|
||||||
"account.reject-follow-request-button.accessibility-label" = "Reject follow request";
|
"account.reject-follow-request-button.accessibility-label" = "Reject follow request";
|
||||||
"account.request" = "Request";
|
"account.request" = "Request";
|
||||||
"account.request.cancel" = "Cancel follow request";
|
"account.request.cancel" = "Cancel follow request";
|
||||||
|
@ -51,6 +52,7 @@
|
||||||
"account.unfollow.confirm-%@" = "Unfollow %@?";
|
"account.unfollow.confirm-%@" = "Unfollow %@?";
|
||||||
"account.unmute" = "Unmute";
|
"account.unmute" = "Unmute";
|
||||||
"account.unmute.confirm-%@" = "Unmute %@?";
|
"account.unmute.confirm-%@" = "Unmute %@?";
|
||||||
|
"account.unnotify" = "Turn off notifications";
|
||||||
"activity.open-in-default-browser" = "Open in default browser";
|
"activity.open-in-default-browser" = "Open in default browser";
|
||||||
"add" = "Add";
|
"add" = "Add";
|
||||||
"apns-default-message" = "New notification";
|
"apns-default-message" = "New notification";
|
||||||
|
|
|
@ -11,6 +11,7 @@ public struct Relationship: Codable, Hashable {
|
||||||
public let muting: Bool
|
public let muting: Bool
|
||||||
@DecodableDefault.False public private(set) var mutingNotifications: Bool
|
@DecodableDefault.False public private(set) var mutingNotifications: Bool
|
||||||
@DecodableDefault.False public private(set) var showingReblogs: Bool
|
@DecodableDefault.False public private(set) var showingReblogs: Bool
|
||||||
|
public let notifying: Bool?
|
||||||
public let blocking: Bool
|
public let blocking: Bool
|
||||||
public let domainBlocking: Bool
|
public let domainBlocking: Bool
|
||||||
@DecodableDefault.False public private(set) var blockedBy: Bool
|
@DecodableDefault.False public private(set) var blockedBy: Bool
|
||||||
|
|
|
@ -5,7 +5,7 @@ import HTTP
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
public enum RelationshipEndpoint {
|
public enum RelationshipEndpoint {
|
||||||
case accountsFollow(id: Account.Id, showReblogs: Bool? = nil)
|
case accountsFollow(id: Account.Id, showReblogs: Bool? = nil, notify: Bool? = nil)
|
||||||
case accountsUnfollow(id: Account.Id)
|
case accountsUnfollow(id: Account.Id)
|
||||||
case accountsBlock(id: Account.Id)
|
case accountsBlock(id: Account.Id)
|
||||||
case accountsUnblock(id: Account.Id)
|
case accountsUnblock(id: Account.Id)
|
||||||
|
@ -32,7 +32,7 @@ extension RelationshipEndpoint: Endpoint {
|
||||||
|
|
||||||
public var pathComponentsInContext: [String] {
|
public var pathComponentsInContext: [String] {
|
||||||
switch self {
|
switch self {
|
||||||
case let .accountsFollow(id, _):
|
case let .accountsFollow(id, _, _):
|
||||||
return [id, "follow"]
|
return [id, "follow"]
|
||||||
case let .accountsUnfollow(id):
|
case let .accountsUnfollow(id):
|
||||||
return [id, "unfollow"]
|
return [id, "unfollow"]
|
||||||
|
@ -59,12 +59,18 @@ extension RelationshipEndpoint: Endpoint {
|
||||||
|
|
||||||
public var queryParameters: [URLQueryItem] {
|
public var queryParameters: [URLQueryItem] {
|
||||||
switch self {
|
switch self {
|
||||||
case let .accountsFollow(_, showReblogs):
|
case let .accountsFollow(_, showReblogs, notify):
|
||||||
|
var params = [URLQueryItem]()
|
||||||
|
|
||||||
if let showReblogs = showReblogs {
|
if let showReblogs = showReblogs {
|
||||||
return [URLQueryItem(name: "reblogs", value: String(showReblogs))]
|
params.append(URLQueryItem(name: "reblogs", value: String(showReblogs)))
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let notify = notify {
|
||||||
|
params.append(URLQueryItem(name: "notify", value: String(notify)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return params
|
||||||
default:
|
default:
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,14 @@ public extension AccountService {
|
||||||
relationshipAction(.accountsFollow(id: account.id, showReblogs: true))
|
relationshipAction(.accountsFollow(id: account.id, showReblogs: true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func notify() -> AnyPublisher<Never, Error> {
|
||||||
|
relationshipAction(.accountsFollow(id: account.id, notify: true))
|
||||||
|
}
|
||||||
|
|
||||||
|
func unnotify() -> AnyPublisher<Never, Error> {
|
||||||
|
relationshipAction(.accountsFollow(id: account.id, notify: false))
|
||||||
|
}
|
||||||
|
|
||||||
func block() -> AnyPublisher<Never, Error> {
|
func block() -> AnyPublisher<Never, Error> {
|
||||||
relationshipAction(.accountsBlock(id: account.id))
|
relationshipAction(.accountsBlock(id: account.id))
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -137,6 +137,14 @@ public extension AccountViewModel {
|
||||||
ignorableOutputEvent(accountService.showReblogs())
|
ignorableOutputEvent(accountService.showReblogs())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func notify() {
|
||||||
|
ignorableOutputEvent(accountService.notify())
|
||||||
|
}
|
||||||
|
|
||||||
|
func unnotify() {
|
||||||
|
ignorableOutputEvent(accountService.unnotify())
|
||||||
|
}
|
||||||
|
|
||||||
func confirmBlock() {
|
func confirmBlock() {
|
||||||
eventsSubject.send(Just(.confirmBlock(self)).setFailureType(to: Error.self).eraseToAnyPublisher())
|
eventsSubject.send(Just(.confirmBlock(self)).setFailureType(to: Error.self).eraseToAnyPublisher())
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ final class AccountHeaderView: UIView {
|
||||||
let relationshipButtonsStackView = UIStackView()
|
let relationshipButtonsStackView = UIStackView()
|
||||||
let followButton = UIButton(type: .system)
|
let followButton = UIButton(type: .system)
|
||||||
let unfollowButton = UIButton(type: .system)
|
let unfollowButton = UIButton(type: .system)
|
||||||
|
let notifyButton = UIButton()
|
||||||
|
let unnotifyButton = UIButton()
|
||||||
let displayNameLabel = AnimatedAttachmentLabel()
|
let displayNameLabel = AnimatedAttachmentLabel()
|
||||||
let accountStackView = UIStackView()
|
let accountStackView = UIStackView()
|
||||||
let accountLabel = UILabel()
|
let accountLabel = UILabel()
|
||||||
|
@ -69,6 +71,19 @@ final class AccountHeaderView: UIView {
|
||||||
comment: ""),
|
comment: ""),
|
||||||
for: .normal)
|
for: .normal)
|
||||||
|
|
||||||
|
if relationship.following, let notifying = relationship.notifying {
|
||||||
|
if notifying {
|
||||||
|
notifyButton.isHidden = true
|
||||||
|
unnotifyButton.isHidden = false
|
||||||
|
} else {
|
||||||
|
notifyButton.isHidden = false
|
||||||
|
unnotifyButton.isHidden = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notifyButton.isHidden = true
|
||||||
|
unnotifyButton.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
relationshipButtonsStackView.isHidden = false
|
relationshipButtonsStackView.isHidden = false
|
||||||
unavailableLabel.isHidden = !relationship.blockedBy
|
unavailableLabel.isHidden = !relationship.blockedBy
|
||||||
} else {
|
} else {
|
||||||
|
@ -201,7 +216,7 @@ final class AccountHeaderView: UIView {
|
||||||
override func layoutSubviews() {
|
override func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
for button in [followButton, unfollowButton] {
|
for button in [followButton, unfollowButton, notifyButton, unnotifyButton] {
|
||||||
let inset = (followButton.bounds.height - (button.titleLabel?.bounds.height ?? 0)) / 2
|
let inset = (followButton.bounds.height - (button.titleLabel?.bounds.height ?? 0)) / 2
|
||||||
|
|
||||||
button.contentEdgeInsets = .init(top: 0, left: inset, bottom: 0, right: inset)
|
button.contentEdgeInsets = .init(top: 0, left: inset, bottom: 0, right: inset)
|
||||||
|
@ -284,7 +299,7 @@ private extension AccountHeaderView {
|
||||||
relationshipButtonsStackView.spacing = .defaultSpacing
|
relationshipButtonsStackView.spacing = .defaultSpacing
|
||||||
relationshipButtonsStackView.addArrangedSubview(UIView())
|
relationshipButtonsStackView.addArrangedSubview(UIView())
|
||||||
|
|
||||||
for button in [followButton, unfollowButton] {
|
for button in [followButton, unfollowButton, notifyButton, unnotifyButton] {
|
||||||
relationshipButtonsStackView.addArrangedSubview(button)
|
relationshipButtonsStackView.addArrangedSubview(button)
|
||||||
button.titleLabel?.font = .preferredFont(forTextStyle: .headline)
|
button.titleLabel?.font = .preferredFont(forTextStyle: .headline)
|
||||||
button.titleLabel?.adjustsFontForContentSizeCategory = true
|
button.titleLabel?.adjustsFontForContentSizeCategory = true
|
||||||
|
@ -296,6 +311,7 @@ private extension AccountHeaderView {
|
||||||
systemName: "person.badge.plus",
|
systemName: "person.badge.plus",
|
||||||
withConfiguration: UIImage.SymbolConfiguration(scale: .small)),
|
withConfiguration: UIImage.SymbolConfiguration(scale: .small)),
|
||||||
for: .normal)
|
for: .normal)
|
||||||
|
followButton.isHidden = true
|
||||||
followButton.addAction(
|
followButton.addAction(
|
||||||
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.follow() },
|
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.follow() },
|
||||||
for: .touchUpInside)
|
for: .touchUpInside)
|
||||||
|
@ -306,10 +322,32 @@ private extension AccountHeaderView {
|
||||||
withConfiguration: UIImage.SymbolConfiguration(scale: .small)),
|
withConfiguration: UIImage.SymbolConfiguration(scale: .small)),
|
||||||
for: .normal)
|
for: .normal)
|
||||||
unfollowButton.setTitle(NSLocalizedString("account.unfollow", comment: ""), for: .normal)
|
unfollowButton.setTitle(NSLocalizedString("account.unfollow", comment: ""), for: .normal)
|
||||||
|
unfollowButton.isHidden = true
|
||||||
unfollowButton.addAction(
|
unfollowButton.addAction(
|
||||||
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.confirmUnfollow() },
|
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.confirmUnfollow() },
|
||||||
for: .touchUpInside)
|
for: .touchUpInside)
|
||||||
|
|
||||||
|
notifyButton.setImage(
|
||||||
|
UIImage(systemName: "bell",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: .large)),
|
||||||
|
for: .normal)
|
||||||
|
notifyButton.accessibilityLabel = NSLocalizedString("account.notify", comment: "")
|
||||||
|
notifyButton.tintColor = .secondaryLabel
|
||||||
|
notifyButton.isHidden = true
|
||||||
|
notifyButton.addAction(
|
||||||
|
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.notify() },
|
||||||
|
for: .touchUpInside)
|
||||||
|
|
||||||
|
unnotifyButton.setImage(
|
||||||
|
UIImage(systemName: "bell.fill",
|
||||||
|
withConfiguration: UIImage.SymbolConfiguration(scale: .large)),
|
||||||
|
for: .normal)
|
||||||
|
unnotifyButton.accessibilityLabel = NSLocalizedString("account.unnotify", comment: "")
|
||||||
|
unnotifyButton.isHidden = true
|
||||||
|
unnotifyButton.addAction(
|
||||||
|
UIAction { [weak self] _ in self?.viewModel.accountViewModel?.unnotify() },
|
||||||
|
for: .touchUpInside)
|
||||||
|
|
||||||
addSubview(baseStackView)
|
addSubview(baseStackView)
|
||||||
baseStackView.translatesAutoresizingMaskIntoConstraints = false
|
baseStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
baseStackView.axis = .vertical
|
baseStackView.axis = .vertical
|
||||||
|
|
Loading…
Reference in a new issue