Signal-iOS/Signal/Backups/Onboarding/BackupOnboardingIntroViewController.swift
2025-08-13 11:08:06 -07:00

181 lines
5.6 KiB
Swift

//
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import SignalServiceKit
import SignalUI
import SwiftUI
class BackupOnboardingIntroViewController: HostingController<BackupOnboardingIntroView> {
init(
onContinue: @escaping () -> Void,
onNotNow: @escaping () -> Void,
) {
super.init(wrappedView: BackupOnboardingIntroView(
onContinue: onContinue,
onNotNow: onNotNow
))
OWSTableViewController2.removeBackButtonText(viewController: self)
}
}
// MARK: -
struct BackupOnboardingIntroView: View {
private struct BulletPoint: Identifiable {
let image: UIImage
let text: String
var id: String { text }
}
fileprivate let onContinue: () -> Void
fileprivate let onNotNow: () -> Void
private let bulletPoints: [BulletPoint] = [
BulletPoint(
image: .lock,
text: OWSLocalizedString(
"BACKUP_ONBOARDING_INTRO_BULLET_1",
comment: "Bullet point on a view introducing Backups during an onboarding flow."
)
),
BulletPoint(
image: .checkSquare,
text: OWSLocalizedString(
"BACKUP_ONBOARDING_INTRO_BULLET_2",
comment: "Bullet point on a view introducing Backups during an onboarding flow."
)
),
BulletPoint(
image: .trash,
text: OWSLocalizedString(
"BACKUP_ONBOARDING_INTRO_BULLET_3",
comment: "Bullet point on a view introducing Backups during an onboarding flow."
)
),
]
var body: some View {
ScrollableContentPinnedFooterView {
VStack {
HStack {
Image(uiImage: Theme.iconImage(.info))
.frame(width: 25, height: 40)
Text(OWSLocalizedString(
"BACKUP_SETTINGS_BETA_NOTICE_HEADER",
comment: "Notice that backups is a beta feature")
)
.font(.footnote)
.multilineTextAlignment(.leading)
}
.foregroundColor(Color.Signal.label)
.padding(.horizontal, 10)
.padding(.vertical, 10)
.background(Color.Signal.quaternaryFill)
.cornerRadius(12)
}
.padding(.horizontal, 10)
VStack {
Spacer().frame(height: 20)
Image(.backupsLogo)
.frame(width: 80, height: 80)
Spacer().frame(height: 16)
HStack {
Text(OWSLocalizedString(
"BACKUP_ONBOARDING_INTRO_TITLE",
comment: "Title for a view introducing Backups during an onboarding flow."
))
.font(.title)
.fontWeight(.semibold)
.foregroundStyle(Color.Signal.label)
Text(CommonStrings.betaLabel)
.font(.caption)
.bold()
.padding(.horizontal, 10)
.padding(.vertical, 4)
.background(Capsule().fill(
Color.Signal.secondaryFill)
)
.foregroundStyle(Color.Signal.label)
}
Spacer().frame(height: 12)
Text(OWSLocalizedString(
"BACKUP_ONBOARDING_INTRO_SUBTITLE",
comment: "Subtitle for a view introducing Backups during an onboarding flow."
))
.font(.body)
.foregroundStyle(Color.Signal.secondaryLabel)
Spacer().frame(height: 32)
VStack(alignment: .leading, spacing: 24) {
ForEach(bulletPoints) { bulletPoint in
Label {
Text(bulletPoint.text)
} icon: {
Image(uiImage: bulletPoint.image)
}
.multilineTextAlignment(.leading)
.foregroundStyle(Color.Signal.label)
.padding(.horizontal, 20) // Extra inset in case of wrap
}
}
}
.padding(.horizontal, 48)
} pinnedFooter: {
Button {
onContinue()
} label: {
Text(CommonStrings.continueButton)
.foregroundStyle(.white)
.font(.headline)
.padding(.vertical, 14)
.frame(maxWidth: .infinity)
.background(Color.Signal.ultramarine)
}
.buttonStyle(.plain)
.cornerRadius(12)
.padding(.horizontal, 40)
Spacer().frame(height: 16)
Button {
onNotNow()
} label: {
Text(CommonStrings.notNowButton)
.foregroundStyle(Color.Signal.ultramarine)
.font(.headline)
.padding(.vertical, 14)
}
.buttonStyle(.plain)
.frame(maxWidth: .infinity)
.padding(.horizontal, 40)
}
.multilineTextAlignment(.center)
.background(Color.Signal.groupedBackground)
}
}
// MARK: -
#if DEBUG
#Preview {
BackupOnboardingIntroView(
onContinue: { print("Continuing...!") },
onNotNow: { print("Not now...!") }
)
}
#endif