cosmo.21: subscription deleted by the bot -> buy a new one by device, then replace the old subscription
This commit is contained in:
parent
9e3be7a630
commit
8d8c0dafd1
6 changed files with 43 additions and 5 deletions
|
|
@ -16,7 +16,7 @@ android {
|
|||
minSdk = 24
|
||||
targetSdk = 37
|
||||
versionCode = 749
|
||||
versionName = "2.3.9-cosmo.20"
|
||||
versionName = "2.3.9-cosmo.21"
|
||||
|
||||
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
|
||||
splits {
|
||||
|
|
|
|||
|
|
@ -158,9 +158,11 @@ fun CosmoMainScreen(
|
|||
}
|
||||
)
|
||||
offerRefresh++
|
||||
// First purchase on this device: add the new subscription (import also downloads its servers).
|
||||
if (newSubUrl != null && CosmoPay.subscriptionUrl() == null) onAction(MainAction.ImportBatchConfig(newSubUrl))
|
||||
else onAction(MainAction.UpdateSubscriptions)
|
||||
// New subscription (first purchase, or the bot deleted the expired one): drop the old one, add the new one.
|
||||
if (newSubUrl != null && CosmoPay.subscriptionUrl()?.trimEnd('/') != newSubUrl.trimEnd('/')) {
|
||||
CosmoPay.removeOtherSubscriptions(newSubUrl)
|
||||
onAction(MainAction.ImportBatchConfig(newSubUrl))
|
||||
} else onAction(MainAction.UpdateSubscriptions)
|
||||
}
|
||||
|
||||
// Bottom bar: Home + My subscription; Settings opens from the gear (top-left) as a separate screen.
|
||||
|
|
|
|||
|
|
@ -86,7 +86,9 @@ fun CosmoRenewSheet(onDismiss: () -> Unit, onUnfrozen: (expireAt: String?) -> Un
|
|||
var mode by remember { mutableStateOf(CosmoSheetMode.Tariffs) }
|
||||
var pack by remember { mutableStateOf<Int?>(null) }
|
||||
// No subscription yet -> the device itself buys (the server creates the subscription after payment).
|
||||
val who = remember { CosmoPay.caller(context) }
|
||||
var who by remember { mutableStateOf(CosmoPay.caller(context)) }
|
||||
// The bot deletes keys some time after they expire: then this device buys a new subscription.
|
||||
var staleSub by remember { mutableStateOf(false) }
|
||||
var reloadTick by remember { mutableIntStateOf(0) }
|
||||
|
||||
LaunchedEffect(reloadTick) {
|
||||
|
|
@ -105,6 +107,12 @@ fun CosmoRenewSheet(onDismiss: () -> Unit, onUnfrozen: (expireAt: String?) -> Un
|
|||
else -> CosmoSheetMode.Tariffs
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (e is CosmoPay.HttpError && e.code == 404 && who.subUrl != null) {
|
||||
who = who.copy(subUrl = null)
|
||||
staleSub = true
|
||||
reloadTick++
|
||||
return@LaunchedEffect
|
||||
}
|
||||
LogUtil.e(AppConfig.TAG, "CosmoPay: load offer failed", e)
|
||||
error = true
|
||||
}
|
||||
|
|
@ -139,6 +147,14 @@ fun CosmoRenewSheet(onDismiss: () -> Unit, onUnfrozen: (expireAt: String?) -> Un
|
|||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
if (staleSub && !loading) {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text(
|
||||
stringResource(R.string.cosmo_renew_sub_deleted),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.height(16.dp))
|
||||
when {
|
||||
loading -> Box(Modifier.fillMaxWidth().padding(24.dp), contentAlignment = Alignment.Center) { CircularProgressIndicator() }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.v2ray.ang.util
|
|||
import android.content.Context
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SettingsManager
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
|
@ -94,6 +95,23 @@ object CosmoPay {
|
|||
null
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes provider subscriptions other than [keepUrl] (e.g. the one the bot deleted after it expired),
|
||||
* together with their servers. Returns how many were removed.
|
||||
*/
|
||||
fun removeOtherSubscriptions(keepUrl: String): Int {
|
||||
val stale = try {
|
||||
MmkvManager.decodeSubscriptions().filter {
|
||||
val url = it.subscription.url.trim()
|
||||
url.startsWith(SUB_PREFIX) && url.trimEnd('/') != keepUrl.trim().trimEnd('/')
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
emptyList()
|
||||
}
|
||||
stale.forEach { SettingsManager.removeSubscriptionWithDefault(it.guid) }
|
||||
return stale.size
|
||||
}
|
||||
|
||||
/** App start without a subscription: this device's existing subscription (restore) or trial availability. */
|
||||
fun device(hwid: String): DeviceState {
|
||||
val o = post("device", JSONObject().put("hwid", hwid))
|
||||
|
|
|
|||
|
|
@ -152,5 +152,6 @@
|
|||
<string name="cosmo_devices_done">Готово: теперь до %1$d устройств</string>
|
||||
<string name="cosmo_devices_full">Все места для устройств заняты (%1$d из %2$d)</string>
|
||||
<string name="cosmo_mysub_devices_used">%1$d из %2$d</string>
|
||||
<string name="cosmo_renew_sub_deleted">Прежняя подписка закончилась и была удалена. Оформите новую — приложение добавит её само.</string>
|
||||
</resources>
|
||||
|
||||
|
|
|
|||
|
|
@ -143,5 +143,6 @@
|
|||
<string name="cosmo_devices_done">Done: now up to %1$d devices</string>
|
||||
<string name="cosmo_devices_full">All device slots are in use (%1$d of %2$d)</string>
|
||||
<string name="cosmo_mysub_devices_used">%1$d of %2$d</string>
|
||||
<string name="cosmo_renew_sub_deleted">Your previous subscription expired and was removed. Get a new one — the app will add it automatically.</string>
|
||||
</resources>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue