Modernize "Group Link Promotion" screen.

This commit is contained in:
Igor Solomennikov
2025-10-27 22:12:10 -07:00
committed by GitHub
parent cc8d170a70
commit 04c7db77f9
4 changed files with 134 additions and 178 deletions

View File

@@ -348,7 +348,6 @@
348EE28E25B897BF00814FC2 /* CVMediaCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348EE28C25B897BF00814FC2 /* CVMediaCache.swift */; };
348EE28F25B897BF00814FC2 /* ReusableMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348EE28D25B897BF00814FC2 /* ReusableMediaView.swift */; };
3490D57D25ADDC2A00F5F96C /* GroupLinkPromotionActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3490D57C25ADDC2900F5F96C /* GroupLinkPromotionActionSheet.swift */; };
3490D57F25ADE49800F5F96C /* ActionSheetContentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3490D57E25ADE49800F5F96C /* ActionSheetContentBuilder.swift */; };
3491899B269CD68E008A18AF /* BlockingAnnouncementOnlyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3491899A269CD68D008A18AF /* BlockingAnnouncementOnlyView.swift */; };
349439D624360C30001045F7 /* AddGroupMembersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349439D524360C30001045F7 /* AddGroupMembersViewController.swift */; };
349439D824360D63001045F7 /* BaseGroupMemberViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349439D724360D63001045F7 /* BaseGroupMemberViewController.swift */; };
@@ -4144,7 +4143,6 @@
348EE28D25B897BF00814FC2 /* ReusableMediaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReusableMediaView.swift; sourceTree = "<group>"; };
348F2EAD1F0D21BC00D4ECE0 /* DeviceSleepManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceSleepManager.swift; sourceTree = "<group>"; };
3490D57C25ADDC2900F5F96C /* GroupLinkPromotionActionSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupLinkPromotionActionSheet.swift; sourceTree = "<group>"; };
3490D57E25ADE49800F5F96C /* ActionSheetContentBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetContentBuilder.swift; sourceTree = "<group>"; };
3491899A269CD68D008A18AF /* BlockingAnnouncementOnlyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockingAnnouncementOnlyView.swift; sourceTree = "<group>"; };
349439D524360C30001045F7 /* AddGroupMembersViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddGroupMembersViewController.swift; sourceTree = "<group>"; };
349439D724360D63001045F7 /* BaseGroupMemberViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseGroupMemberViewController.swift; sourceTree = "<group>"; };
@@ -8718,7 +8716,6 @@
349767DE25B8744600ECE1B0 /* Stickers */,
340FC897204DAC8D007AEB0F /* ThreadSettings */,
88A51B9825BA079500CDB45C /* Wallpapers */,
3490D57E25ADE49800F5F96C /* ActionSheetContentBuilder.swift */,
4C46361022EB98EC00185951 /* CameraFirstCaptureSendFlow.swift */,
348BB25C20A0C5530047AEC2 /* ContactShareViewHelper.swift */,
34E88D252098C5AE00A608F4 /* ContactViewController.swift */,
@@ -16750,7 +16747,6 @@
files = (
D91174562E8F35C1009EB756 /* AccountEntropyPoolTextView.swift in Sources */,
88E728FF25F0241100A2E4A4 /* AccountSettingsViewController.swift in Sources */,
3490D57F25ADE49800F5F96C /* ActionSheetContentBuilder.swift in Sources */,
349439D624360C30001045F7 /* AddGroupMembersViewController.swift in Sources */,
8835DE03230DEC6A00DC6B66 /* AddToBlockListViewController.swift in Sources */,
882BDAAE249050F000C14587 /* AddToGroupViewController.swift in Sources */,

View File

@@ -1,60 +0,0 @@
//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import SignalUI
import UIKit
public class ActionSheetContentBuilder {
var subviews = [UIView]()
func buildLabel(text: String? = nil,
textColor: UIColor? = nil,
font: UIFont? = nil,
textAlignment: NSTextAlignment = .natural) -> UILabel {
let label = UILabel()
label.text = text
label.textColor = textColor ?? Theme.primaryTextColor
label.font = font ?? UIFont.dynamicTypeBody
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.textAlignment = textAlignment
return label
}
func buildTitleLabel(text: String) -> UILabel {
buildLabel(text: text,
font: UIFont.dynamicTypeTitle2.semibold(),
textAlignment: .center)
}
func add(_ subview: UIView) {
subviews.append(subview)
}
func addVerticalSpacer(height: CGFloat) {
add(UIView.spacer(withHeight: height))
}
func addBottomButton(
title: String,
titleColor: UIColor,
backgroundColor: UIColor,
target: Any,
selector: Selector
) {
let buttonFont = UIFont.dynamicTypeHeadlineClamped
let buttonHeight = OWSFlatButton.heightForFont(buttonFont)
let upgradeButton = OWSFlatButton.button(title: title,
font: buttonFont,
titleColor: titleColor,
backgroundColor: backgroundColor,
target: target,
selector: selector)
upgradeButton.autoSetDimension(.height, toSize: buttonHeight)
subviews.append(upgradeButton)
}
}

View File

@@ -14,16 +14,141 @@ public class GroupLinkPromotionActionSheet: UIView {
weak var actionSheetController: ActionSheetController?
private let stackView = UIStackView()
init(groupThread: TSGroupThread,
conversationViewController: ConversationViewController) {
init(groupThread: TSGroupThread, conversationViewController: ConversationViewController) {
self.groupThread = groupThread
self.conversationViewController = conversationViewController
super.init(frame: .zero)
configure()
let titleLabel = UILabel()
titleLabel.text = OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_TITLE",
comment: "Title for the 'group link promotion' alert view.")
titleLabel.textColor = .Signal.label
titleLabel.font = .dynamicTypeHeadline
titleLabel.textAlignment = .natural
let subtitleLabel = UILabel()
subtitleLabel.text = OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_SUBTITLE",
comment: "Subtitle for the 'group link promotion' alert view.")
subtitleLabel.textColor = .Signal.label
subtitleLabel.font = .dynamicTypeBody
subtitleLabel.textAlignment = .natural
subtitleLabel.numberOfLines = 0
subtitleLabel.lineBreakMode = .byWordWrapping
let topStack = UIStackView(arrangedSubviews: [ titleLabel, subtitleLabel ])
topStack.axis = .vertical
topStack.spacing = 4
topStack.isLayoutMarginsRelativeArrangement = true
topStack.directionalLayoutMargins = .init(top: 14, leading: 14, bottom: 20, trailing: 14)
topStack.translatesAutoresizingMaskIntoConstraints = false
addSubview(topStack)
addConstraints([
topStack.topAnchor.constraint(equalTo: topAnchor),
topStack.leadingAnchor.constraint(equalTo: leadingAnchor),
topStack.trailingAnchor.constraint(equalTo: trailingAnchor),
])
let buttonStackTopAnchor: NSLayoutYAxisAnchor
if isGroupLinkEnabled {
buttonStackTopAnchor = topStack.bottomAnchor
} else {
let switchLabel = UILabel()
switchLabel.text = OWSLocalizedString(
"GROUP_LINK_PROMOTION_ALERT_APPROVE_NEW_MEMBERS_SWITCH",
comment: "Label for the 'approve new group members' switch."
)
switchLabel.setCompressionResistanceHorizontalHigh()
memberApprovalSwitch.setCompressionResistanceHorizontalHigh()
let memberApprovalStack = UIStackView(arrangedSubviews: [
switchLabel,
.hStretchingSpacer(),
memberApprovalSwitch,
])
memberApprovalStack.axis = .horizontal
memberApprovalStack.alignment = .center
memberApprovalStack.distribution = .fill
memberApprovalStack.layoutMargins = UIEdgeInsets(hMargin: 16, vMargin: 10)
memberApprovalStack.isLayoutMarginsRelativeArrangement = true
memberApprovalStack.addBackgroundView(
withBackgroundColor: .Signal.secondaryGroupedBackground,
cornerRadius: OWSTableViewController2.cellRounding
)
let captionLabel = UILabel()
captionLabel.text = OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_APPROVE_NEW_MEMBERS_EXPLANATION",
comment: "Explanation of the 'approve new group members' switch.")
captionLabel.textColor = .Signal.secondaryLabel
captionLabel.font = .dynamicTypeFootnote
captionLabel.numberOfLines = 0
captionLabel.lineBreakMode = .byWordWrapping
captionLabel.translatesAutoresizingMaskIntoConstraints = false
let captionContainer = UIView()
captionContainer.directionalLayoutMargins = .init(top: 12, leading: 16, bottom: 12, trailing: 16)
captionContainer.addSubview(captionLabel)
captionContainer.addConstraints([
captionLabel.topAnchor.constraint(equalTo: captionContainer.layoutMarginsGuide.topAnchor),
captionLabel.leadingAnchor.constraint(equalTo: captionContainer.layoutMarginsGuide.leadingAnchor),
captionLabel.trailingAnchor.constraint(equalTo: captionContainer.layoutMarginsGuide.trailingAnchor),
captionLabel.bottomAnchor.constraint(equalTo: captionContainer.layoutMarginsGuide.bottomAnchor),
])
let middleStack = UIStackView(arrangedSubviews: [memberApprovalStack, captionContainer])
middleStack.axis = .vertical
middleStack.translatesAutoresizingMaskIntoConstraints = false
addSubview(middleStack)
addConstraints([
middleStack.topAnchor.constraint(equalTo: topStack.bottomAnchor),
middleStack.leadingAnchor.constraint(equalTo: leadingAnchor),
middleStack.trailingAnchor.constraint(equalTo: trailingAnchor),
])
buttonStackTopAnchor = middleStack.bottomAnchor
}
// Two buttons at the bottom
let topButton: UIButton
if isGroupLinkEnabled {
topButton = UIButton(
configuration: .largePrimary(title: OWSLocalizedString(
"GROUP_LINK_PROMOTION_ALERT_SHARE_LINK",
comment: "Label for the 'share link' button in the 'group link promotion' alert view."
)),
primaryAction: UIAction { [weak self] _ in
self?.dismissAndShareLink()
}
)
} else {
topButton = UIButton(
configuration: .largePrimary(title: OWSLocalizedString(
"GROUP_LINK_PROMOTION_ALERT_ENABLE_AND_SHARE_LINK",
comment: "Label for the 'enable and share link' button in the 'group link promotion' alert view."
)),
primaryAction: UIAction { [weak self] _ in
self?.enableAndShareLink()
}
)
}
let cancelButton = UIButton(
configuration: .largeSecondary(title: CommonStrings.cancelButton),
primaryAction: UIAction { [weak self] _ in
self?.dismissAlert()
}
)
let buttonStack = UIStackView.verticalButtonStack(buttons: [ topButton, cancelButton], isFullWidthButtons: true)
buttonStack.directionalLayoutMargins = .zero
buttonStack.translatesAutoresizingMaskIntoConstraints = false
addSubview(buttonStack)
addConstraints([
buttonStack.topAnchor.constraint(equalTo: buttonStackTopAnchor, constant: 12),
buttonStack.leadingAnchor.constraint(equalTo: leadingAnchor),
buttonStack.trailingAnchor.constraint(equalTo: trailingAnchor),
buttonStack.bottomAnchor.constraint(equalTo: bottomAnchor),
])
}
required init(coder: NSCoder) {
@@ -38,21 +163,6 @@ public class GroupLinkPromotionActionSheet: UIView {
self.actionSheetController = actionSheetController
}
public func configure() {
let subviews = buildContents()
let stackView = UIStackView(arrangedSubviews: subviews)
stackView.axis = .vertical
stackView.alignment = .fill
stackView.layoutMargins = UIEdgeInsets(top: 24, leading: 24, bottom: 8, trailing: 24)
stackView.isLayoutMarginsRelativeArrangement = true
layoutMargins = .zero
addSubview(stackView)
stackView.autoPinEdgesToSuperviewMargins()
stackView.setContentHuggingHorizontalLow()
}
private var isGroupLinkEnabled: Bool {
guard let groupModel = groupThread.groupModel as? TSGroupModelV2 else {
owsFailDebug("Invalid groupModel.")
@@ -68,101 +178,13 @@ public class GroupLinkPromotionActionSheet: UIView {
private let memberApprovalSwitch = UISwitch()
private func buildContents() -> [UIView] {
let builder = ActionSheetContentBuilder()
builder.add(builder.buildTitleLabel(text: OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_TITLE",
comment: "Title for the 'group link promotion' alert view.")))
builder.addVerticalSpacer(height: 2)
builder.add(builder.buildLabel(text: OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_SUBTITLE",
comment: "Subtitle for the 'group link promotion' alert view."),
textAlignment: .center))
let isGroupLinkEnabled = self.isGroupLinkEnabled
if isGroupLinkEnabled {
builder.addVerticalSpacer(height: 88)
builder.addBottomButton(title: OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_SHARE_LINK",
comment: "Label for the 'share link' button in the 'group link promotion' alert view."),
titleColor: .white,
backgroundColor: .ows_accentBlue,
target: self,
selector: #selector(dismissAndShareLink))
} else {
builder.addVerticalSpacer(height: 32)
let memberApprovalStack = UIStackView()
memberApprovalStack.axis = .horizontal
memberApprovalStack.alignment = .center
memberApprovalStack.distribution = .fill
memberApprovalStack.layoutMargins = UIEdgeInsets(hMargin: 16, vMargin: 10)
memberApprovalStack.isLayoutMarginsRelativeArrangement = true
memberApprovalStack.addBackgroundView(withBackgroundColor: Theme.isDarkThemeEnabled ? .ows_gray65 : .ows_gray02, cornerRadius: 8)
let switchLabel = builder.buildLabel(text: OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_APPROVE_NEW_MEMBERS_SWITCH",
comment: "Label for the 'approve new group members' switch."))
memberApprovalStack.addArrangedSubview(switchLabel)
switchLabel.setCompressionResistanceHorizontalHigh()
memberApprovalStack.addArrangedSubview(UIView.hStretchingSpacer())
memberApprovalStack.addArrangedSubview(memberApprovalSwitch)
memberApprovalSwitch.setCompressionResistanceHorizontalHigh()
builder.add(memberApprovalStack)
builder.addVerticalSpacer(height: 8)
let captionLabel = builder.buildLabel(text: OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_APPROVE_NEW_MEMBERS_EXPLANATION",
comment: "Explanation of the 'approve new group members' switch."),
textColor: Theme.secondaryTextAndIconColor,
font: .dynamicTypeCaption1)
let captionContainer = UIView()
captionContainer.layoutMargins = UIEdgeInsets(hMargin: 8, vMargin: 0)
captionContainer.addSubview(captionLabel)
captionLabel.autoPinEdgesToSuperviewMargins()
builder.add(captionContainer)
builder.addVerticalSpacer(height: 44)
builder.addBottomButton(title: OWSLocalizedString("GROUP_LINK_PROMOTION_ALERT_ENABLE_AND_SHARE_LINK",
comment: "Label for the 'enable and share link' button in the 'group link promotion' alert view."),
titleColor: .white,
backgroundColor: .ows_accentBlue,
target: self,
selector: #selector(enableAndShareLink))
}
builder.addVerticalSpacer(height: 5)
builder.addBottomButton(title: CommonStrings.cancelButton,
titleColor: Theme.secondaryTextAndIconColor,
backgroundColor: .clear,
target: self,
selector: #selector(dismissAlert))
return builder.subviews
}
// MARK: - Events
@objc
private func dismissAlert() {
actionSheetController?.dismiss(animated: true)
}
}
// MARK: -
private extension GroupLinkPromotionActionSheet {
@objc
func enableAndShareLink() {
private func enableAndShareLink() {
guard let actionSheetController = actionSheetController else {
owsFailDebug("Missing actionSheetController.")
return
@@ -192,8 +214,7 @@ private extension GroupLinkPromotionActionSheet {
)
}
@objc
func dismissAndShareLink() {
private func dismissAndShareLink() {
guard let groupModelV2 = groupThread.groupModel as? TSGroupModelV2 else {
owsFailDebug("Invalid groupModel.")
return

View File

@@ -170,9 +170,8 @@ open class ActionSheetController: OWSViewController {
/// strange when there's only slightly more space on the sides than below.
let maxWidthWiggleRoom: CGFloat = 40
override public func loadView() {
view = UIView()
view.backgroundColor = .clear
override open func viewDidLoad() {
super.viewDidLoad()
// Depending on the number of actions, the sheet may need
// to scroll to allow access to all options.