1.2.0: offer code redemption + share link alongside export image

- "Redeem promo code" button in PremiumView via offerCodeRedemption
  (hidden on Mac where the sheet is unavailable); entitlement re-checked
  on success — unblocks influencer/blog promo campaigns
- System share sheet now includes a localized text with the mealmood.app
  link next to the exported image (viral loop no longer QR-only)
- 2 new strings × 6 languages

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
This commit is contained in:
alexandrev-tibco
2026-07-03 10:14:58 +02:00
parent f5cb67adc0
commit cbe0ca1326
8 changed files with 46 additions and 1 deletions
@@ -380,3 +380,7 @@
/* Widget promo (1.2.0) */
"widget_promo_title" = "Die heutigen Mahlzeiten auf deinem Home-Bildschirm";
"widget_promo_body" = "Halte den Home-Bildschirm gedrückt, tippe auf + und suche nach MealMood, um das Widget hinzuzufügen.";
/* Offer codes + share link (1.2.0) */
"premium_redeem_code" = "Promo-Code einlösen";
"share_link_text" = "Unsere Woche, geplant mit MealMood → https://mealmood.app";
@@ -380,3 +380,7 @@
/* Widget promo (1.2.0) */
"widget_promo_title" = "Today's meals on your Home Screen";
"widget_promo_body" = "Long-press your Home Screen, tap +, and search for MealMood to add the widget.";
/* Offer codes + share link (1.2.0) */
"premium_redeem_code" = "Redeem promo code";
"share_link_text" = "Our week, planned with MealMood → https://mealmood.app";
@@ -380,3 +380,7 @@
/* Widget promo (1.2.0) */
"widget_promo_title" = "Las comidas de hoy en tu pantalla de inicio";
"widget_promo_body" = "Mantén pulsada la pantalla de inicio, toca + y busca MealMood para añadir el widget.";
/* Offer codes + share link (1.2.0) */
"premium_redeem_code" = "Canjear código promocional";
"share_link_text" = "Nuestra semana, planificada con MealMood → https://mealmood.app";
@@ -380,3 +380,7 @@
/* Widget promo (1.2.0) */
"widget_promo_title" = "Les repas du jour sur votre écran d'accueil";
"widget_promo_body" = "Appuyez longuement sur l'écran d'accueil, touchez + et cherchez MealMood pour ajouter le widget.";
/* Offer codes + share link (1.2.0) */
"premium_redeem_code" = "Utiliser un code promo";
"share_link_text" = "Notre semaine, planifiée avec MealMood → https://mealmood.app";
@@ -380,3 +380,7 @@
/* Widget promo (1.2.0) */
"widget_promo_title" = "I pasti di oggi sulla schermata Home";
"widget_promo_body" = "Tieni premuta la schermata Home, tocca + e cerca MealMood per aggiungere il widget.";
/* Offer codes + share link (1.2.0) */
"premium_redeem_code" = "Riscatta codice promo";
"share_link_text" = "La nostra settimana, pianificata con MealMood → https://mealmood.app";
@@ -380,3 +380,7 @@
/* Widget promo (1.2.0) */
"widget_promo_title" = "As refeições de hoje na sua tela de início";
"widget_promo_body" = "Pressione a tela de início, toque em + e procure MealMood para adicionar o widget.";
/* Offer codes + share link (1.2.0) */
"premium_redeem_code" = "Resgatar código promocional";
"share_link_text" = "Nossa semana, planejada com MealMood → https://mealmood.app";
+3 -1
View File
@@ -62,7 +62,9 @@ struct SocialShareSheet: View {
}
.toast(isShowing: $showCopiedToast, message: String(localized: "share_copied"))
.sheet(isPresented: $showSystemShare) {
SystemShareSheet(activityItems: [imageURL])
// Ship the link as text alongside the image so the viral loop isn't
// limited to the QR baked into the rendered export.
SystemShareSheet(activityItems: [imageURL, String(localized: "share_link_text")])
}
}
+19
View File
@@ -8,6 +8,7 @@ struct PremiumView: View {
@State private var appearedAt: Date = Date()
@State private var didConvert: Bool = false
@State private var selectedPlan: PlanChoice = .yearly
@State private var showOfferCodeRedemption: Bool = false
let settings: AppSettings
var source: String = "unknown"
@@ -112,6 +113,17 @@ struct PremiumView: View {
}
.padding(.top, 4)
if !ProcessInfo.processInfo.isiOSAppOnMac {
Button {
showOfferCodeRedemption = true
} label: {
Text("premium_redeem_code")
.font(.mealMoodSmall)
.foregroundColor(.mealMoodCoral)
}
.padding(.top, 2)
}
Text("premium_terms_note")
.font(.mealMoodCaption)
.foregroundColor(.mealMoodTextSecondary)
@@ -129,6 +141,13 @@ struct PremiumView: View {
.task {
await storeManager.loadProducts()
}
.offerCodeRedemption(isPresented: $showOfferCodeRedemption) { result in
if case .success = result {
// Entitlement propagates via Transaction.updates; force a re-check
// so premium unlocks immediately after redeeming.
Task { await storeManager.restorePurchases() }
}
}
.onAppear {
appearedAt = Date()
AnalyticsService.logPaywallViewed(source: source)