add auto deletes subtitle on delete action in long press menu screen

pull/731/head
Ryan ZHAO 3 months ago
parent e9dd86bfc2
commit 68a8311166

@ -3,11 +3,19 @@
import UIKit
import SessionMessagingKit
import SessionUtilitiesKit
import SessionUIKit
extension ContextMenuVC {
struct ExpirationInfo {
let expiresStartedAtMs: Double?
let expiresInSeconds: TimeInterval?
}
struct Action {
let icon: UIImage?
let title: String
let expirationInfo: ExpirationInfo?
let themeColor: ThemeValue
let isEmojiAction: Bool
let isEmojiPlus: Bool
let isDismissAction: Bool
@ -19,6 +27,8 @@ extension ContextMenuVC {
init(
icon: UIImage? = nil,
title: String = "",
expirationInfo: ExpirationInfo? = nil,
themeColor: ThemeValue = .textPrimary,
isEmojiAction: Bool = false,
isEmojiPlus: Bool = false,
isDismissAction: Bool = false,
@ -27,6 +37,8 @@ extension ContextMenuVC {
) {
self.icon = icon
self.title = title
self.expirationInfo = expirationInfo
self.themeColor = themeColor
self.isEmojiAction = isEmojiAction
self.isEmojiPlus = isEmojiPlus
self.isDismissAction = isDismissAction
@ -84,6 +96,11 @@ extension ContextMenuVC {
return Action(
icon: UIImage(named: "ic_trash"),
title: "TXT_DELETE_TITLE".localized(),
expirationInfo: ExpirationInfo(
expiresStartedAtMs: cellViewModel.expiresStartedAtMs,
expiresInSeconds: cellViewModel.expiresInSeconds
),
themeColor: .danger,
accessibilityLabel: "Delete message"
) { delegate?.delete(cellViewModel, using: dependencies) }
}
@ -100,6 +117,7 @@ extension ContextMenuVC {
return Action(
icon: UIImage(named: "ic_block"),
title: "context_menu_ban_user".localized(),
themeColor: .danger,
accessibilityLabel: "Ban user"
) { delegate?.ban(cellViewModel, using: dependencies) }
}
@ -108,6 +126,7 @@ extension ContextMenuVC {
return Action(
icon: UIImage(named: "ic_block"),
title: "context_menu_ban_and_delete_all".localized(),
themeColor: .danger,
accessibilityLabel: "Ban user and delete"
) { delegate?.banAndDeleteAllMessages(cellViewModel, using: dependencies) }
}

@ -3,6 +3,7 @@
import UIKit
import SessionUIKit
import SessionUtilitiesKit
import SessionSnodeKit
extension ContextMenuVC {
final class ActionView: UIView {
@ -12,23 +13,32 @@ extension ContextMenuVC {
private let action: Action
private let dismiss: () -> Void
private var didTouchDownInside: Bool = false
private var timer: Timer?
// MARK: - UI
private let iconImageView: UIImageView = {
private lazy var iconImageView: UIImageView = {
let result: UIImageView = UIImageView()
result.contentMode = .center
result.themeTintColor = .textPrimary
result.themeTintColor = action.themeColor
result.set(.width, to: ActionView.iconImageViewSize)
result.set(.height, to: ActionView.iconImageViewSize)
return result
}()
private let titleLabel: UILabel = {
private lazy var titleLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.mediumFontSize)
result.themeTextColor = .textPrimary
result.themeTextColor = action.themeColor
return result
}()
private lazy var subtitleLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.miniFontSize)
result.themeTextColor = action.themeColor
return result
}()
@ -59,9 +69,18 @@ extension ContextMenuVC {
.resizedImage(to: CGSize(width: ActionView.iconSize, height: ActionView.iconSize))?
.withRenderingMode(.alwaysTemplate)
titleLabel.text = action.title
setUpSubtitle()
let labelContainer: UIView = UIView()
labelContainer.set(.width, greaterThanOrEqualTo: 115)
labelContainer.addSubview(titleLabel)
labelContainer.addSubview(subtitleLabel)
titleLabel.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing, UIView.VerticalEdge.top ], to: labelContainer)
subtitleLabel.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing, UIView.VerticalEdge.bottom ], to: labelContainer)
titleLabel.pin(.bottom, to: .top, of: subtitleLabel)
// Stack view
let stackView: UIStackView = UIStackView(arrangedSubviews: [ iconImageView, titleLabel ])
let stackView: UIStackView = UIStackView(arrangedSubviews: [ iconImageView, labelContainer ])
stackView.axis = .horizontal
stackView.spacing = Values.smallSpacing
stackView.alignment = .center
@ -82,11 +101,44 @@ extension ContextMenuVC {
addGestureRecognizer(tapGestureRecognizer)
}
private func setUpSubtitle() {
guard
let expiresInSeconds = self.action.expirationInfo?.expiresInSeconds,
let expiresStartedAtMs = self.action.expirationInfo?.expiresStartedAtMs
else {
subtitleLabel.isHidden = true
return
}
subtitleLabel.isHidden = false
let timeToExpireInSeconds: TimeInterval = (expiresStartedAtMs + expiresInSeconds * 1000 - Double(SnodeAPI.currentOffsetTimestampMs())) / 1000
subtitleLabel.text = "Auto-deletes in \(timeToExpireInSeconds.formatted(format: .twoUnits))"
timer = Timer.scheduledTimerOnMainThread(withTimeInterval: 1, repeats: true, block: { [weak self] _ in
let timeToExpireInSeconds: TimeInterval = (expiresStartedAtMs + expiresInSeconds * 1000 - Double(SnodeAPI.currentOffsetTimestampMs())) / 1000
if timeToExpireInSeconds <= 0 {
self?.dismissWithTimerInvalidationIfNeeded()
} else {
self?.subtitleLabel.text = "Auto-deletes in \(timeToExpireInSeconds.formatted(format: .twoUnits))"
}
})
}
override func removeFromSuperview() {
self.timer?.invalidate()
super.removeFromSuperview()
}
// MARK: - Interaction
private func dismissWithTimerInvalidationIfNeeded() {
self.timer?.invalidate()
dismiss()
}
@objc private func handleTap() {
action.work()
dismiss()
dismissWithTimerInvalidationIfNeeded()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

@ -251,6 +251,84 @@ public extension String {
)
)
}
}
case .twoUnits:
let seconds: Int = Int(duration.truncatingRemainder(dividingBy: 60))
let minutes: Int = Int((duration / 60).truncatingRemainder(dividingBy: 60))
let hours: Int = Int((duration / 3600).truncatingRemainder(dividingBy: 24))
let days: Int = Int((duration / 3600 / 24).truncatingRemainder(dividingBy: 7))
let weeks: Int = Int(duration / 3600 / 24 / 7)
guard weeks == 0 else {
return String(
format: "TIME_AMOUNT_WEEKS_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: weeks),
number: .none
)
) + " " + String(
format: "TIME_AMOUNT_DAYS_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: days),
number: .none
)
)
}
guard days == 0 else {
return String(
format: "TIME_AMOUNT_DAYS_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: days),
number: .none
)
) + " " + String(
format: "TIME_AMOUNT_HOURS_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: hours),
number: .none
)
)
}
guard hours == 0 else {
return String(
format: "TIME_AMOUNT_HOURS_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: hours),
number: .none
)
) + " " + String(
format: "TIME_AMOUNT_MINUTES_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: minutes),
number: .none
)
)
}
guard minutes == 0 else {
return String(
format: "TIME_AMOUNT_MINUTES_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: minutes),
number: .none
)
) + " " + String(
format: "TIME_AMOUNT_SECONDS_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: seconds),
number: .none
)
)
}
return String(
format: "TIME_AMOUNT_SECONDS_SHORT_FORMAT".localized(),
NumberFormatter.localizedString(
from: NSNumber(integerLiteral: seconds),
number: .none
)
)
}
}
}

@ -8,6 +8,7 @@ public extension TimeInterval {
case long
case hoursMinutesSeconds
case videoDuration
case twoUnits
}
func formatted(format: DurationFormat) -> String {

Loading…
Cancel
Save