forked from wolopo/newtv
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
187504b
commit ec67a64
Showing
13 changed files
with
396 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
app/src/main/java/top/yogiczy/mytv/data/entities/GithubRelease.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package top.yogiczy.mytv.data.entities | ||
|
||
data class GithubRelease( | ||
val tagName: String = "v0.0.0", | ||
val downloadUrl: String = "", | ||
val description: String = "", | ||
) |
7 changes: 7 additions & 0 deletions
7
app/src/main/java/top/yogiczy/mytv/data/repositories/GithubRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package top.yogiczy.mytv.data.repositories | ||
|
||
import top.yogiczy.mytv.data.entities.GithubRelease | ||
|
||
interface GithubRepository { | ||
suspend fun latestRelease(): GithubRelease | ||
} |
46 changes: 46 additions & 0 deletions
46
app/src/main/java/top/yogiczy/mytv/data/repositories/GithubRepositoryImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package top.yogiczy.mytv.data.repositories | ||
|
||
import android.util.Log | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.withContext | ||
import okhttp3.OkHttpClient | ||
import okhttp3.Request | ||
import org.json.JSONArray | ||
import org.json.JSONObject | ||
import top.yogiczy.mytv.data.entities.GithubRelease | ||
import top.yogiczy.mytv.data.utils.Constants | ||
|
||
class GithubRepositoryImpl : GithubRepository { | ||
override suspend fun latestRelease(): GithubRelease = withContext(Dispatchers.IO) { | ||
Log.d(TAG, "获取最新release: ${Constants.GITHUB_RELEASE_LATEST_URL}") | ||
|
||
val client = OkHttpClient() | ||
val request = Request.Builder().url(Constants.GITHUB_RELEASE_LATEST_URL).build() | ||
|
||
try { | ||
return@withContext with(client.newCall(request).execute()) { | ||
if (!isSuccessful) { | ||
throw Exception("获取最新release失败: $code") | ||
} | ||
|
||
val json = JSONObject(body!!.string()) | ||
|
||
val release = GithubRelease( | ||
tagName = json["tag_name"] as String, | ||
downloadUrl = (json["assets"] as JSONArray).getJSONObject(0)["browser_download_url"] as String, | ||
description = json["body"] as String | ||
) | ||
Log.d(TAG, "获取最新release: $release") | ||
|
||
return@with release | ||
} | ||
} catch (e: Exception) { | ||
Log.e(TAG, "获取最新release失败", e) | ||
throw Exception("获取最新release失败,请检查网络连接", e.cause) | ||
} | ||
} | ||
|
||
companion object { | ||
const val TAG = "GithubRepositoryImpl" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
173 changes: 173 additions & 0 deletions
173
app/src/main/java/top/yogiczy/mytv/ui/screens/settings/components/UpdateState.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
package top.yogiczy.mytv.ui.screens.settings.components | ||
|
||
import android.content.Context | ||
import android.content.Intent | ||
import android.content.pm.PackageInfo | ||
import android.os.Build | ||
import android.provider.Settings | ||
import android.util.Log | ||
import android.widget.Toast | ||
import androidx.activity.compose.rememberLauncherForActivityResult | ||
import androidx.activity.result.contract.ActivityResultContracts | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.Stable | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.rememberCoroutineScope | ||
import androidx.compose.runtime.setValue | ||
import androidx.compose.ui.platform.LocalContext | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.launch | ||
import top.yogiczy.mytv.data.entities.GithubRelease | ||
import top.yogiczy.mytv.data.repositories.GithubRepositoryImpl | ||
import top.yogiczy.mytv.data.utils.Constants | ||
import top.yogiczy.mytv.ui.utils.ApkInstaller | ||
import top.yogiczy.mytv.ui.utils.DownloadUtil | ||
import top.yogiczy.mytv.ui.utils.VersionUtil | ||
import java.io.File | ||
|
||
@Stable | ||
data class UpdateState( | ||
private val context: Context, | ||
private val packageInfo: PackageInfo, | ||
private val coroutineScope: CoroutineScope, | ||
val latestFile: File = File(context.cacheDir, "latest.apk"), | ||
) { | ||
private var _isChecking by mutableStateOf(false) | ||
val isChecking get() = _isChecking | ||
|
||
private var _isUpdating by mutableStateOf(false) | ||
val isUpdating get() = _isUpdating | ||
|
||
private var _isUpdateAvailable by mutableStateOf(false) | ||
val isUpdateAvailable get() = _isUpdateAvailable | ||
|
||
private var _updateDownloaded by mutableStateOf(false) | ||
val updateDownloaded get() = _updateDownloaded | ||
|
||
private var _latestRelease by mutableStateOf(GithubRelease()) | ||
val latestRelease get() = _latestRelease | ||
|
||
suspend fun checkUpdate() { | ||
if (_isChecking) return | ||
if (_isUpdateAvailable) return | ||
|
||
try { | ||
_isChecking = true | ||
_latestRelease = GithubRepositoryImpl().latestRelease() | ||
if (VersionUtil.compareVersion( | ||
_latestRelease.tagName.substring(1), | ||
packageInfo.versionName | ||
) > 0 | ||
) { | ||
_isUpdateAvailable = true | ||
Toast.makeText( | ||
context, | ||
"新版本: ${_latestRelease.tagName}", | ||
Toast.LENGTH_SHORT | ||
) | ||
.show() | ||
} | ||
} catch (e: Exception) { | ||
Log.e("UpdateState", e.message ?: e.toString(), e) | ||
Toast.makeText(context, "检查更新失败", Toast.LENGTH_SHORT).show() | ||
} finally { | ||
_isChecking = false | ||
} | ||
} | ||
|
||
suspend fun downloadAndUpdate() { | ||
if (!_isUpdateAvailable) return | ||
if (_isUpdating) return | ||
|
||
try { | ||
_isUpdating = true | ||
_updateDownloaded = false | ||
|
||
var toast = Toast.makeText( | ||
context, "开始下载更新: ${_latestRelease.tagName}", Toast.LENGTH_SHORT | ||
).apply { show() } | ||
|
||
DownloadUtil.downloadTo( | ||
"${Constants.GITHUB_PROXY}${_latestRelease.downloadUrl}", | ||
latestFile.path, | ||
downloadListener = object : DownloadUtil.DownloadListener() { | ||
var lastTime = 0L | ||
override fun onProgress(progress: Int) { | ||
coroutineScope.launch { | ||
if (System.currentTimeMillis() - lastTime > 1000) { | ||
lastTime = System.currentTimeMillis() | ||
toast.cancel() | ||
toast = Toast.makeText( | ||
context, | ||
"正在下载更新: $progress%", | ||
Toast.LENGTH_SHORT | ||
).apply { show() } | ||
} | ||
} | ||
} | ||
} | ||
) | ||
|
||
_updateDownloaded = true | ||
toast.cancel() | ||
Toast.makeText( | ||
context, "下载更新成功: ${_latestRelease.tagName}", Toast.LENGTH_SHORT | ||
).show() | ||
|
||
} catch (e: Exception) { | ||
Toast.makeText(context, "下载更新失败", Toast.LENGTH_SHORT).show() | ||
} finally { | ||
_isUpdating = false | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
fun rememberUpdateState( | ||
context: Context = LocalContext.current, | ||
): UpdateState { | ||
val coroutineScope = rememberCoroutineScope() | ||
val packageInfo = rememberPackageInfo() | ||
|
||
val state = remember { | ||
UpdateState( | ||
context = context, | ||
packageInfo = packageInfo, | ||
coroutineScope = coroutineScope, | ||
) | ||
} | ||
|
||
LaunchedEffect(Unit) { | ||
state.checkUpdate() | ||
} | ||
|
||
val launcher = | ||
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||
if (context.packageManager.canRequestPackageInstalls()) | ||
ApkInstaller.installApk(context, state.latestFile.path) | ||
else | ||
Toast.makeText(context, "未授予安装权限", Toast.LENGTH_SHORT).show() | ||
} | ||
} | ||
|
||
LaunchedEffect(state.updateDownloaded) { | ||
if (!state.updateDownloaded) return@LaunchedEffect | ||
|
||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { | ||
ApkInstaller.installApk(context, state.latestFile.path) | ||
} else { | ||
if (context.packageManager.canRequestPackageInstalls()) { | ||
ApkInstaller.installApk(context, state.latestFile.path) | ||
} else { | ||
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES) | ||
launcher.launch(intent) | ||
} | ||
} | ||
} | ||
|
||
return state | ||
} |
Oops, something went wrong.