forked from Tadrisino/MathApp_frontend
Calmer shop with payment choice, step-by-step phone back, sound/haptics that reach the phone, live streak flame
- Shop: subscription perks shown once (each card repeated them, «۳ سوال در روز» twice), plans as selectable rows with one big buy button, prices as «۷۹۸ هزار تومان», a single clear status card for subscribers. Checkout inside the Bazaar app offers «کارتِ بانکی» (default) or «کافهبازار» for packs with a SKU; «بهزودی در بازار» is gone. The gateway opens in the phone browser; status refreshes on return. - Back button: every back-able level (open sheet, pushed screen, non-home tab, shop list) owns exactly one history entry created right after the tap; back closes the sheet, then the screen, then returns to Home, then leaves the app. (A re-pushed trap is skipped by Chrome's history intervention.) - Sound: AudioContext unlocked on the first touch (it was created after a network wait, which WebView/Safari keep muted); softer notes, option tick, finish fanfare, streak whoosh. Haptics through the new TadrisinoAndroid.vibrate bridge when the APK has it, navigator.vibrate otherwise. - Streak: animated flame with lit / at-risk (grey) / frozen (ice) states on Home and the streak screen, a companion reminder when the streak is at risk or frozen, and a full-screen «روزِ پیاپی» celebration after the first lesson of the day (needs backend 9024c6b: streak.activeToday / lost). - Lessons: intro/example text with inline «۱. … ۲. …» renders as a numbered list (2,250 of 4,469 texts). - Quiz: duplicate React key on the answer bubble fixed. - android/MainActivity.kt: vibrate bridge and mediaPlaybackRequiresUserGesture=false. Not built; needs the next APK from the signing owner. Checked in headless Chrome against the local backend (shop as a subscriber with the Bazaar bridge stubbed, back sequences, quiz → streak celebration, frozen state). Not checked on a real phone or in the APK. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,11 @@ package com.tadrisino.app
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.os.VibratorManager
|
||||
import android.util.Log
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.WebResourceRequest
|
||||
@@ -16,6 +20,7 @@ import ir.cafebazaar.poolakey.Payment
|
||||
import ir.cafebazaar.poolakey.config.PaymentConfiguration
|
||||
import ir.cafebazaar.poolakey.config.SecurityCheck
|
||||
import ir.cafebazaar.poolakey.request.PurchaseRequest
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
@@ -54,6 +59,8 @@ class MainActivity : AppCompatActivity() {
|
||||
// WebView فقط آدرسِ وب را میخواند؛ دسترسی به فایل و content:// لازم نیست.
|
||||
webView.settings.allowFileAccess = false
|
||||
webView.settings.allowContentAccess = false
|
||||
// صداهای کوتاهِ رابط (Web Audio) بعد از پاسخِ سرور پخش میشوند، نه درست در لحظهی لمس.
|
||||
webView.settings.mediaPlaybackRequiresUserGesture = false
|
||||
webView.webViewClient = object : WebViewClient() {
|
||||
// هر آدرسی بیرونِ دامنهی خودمان در مرورگرِ گوشی باز میشود، نه داخلِ اپ؛ پس پل فقط
|
||||
// در صفحههای خودمان در دسترس است.
|
||||
@@ -160,6 +167,32 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* لرزشِ کوتاهِ رابط (src/lib/sound.tsِ فرانت). `navigator.vibrate` در همهی WebViewها اجرا نمیشود؛
|
||||
* این مستقیم از Vibratorِ گوشی است. ورودی آرایهی JSON از میلیثانیهها: [لرزش، مکث، لرزش، …].
|
||||
*/
|
||||
@JavascriptInterface
|
||||
fun vibrate(patternJson: String) {
|
||||
val pattern = try {
|
||||
val arr = JSONArray(patternJson)
|
||||
LongArray(arr.length()) { i -> arr.getLong(i).coerceIn(0, 1000) }
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "bad vibrate pattern", e)
|
||||
return
|
||||
}
|
||||
if (pattern.isEmpty()) return
|
||||
val vibrator = if (Build.VERSION.SDK_INT >= 31) {
|
||||
(getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager).defaultVibrator
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
getSystemService(VIBRATOR_SERVICE) as Vibrator
|
||||
}
|
||||
// [لرزش، مکث، …] → قالبِ اندروید که با مکث شروع میشود.
|
||||
val timings = longArrayOf(0) + pattern
|
||||
if (Build.VERSION.SDK_INT >= 26) vibrator.vibrate(VibrationEffect.createWaveform(timings, -1))
|
||||
else @Suppress("DEPRECATION") vibrator.vibrate(timings, -1)
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
fun bazaarConsume(purchaseToken: String) {
|
||||
runOnUiThread {
|
||||
|
||||
Reference in New Issue
Block a user