mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-16 04:52:39 +02:00
Update dialogs
This commit is contained in:
@@ -7,6 +7,10 @@ import android.os.IBinder
|
||||
import android.os.SystemClock
|
||||
import com.futo.platformplayer.UIDialogs.ActionStyle
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.models.ImageVariable
|
||||
import com.futo.platformplayer.states.AnnouncementType
|
||||
import com.futo.platformplayer.states.SessionAnnouncement
|
||||
import com.futo.platformplayer.states.StateAnnouncement
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.states.StateUpdate
|
||||
import kotlinx.coroutines.*
|
||||
@@ -14,6 +18,7 @@ import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
class UpdateDownloadService : Service() {
|
||||
|
||||
@@ -85,13 +90,16 @@ class UpdateDownloadService : Service() {
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
private fun throttledUpdateDownloadProgress(version: Int, progress: Int, indeterminate: Boolean) {
|
||||
private fun throttledUpdateDownloadProgress(version: Int, progress: Int, indeterminate: Boolean, onProgress: ((Int) -> Unit)? = null) {
|
||||
val now = SystemClock.elapsedRealtime()
|
||||
val force = progress == 100 && !indeterminate
|
||||
|
||||
if (force || now - lastProgressUpdateElapsedMs >= MIN_PROGRESS_UPDATE_INTERVAL_MS) {
|
||||
lastProgressUpdateElapsedMs = now
|
||||
UpdateNotificationManager.updateDownloadProgress(this, version, progress, indeterminate)
|
||||
UpdateNotificationManager.updateDownloadProgress(this, version, progress, indeterminate);
|
||||
|
||||
if(onProgress != null)
|
||||
onProgress.invoke(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +107,7 @@ class UpdateDownloadService : Service() {
|
||||
val apkFile = StateUpdate.getApkFile(this, version)
|
||||
val partialFile = StateUpdate.getPartialApkFile(this, version)
|
||||
|
||||
var announcement: SessionAnnouncement? = null;
|
||||
try {
|
||||
if (apkFile.exists() && apkFile.length() > 0L) {
|
||||
Logger.i(TAG, "APK already downloaded at ${apkFile.absolutePath}")
|
||||
@@ -106,6 +115,14 @@ class UpdateDownloadService : Service() {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
announcement = StateAnnouncement.instance.registerLoading("Downloading new version [${version}]", "New version is being downloaded..",
|
||||
ImageVariable.fromResource(R.drawable.foreground));
|
||||
}
|
||||
catch(ex: Exception){
|
||||
Logger.e(TAG, "Failed to set progress announcement", ex);
|
||||
}
|
||||
|
||||
var backoffMs = INITIAL_BACKOFF_MS
|
||||
|
||||
for (attempt in 0 until MAX_RETRIES) {
|
||||
@@ -115,7 +132,13 @@ class UpdateDownloadService : Service() {
|
||||
}
|
||||
|
||||
try {
|
||||
performDownload(StateUpdate.APK_URL, partialFile, version)
|
||||
performDownload(StateUpdate.APK_URL, partialFile, version, {
|
||||
try {
|
||||
if (announcement != null)
|
||||
announcement?.setProgress(it);
|
||||
}
|
||||
catch(ex: Throwable) {}
|
||||
})
|
||||
|
||||
if (!cancelRequested) {
|
||||
if (apkFile.exists()) {
|
||||
@@ -145,6 +168,12 @@ class UpdateDownloadService : Service() {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (announcement != null) {
|
||||
StateAnnouncement.instance.closeAnnouncement(announcement.id);
|
||||
}
|
||||
}
|
||||
catch(ex: Throwable){}
|
||||
isDownloading = false
|
||||
cancelRequested = false
|
||||
stopForeground(Service.STOP_FOREGROUND_REMOVE)
|
||||
@@ -152,7 +181,7 @@ class UpdateDownloadService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun performDownload(url: String, partialFile: File, version: Int) {
|
||||
private fun performDownload(url: String, partialFile: File, version: Int, onProgress: ((Int)->Unit)? = null) {
|
||||
var startOffset = if (partialFile.exists()) partialFile.length() else 0L
|
||||
Logger.i(TAG, "Starting download. url=$url, existingBytes=$startOffset")
|
||||
|
||||
@@ -204,7 +233,7 @@ class UpdateDownloadService : Service() {
|
||||
progress > 100 -> 100
|
||||
else -> progress
|
||||
}
|
||||
throttledUpdateDownloadProgress(version, safeProgress, indeterminate = false)
|
||||
throttledUpdateDownloadProgress(version, safeProgress, indeterminate = false, onProgress)
|
||||
}
|
||||
} else {
|
||||
throttledUpdateDownloadProgress(version, progress = 0, indeterminate = true)
|
||||
@@ -250,6 +279,18 @@ class UpdateDownloadService : Service() {
|
||||
UpdateNotificationManager.cancelAll(ctx)
|
||||
UpdateInstaller.startInstall(ctx, version, apkFile)
|
||||
}, ActionStyle.PRIMARY, true));
|
||||
|
||||
try {
|
||||
StateAnnouncement.instance.registerAnnouncement("install-update-apk", "Grayjay v${version} is ready!", "You can now install the new Grayjay version.",
|
||||
AnnouncementType.SESSION,
|
||||
OffsetDateTime.now(), "update", "Install", {
|
||||
UpdateNotificationManager.cancelAll(ctx)
|
||||
UpdateInstaller.startInstall(ctx, version, apkFile)
|
||||
});
|
||||
}
|
||||
catch(ex: Throwable) {
|
||||
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
Logger.w(TAG, "Failed to show in-app update downloaded dialog", t)
|
||||
updateDownloadedDialog = null
|
||||
|
||||
@@ -7,6 +7,8 @@ import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.api.http.ManagedHttpClient
|
||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.constructs.Event2
|
||||
import com.futo.platformplayer.dialogs.PluginUpdateDialog
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.models.ImageVariable
|
||||
@@ -118,8 +120,8 @@ class StateAnnouncement {
|
||||
}
|
||||
|
||||
//Special Announcements
|
||||
fun registerPluginUpdate(oldConfig: SourcePluginConfig, newConfig: SourcePluginConfig) {
|
||||
registerAnnouncementSession(SessionAnnouncement(
|
||||
fun registerPluginUpdate(oldConfig: SourcePluginConfig, newConfig: SourcePluginConfig): SessionAnnouncement {
|
||||
val announcement = SessionAnnouncement(
|
||||
"update-plugin-" + UUID.randomUUID().toString(),
|
||||
"${newConfig.name} update v${newConfig.version} available!",
|
||||
"An update is available to upgrade from ${oldConfig.version} to ${newConfig.version}.",
|
||||
@@ -127,7 +129,9 @@ class StateAnnouncement {
|
||||
null, "updates", "Update", StateAnnouncement.ACTION_UPDATE_PLUGIN,
|
||||
null, null,oldConfig.id,
|
||||
newConfig?.absoluteIconUrl?.let { ImageVariable.fromUrl(it) }
|
||||
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, oldConfig.id));
|
||||
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, oldConfig.id);
|
||||
registerAnnouncementSession(announcement);
|
||||
return announcement;
|
||||
}
|
||||
fun registerPluginUpdated(newConfig: SourcePluginConfig) {
|
||||
registerAnnouncementSession(SessionAnnouncement(
|
||||
@@ -141,17 +145,18 @@ class StateAnnouncement {
|
||||
).withExtraAction("Changelog", StateAnnouncement.ACTION_CHANGELOG, newConfig.id));
|
||||
}
|
||||
|
||||
fun registerLoading(title: String, description: String, icon: ImageVariable? = null): String {
|
||||
fun registerLoading(title: String, description: String, icon: ImageVariable? = null, customId: String? = null): SessionAnnouncement {
|
||||
val id = "loading-" + UUID.randomUUID().toString();
|
||||
registerAnnouncementSession(SessionAnnouncement(
|
||||
id,
|
||||
val announcement = SessionAnnouncement(
|
||||
customId ?: id,
|
||||
title,
|
||||
description,
|
||||
AnnouncementType.ONGOING,
|
||||
null, "loading", null, null,
|
||||
null, null,null, icon
|
||||
));
|
||||
return id;
|
||||
);
|
||||
registerAnnouncementSession(announcement);
|
||||
return announcement;
|
||||
}
|
||||
|
||||
|
||||
@@ -338,9 +343,10 @@ class StateAnnouncement {
|
||||
return
|
||||
|
||||
closeAnnouncement(notifId);
|
||||
val loadingId = registerLoading("Updating ${plugin.config.name}..", "An update is in progress for ${plugin.config.name}.",
|
||||
val loadingAnnouncement = registerLoading("Updating ${plugin.config.name}..", "An update is in progress for ${plugin.config.name}.",
|
||||
if(plugin.config.absoluteIconUrl != null) ImageVariable.fromUrl(plugin.config.absoluteIconUrl!!) else null);
|
||||
|
||||
val loadingId = loadingAnnouncement.id;
|
||||
|
||||
StateApp.instance.contextOrNull?.let { context ->
|
||||
|
||||
@@ -462,12 +468,26 @@ class SessionAnnouncement(
|
||||
var extraActionId: String? = null;
|
||||
var extraActionData: String? = null;
|
||||
|
||||
var extraObj: Any? = null;
|
||||
|
||||
var progress: Double? = null;
|
||||
val onProgressChanged = Event1<SessionAnnouncement>();
|
||||
|
||||
fun withExtraAction(name: String, id: String, data: String? = null): SessionAnnouncement {
|
||||
extraActionName = name;
|
||||
extraActionId = id;
|
||||
extraActionData = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
fun setProgress(progress: Double) {
|
||||
this.progress = progress;
|
||||
onProgressChanged?.emit(this);
|
||||
}
|
||||
fun setProgress(progress: Int) {
|
||||
this.progress = progress.toDouble().div(100);
|
||||
onProgressChanged?.emit(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum class AnnouncementType(val value : Int) {
|
||||
|
||||
@@ -113,7 +113,10 @@ class StateUpdate {
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
return File(dir, "app-${DESIRED_ABI}-${version}.apk");
|
||||
val result = File(dir, "app-${DESIRED_ABI}-${version}.apk");
|
||||
//if(result.exists())
|
||||
// result.delete();
|
||||
return result;
|
||||
}
|
||||
|
||||
fun getPartialApkFile(context: Context, version: Int): File {
|
||||
@@ -121,7 +124,10 @@ class StateUpdate {
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
return File(dir, "app-${DESIRED_ABI}-${version}.apk.part");
|
||||
val result = File(dir, "app-${DESIRED_ABI}-${version}.apk.part");
|
||||
//if(result.exists())
|
||||
// result.delete();
|
||||
return result;
|
||||
}
|
||||
|
||||
fun finish() {
|
||||
|
||||
+26
@@ -7,8 +7,11 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.findViewTreeLifecycleOwner
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.fragment.mainactivity.main.MainFragment
|
||||
@@ -78,6 +81,7 @@ class NotificationOverlayView: ConstraintLayout {
|
||||
protected val _buttonExtra: LinearLayout
|
||||
protected val _buttonExtraText: TextView
|
||||
protected val _loader: LoaderView;
|
||||
protected val _progress: ProgressBar;
|
||||
|
||||
init {
|
||||
_textName = _view.findViewById(R.id.text_name);
|
||||
@@ -90,6 +94,7 @@ class NotificationOverlayView: ConstraintLayout {
|
||||
_buttonExtraText = _view.findViewById(R.id.button_extra_text);
|
||||
_icon = _view.findViewById(R.id.icon);
|
||||
_loader = _view.findViewById(R.id.loader);
|
||||
_progress = _view.findViewById(R.id.progress);
|
||||
|
||||
_buttonIgnore.setOnClickListener {
|
||||
_announcement.let {
|
||||
@@ -116,8 +121,12 @@ class NotificationOverlayView: ConstraintLayout {
|
||||
|
||||
|
||||
override fun bind(value: Announcement) {
|
||||
val oldAnnouncement = _announcement;
|
||||
_announcement = value;
|
||||
|
||||
if(oldAnnouncement is SessionAnnouncement)
|
||||
oldAnnouncement.onProgressChanged.clear();
|
||||
|
||||
_textName.text = value.title;
|
||||
_textMetadata.text = value.msg;
|
||||
|
||||
@@ -141,6 +150,23 @@ class NotificationOverlayView: ConstraintLayout {
|
||||
else {
|
||||
_buttonIgnore.visibility = View.VISIBLE;
|
||||
}
|
||||
if(value.progress != null && value.announceType == AnnouncementType.ONGOING) {
|
||||
_progress.isVisible = true;
|
||||
_progress.min = 0;
|
||||
_progress.max = 100;
|
||||
value.onProgressChanged.subscribe {
|
||||
val prog = it.progress;
|
||||
if(prog == 0.toDouble() || prog == 100.toDouble()) {
|
||||
_progress.isIndeterminate = true;
|
||||
}
|
||||
else {
|
||||
_progress.isIndeterminate = false;
|
||||
_progress.setProgress(it.progress?.times(100)?.toInt() ?: 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
_progress.isVisible = false;
|
||||
}
|
||||
else {
|
||||
_buttonExtra.visibility = View.GONE;
|
||||
|
||||
@@ -143,6 +143,17 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:progressTint="@color/primary"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:id="@+id/separator"
|
||||
|
||||
Reference in New Issue
Block a user