mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-12 07:18:04 +00:00
* android, desktop: what's new in v7.1, get a supporter badge, Flat layout * android, desktop: what's new image opens Wefunder, sections get icons * android, desktop: crowdfunding image without the stripe at its left edge * android, desktop: Support SimpleX in settings, badge benefits shown * android, desktop: more space under the what's new crowdfunding image * ci: desktop references of v7.1 what's new and the settings badge row * android, desktop: crowdfunding page without contact button, badge texts * ci: desktop references of what's new with one rocket * ui: what's new in v7.1, badge links and benefits, investor offer in store * ui: localized crowdfunding texts on iOS, badge button kept in place * ci: iOS references of v7.1 what's new, badge row and store screens * ui: badge instead of the phone picture in what's new * ui: what's new crowdfunding section without the investor count * ui: what's new badges section without a picture * ci: what's new references without the picture and investor count * ui: investor offer on badge store screens in every country * ui: shorter subscription terms and store notes on badge screens * ios: subscription terms without the cancellation window * ios: subscription terms worded as on Google Play * ui: shorter badge errors and subscription notes * ui: translations of the shorter badge texts; shorter purchases alert on iOS * ui: shorter link, channel signing and badge texts, with translations * ui: Your badge for every badge except legend in settings * android, desktop: badge button at one height on the store screens; crowdfunding texts translatable * android, desktop: smaller crowdfunding image * android, desktop: what's new references with the smaller crowdfunding image
240 lines
8.4 KiB
Swift
240 lines
8.4 KiB
Swift
//
|
|
// BadgesSupportSimplexView.swift
|
|
// SimpleX (iOS)
|
|
//
|
|
// Created by spaced4ndy on 28.07.2026.
|
|
// Copyright © 2026 SimpleX Chat. All rights reserved.
|
|
//
|
|
|
|
import SwiftUI
|
|
import SimpleXChat
|
|
|
|
struct BadgesSupportSimplexView: View {
|
|
@EnvironmentObject var theme: AppTheme
|
|
@EnvironmentObject var chatModel: ChatModel
|
|
@ObservedObject private var store = BadgeStore.shared
|
|
// set true when presented as a sheet root (from the chat-list banner) — that path doesn't
|
|
// reserve nav-bar space like a NavigationLink push does, so the title lands too close to the top
|
|
var showsAsSheet: Bool = false
|
|
@State private var whyBuiltActive = false
|
|
@State private var howItWorksActive = false
|
|
@State private var chooseLevelActive = false
|
|
|
|
var body: some View {
|
|
GeometryReader { g in
|
|
VStack(alignment: .center, spacing: 16) {
|
|
Text("Support SimpleX")
|
|
.font(.largeTitle)
|
|
.bold()
|
|
.foregroundColor(theme.colors.primary)
|
|
.multilineTextAlignment(.center)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
|
|
Text("Get a badge to send larger files (2-5GB) that stay available longer (7-21 days), and to show it on your profile.")
|
|
.font(.body)
|
|
.multilineTextAlignment(.center)
|
|
.fixedSize(horizontal: false, vertical: true)
|
|
|
|
howItWorksButton()
|
|
|
|
Spacer(minLength: 0)
|
|
|
|
PhoneSupporterHero()
|
|
.frame(maxWidth: g.size.width * 0.55)
|
|
.layoutPriority(-1)
|
|
|
|
Spacer(minLength: 0)
|
|
|
|
// Store purchases are not released on iOS: TestFlight buys in the sandbox, which the
|
|
// service refuses for good. The badge is chosen on the site, and the code redeemed here.
|
|
// Revert this commit to restore the block below.
|
|
// VStack(spacing: 10) {
|
|
// chooseLevelButton()
|
|
// .padding(.vertical, 10)
|
|
// Group {
|
|
// if badgeBrowserAllowed {
|
|
// buyInBrowserButton()
|
|
// } else {
|
|
// RedeemCodeButton()
|
|
// }
|
|
// }
|
|
// .frame(height: 22)
|
|
// RestorePurchasesButton()
|
|
// .frame(height: 22)
|
|
// .padding(.top, 10)
|
|
// Text("If you were charged but have no badge, this adds it. A subscription bought with this App Store account moves to this profile, and the device or profile that had it loses its badge at its next renewal.")
|
|
// .font(.footnote)
|
|
// .foregroundColor(theme.colors.secondary)
|
|
// .multilineTextAlignment(.center)
|
|
// .fixedSize(horizontal: false, vertical: true)
|
|
// }
|
|
VStack(spacing: 10) {
|
|
chooseBadgeOnSiteButton()
|
|
.padding(.vertical, 10)
|
|
Group {
|
|
RedeemCodeButton()
|
|
}
|
|
.frame(height: 22)
|
|
BadgeInvestorOffer(level: .supporter).hidden()
|
|
}
|
|
.padding(.bottom, g.safeAreaInsets.bottom == 0 ? 20 : 0)
|
|
}
|
|
.padding(.horizontal, 25)
|
|
.padding(.top, showsAsSheet ? 48 : 0)
|
|
.padding(.bottom, 20)
|
|
// .frame(height:) not minHeight — inside the banner sheet's NavigationView minHeight
|
|
// would let the VStack expand past the visible area and inflate the hero.
|
|
.frame(height: g.size.height)
|
|
}
|
|
.frame(maxHeight: .infinity)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
}
|
|
|
|
private func chooseLevelButton() -> some View {
|
|
let disabled = !store.canBuy(chatModel.currentUser?.userId)
|
|
return ZStack {
|
|
Button {
|
|
chooseLevelActive = true
|
|
} label: {
|
|
Text("Choose your badge")
|
|
}
|
|
.buttonStyle(OnboardingButtonStyle(isDisabled: disabled))
|
|
.disabled(disabled)
|
|
|
|
NavigationLink(isActive: $chooseLevelActive) {
|
|
BadgesChooseBadgeView()
|
|
.modifier(ThemedBackground())
|
|
} label: {
|
|
EmptyView()
|
|
}
|
|
.frame(width: 1, height: 1)
|
|
.hidden()
|
|
}
|
|
}
|
|
|
|
private func whyBuiltButton() -> some View {
|
|
ZStack {
|
|
Button { whyBuiltActive = true } label: {
|
|
HStack(spacing: 4) {
|
|
Image(systemName: "info.circle")
|
|
Text("Why SimpleX is built.").fontWeight(.medium)
|
|
}
|
|
.font(.body)
|
|
}
|
|
NavigationLink(isActive: $whyBuiltActive) {
|
|
WhySimpleX(onboarding: false, titleColor: theme.colors.primary, createProfileNavLinkActive: .constant(false))
|
|
} label: {
|
|
EmptyView()
|
|
}
|
|
.frame(width: 1, height: 1)
|
|
.hidden()
|
|
}
|
|
}
|
|
|
|
private func howItWorksButton() -> some View {
|
|
ZStack {
|
|
Button { howItWorksActive = true } label: {
|
|
HStack(spacing: 4) {
|
|
Image(systemName: "info.circle")
|
|
Text("How badges protect your privacy").fontWeight(.medium)
|
|
}
|
|
.font(.body)
|
|
}
|
|
NavigationLink(isActive: $howItWorksActive) {
|
|
BadgesHowItWorksView()
|
|
.modifier(ThemedBackground())
|
|
} label: {
|
|
EmptyView()
|
|
}
|
|
.frame(width: 1, height: 1)
|
|
.hidden()
|
|
}
|
|
}
|
|
|
|
// delete with the commented block above to restore store purchases
|
|
private func chooseBadgeOnSiteButton() -> some View {
|
|
Button {
|
|
UIApplication.shared.open(URL(string: badgePageUrl)!)
|
|
} label: {
|
|
Text("Choose your badge")
|
|
}
|
|
.buttonStyle(OnboardingButtonStyle(isDisabled: false))
|
|
}
|
|
|
|
private func buyInBrowserButton() -> some View {
|
|
Button {
|
|
UIApplication.shared.open(URL(string: badgePageUrl)!)
|
|
} label: {
|
|
Text("Buy in browser")
|
|
.font(.body)
|
|
.fontWeight(.medium)
|
|
.foregroundColor(theme.colors.primary)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct RedeemCodeButton: View {
|
|
@EnvironmentObject var theme: AppTheme
|
|
@State private var redeemCodeActive = false
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
Button {
|
|
redeemCodeActive = true
|
|
} label: {
|
|
Text("Redeem badge code")
|
|
.font(.body)
|
|
.fontWeight(.medium)
|
|
.foregroundColor(theme.colors.primary)
|
|
}
|
|
|
|
NavigationLink(isActive: $redeemCodeActive) {
|
|
BadgesRedeemCodeView()
|
|
.modifier(ThemedBackground())
|
|
} label: {
|
|
EmptyView()
|
|
}
|
|
.frame(width: 1, height: 1)
|
|
.hidden()
|
|
}
|
|
}
|
|
}
|
|
|
|
struct PhoneSupporterHero: View {
|
|
@EnvironmentObject var theme: AppTheme
|
|
@Environment(\.colorScheme) var colorScheme: ColorScheme
|
|
|
|
var body: some View {
|
|
#if SIMPLEX_ASSETS
|
|
Image(colorScheme == .light ? "phone-supporter" : "phone-supporter-light")
|
|
.resizable()
|
|
.scaledToFit()
|
|
.frame(maxWidth: .infinity)
|
|
#else
|
|
ZStack {
|
|
let gp = OnboardingCardView.gradientPoints(aspectRatio: 1.0, scale: colorScheme == .light ? 1.2 : 1.5)
|
|
LinearGradient(
|
|
stops: colorScheme == .light ? OnboardingCardView.lightStops : OnboardingCardView.darkStops,
|
|
startPoint: gp.start,
|
|
endPoint: gp.end
|
|
)
|
|
Image("badge-supporter")
|
|
.resizable()
|
|
.scaledToFit()
|
|
.frame(width: 96)
|
|
}
|
|
.aspectRatio(1.0, contentMode: .fit)
|
|
.clipShape(RoundedRectangle(cornerRadius: 24))
|
|
.frame(maxWidth: .infinity)
|
|
#endif
|
|
}
|
|
}
|
|
|
|
struct BadgesSupportSimplexView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
NavigationView {
|
|
BadgesSupportSimplexView()
|
|
}
|
|
}
|
|
}
|