diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6f713c7..4532ad3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,6 @@ - - ("app_id" to "4", "device" to "0") - val fetchResult = buildHttpRequest { - url("https://hk4e-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/fetch") - params.post(this) - }.getAsJson() - if (fetchResult.retcode != 0) { - showDialog("请求失败: ${fetchResult.message}") - return null - } - val ticket = fetchResult.data().getUri().getQueryParameter("ticket") - val scanResult = buildHttpRequest { - url("https://api-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/scan") - params.apply { - put("ticket", ticket) - }.post(this) - }.getAsJson() - if (scanResult.retcode != 0) { - showDialog("请求失败: ${scanResult.message}") - return@runCatching null - } - val confirmResult = buildHttpRequest { - url("https://api-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/confirm") - params.apply { - put("payload", buildMap { - put("proto", "Account") - put("raw", buildMap { - put("uid", acc.uid) - put("ltoken", acc.lToken) - if (useSToken) { - put("mid", acc.mid) - put("stoken", acc.sToken) - } - }.toJson()) - }) - }.post(this) - }.getAsJson() - if (confirmResult.retcode != 0) { - showDialog("请求失败: ${confirmResult.message}") - return null - } - return ticket -}.onFailure { - showDialog("网络异常,请稍后重试") -}.getOrNull() - @Composable private fun TokenActivity.Content(accountInfo: AccountInfo) = Column( modifier = Modifier.fillMaxSize() @@ -136,9 +77,8 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column( Column( modifier = Modifier.padding(15.dp) ) { - var isLoading by remember { mutableStateOf(false) } - var authTicket by remember { mutableStateOf("") } var grantSToken by remember { mutableStateOf(false) } + var showDoneIcon by remember { mutableStateOf(false) } CustomCheckBox( checked = true, onCheckedChange = {}, @@ -161,106 +101,40 @@ private fun TokenActivity.Content(accountInfo: AccountInfo) = Column( } // TODO: More description ) Divider() - AnimatedVisibility( - visible = authTicket.isNotEmpty(), - modifier = Modifier.fillMaxWidth() - ) { - AuthTicketView(authTicket) - } Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End ) { - if (BuildConfig.DEBUG) { - TextButton( - onClick = { - CoroutineScope(Dispatchers.IO).launch { - val confirmResult = buildHttpRequest { - url("https://hk4e-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/query") - buildMap { - put("app_id", "4") - put("device", "0") - put("ticket", authTicket.removePrefix("ma_")) - }.post(this) - }.getAsJson() - if (confirmResult.retcode != 0) { - showDialog("请求失败: ${confirmResult.message}") - return@launch - } else { - showDialog(confirmResult.data?.toJson() ?: "success, but data is null") - } - } - } - ) { - Text(text = "query") - } - } TextButton( onClick = { - CoroutineScope(Dispatchers.IO).launch { - authTicket = "" - isLoading = true - authTicket = genAuthCode(accountInfo, grantSToken)?.let { s -> "ma_${s}" } ?: "" - isLoading = false + runCatching { + val authStr = buildMap { + put("uid", accountInfo.uid) + put("ltoken", accountInfo.lToken) + if (grantSToken) { + put("mid", accountInfo.mid) + put("stoken", accountInfo.sToken) + } + }.map { (k, v) -> "$k=$v" }.joinToString(";") + val clip = ClipData.newPlainText(null, authStr) + getSystemService()!!.setPrimaryClip(clip) + }.onFailure { + showDialog("复制失败") + }.onSuccess { + showDoneIcon = true } - }, - enabled = !isLoading + } ) { - AnimatedVisibility(visible = isLoading) { - CircularProgressIndicator( - modifier = Modifier.size(24.dp), - strokeWidth = 3.dp + AnimatedVisibility(visible = showDoneIcon) { + Image( + imageVector = Icons.Outlined.Done, + contentDescription = null, + colorFilter = ColorFilter.tint(Color(0xFF4CAF50)) ) } - AnimatedVisibility(visible = !isLoading) { - // 120s available - Text("生成登录代码") - } + Text("复制登录信息") } } - } -} - -@OptIn(ExperimentalAnimationApi::class) -@Composable -private fun TokenActivity.AuthTicketView(authTicket: String) = ConstraintLayout( - modifier = Modifier.fillMaxWidth() -) { - val (divider, code, copyBtn) = createRefs() - Text( - text = authTicket, - modifier = Modifier.constrainAs(code) { - top.linkTo(parent.top, 12.dp) - start.linkTo(parent.start, 12.dp) - }, - fontFamily = FontFamily.Monospace - ) - var showDoneIcon by remember { mutableStateOf(false) } - val iconColor by animateColorAsState(if (showDoneIcon) Color(0xFF4CAF50) else textColor) - IconButton( - modifier = Modifier.constrainAs(copyBtn) { - top.linkTo(parent.top) - end.linkTo(parent.end) - bottom.linkTo(parent.bottom) - }, - onClick = { - runCatching { - val clip = ClipData.newPlainText(null, authTicket) - getSystemService()!!.setPrimaryClip(clip) - }.onFailure { - showDialog("复制失败") - }.onSuccess { - showDoneIcon = true - } - } - ) { - AnimatedContent(targetState = if (showDoneIcon) Icons.Outlined.Done else Res.iconCopy) { targetIcon -> - Image( - imageVector = targetIcon, - contentDescription = "Copy auth ticket", - colorFilter = ColorFilter.tint(iconColor) - ) - } LaunchedEffect(showDoneIcon) { if (showDoneIcon) { delay(1500) @@ -268,12 +142,6 @@ private fun TokenActivity.AuthTicketView(authTicket: String) = ConstraintLayout( } } } - Divider( - modifier = Modifier.constrainAs(divider) { - top.linkTo(code.bottom, 12.dp) - bottom.linkTo(parent.bottom) - } - ) } @Composable diff --git a/app/src/main/java/hat/holo/token/models/BaseResponse.kt b/app/src/main/java/hat/holo/token/models/BaseResponse.kt deleted file mode 100644 index 9193a2e..0000000 --- a/app/src/main/java/hat/holo/token/models/BaseResponse.kt +++ /dev/null @@ -1,16 +0,0 @@ -package hat.holo.token.models - -import androidx.annotation.Keep -import com.google.gson.JsonElement -import hat.holo.token.utils.convertTo - -@Keep -data class BaseResponse( - val retcode: Int = 0, - val message: String = "ok", - val data: JsonElement? = null -) { - inline fun data(): T { - return data!!.convertTo() - } -} diff --git a/app/src/main/java/hat/holo/token/models/FetchRsp.kt b/app/src/main/java/hat/holo/token/models/FetchRsp.kt deleted file mode 100644 index cc6c579..0000000 --- a/app/src/main/java/hat/holo/token/models/FetchRsp.kt +++ /dev/null @@ -1,11 +0,0 @@ -package hat.holo.token.models - -import android.net.Uri -import androidx.annotation.Keep - -@Keep -data class FetchRsp( - val url: String -) { - fun getUri(): Uri = Uri.parse(url) -} diff --git a/app/src/main/java/hat/holo/token/utils/HttpUtils.kt b/app/src/main/java/hat/holo/token/utils/HttpUtils.kt deleted file mode 100644 index 227ec58..0000000 --- a/app/src/main/java/hat/holo/token/utils/HttpUtils.kt +++ /dev/null @@ -1,70 +0,0 @@ -package hat.holo.token.utils - -import android.util.Log -import com.google.gson.Gson -import com.google.gson.JsonElement -import hat.holo.token.BuildConfig -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlinx.coroutines.withContext -import okhttp3.* -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.logging.HttpLoggingInterceptor -import java.io.IOException -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException - -private val gson by lazy { Gson() } - -fun buildHttpRequest(block: Request.Builder.() -> Unit) = Request.Builder().apply(block).build() - -fun Map.toJson() = gson.toJson(this)!! - -fun JsonElement.toJson() = gson.toJson(this)!! - -fun Map.post(builder: Request.Builder) { - builder.post(toJson().toRequestBody("application/json".toMediaType())) -} - -val defaultOkClient = OkHttpClient.Builder().apply { - if (BuildConfig.DEBUG) { - val i = HttpLoggingInterceptor { - Log.d("LSPosed-Bridge", it) - } - i.level = HttpLoggingInterceptor.Level.BODY - addInterceptor(i) - } -}.build() - -suspend inline fun Request.getAsJson(client: OkHttpClient = defaultOkClient): T { - return Gson().fromJson(this@getAsJson.getAsText(client), T::class.java)!! -} - -suspend fun Request.getAsText(client: OkHttpClient = defaultOkClient) = withContext(Dispatchers.IO) { - client.newCall(this@getAsText).await().use { r-> - checkNotNull(r.body).use { b -> - b.string() - } - } -} - -inline fun JsonElement.convertTo(): T = Gson().fromJson(this, T::class.java) - -suspend fun Call.await(): Response = suspendCancellableCoroutine { continuation -> - enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - continuation.resume(response) - } - override fun onFailure(call: Call, e: IOException) { - if (continuation.isCancelled) return - continuation.resumeWithException(e) - } - }) - continuation.invokeOnCancellation { - try { - cancel() - } catch (_: Throwable) { - } - } -} diff --git a/app/src/main/java/hat/holo/token/utils/Res.kt b/app/src/main/java/hat/holo/token/utils/Res.kt index c597edb..5f3692f 100644 --- a/app/src/main/java/hat/holo/token/utils/Res.kt +++ b/app/src/main/java/hat/holo/token/utils/Res.kt @@ -1,9 +1,6 @@ package hat.holo.token.utils import android.graphics.drawable.Drawable -import androidx.compose.material.icons.materialIcon -import androidx.compose.material.icons.materialPath -import androidx.compose.ui.graphics.vector.ImageVector import java.util.* @Suppress("SpellCheckingInspection") @@ -16,44 +13,4 @@ object Res { } } - val iconCopy: ImageVector - get() { - if (_contentCopy != null) { - return _contentCopy!! - } - _contentCopy = materialIcon(name = "Outlined.ContentCopy") { - materialPath { - moveTo(16.0f, 1.0f) - lineTo(4.0f, 1.0f) - curveToRelative(-1.1f, 0.0f, -2.0f, 0.9f, -2.0f, 2.0f) - verticalLineToRelative(14.0f) - horizontalLineToRelative(2.0f) - lineTo(4.0f, 3.0f) - horizontalLineToRelative(12.0f) - lineTo(16.0f, 1.0f) - close() - moveTo(19.0f, 5.0f) - lineTo(8.0f, 5.0f) - curveToRelative(-1.1f, 0.0f, -2.0f, 0.9f, -2.0f, 2.0f) - verticalLineToRelative(14.0f) - curveToRelative(0.0f, 1.1f, 0.9f, 2.0f, 2.0f, 2.0f) - horizontalLineToRelative(11.0f) - curveToRelative(1.1f, 0.0f, 2.0f, -0.9f, 2.0f, -2.0f) - lineTo(21.0f, 7.0f) - curveToRelative(0.0f, -1.1f, -0.9f, -2.0f, -2.0f, -2.0f) - close() - moveTo(19.0f, 21.0f) - lineTo(8.0f, 21.0f) - lineTo(8.0f, 7.0f) - horizontalLineToRelative(11.0f) - verticalLineToRelative(14.0f) - close() - } - } - return _contentCopy!! - } - - @Suppress("ObjectPropertyName") - private var _contentCopy: ImageVector? = null - }