diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt index ed377ad1a..6e26e4a37 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -83,6 +83,7 @@ class MainActivity : BaseActivity(), AppBarOwner, BottomNav private val viewModel by viewModels() private val searchSuggestionViewModel by viewModels() private val closeSearchCallback = CloseSearchCallback() + private val appUpdateDialog = AppUpdateDialog(this) private lateinit var navigationDelegate: MainNavigationDelegate private lateinit var appUpdateBadge: OptionsMenuBadgeHelper @@ -198,8 +199,7 @@ class MainActivity : BaseActivity(), AppBarOwner, BottomNav R.id.action_app_update -> { viewModel.appUpdate.value?.also { - AppUpdateDialog(this) - .show(it) + appUpdateDialog.show(it) } != null } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt index c73d73c9e..c97316613 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/SettingsActivity.kt @@ -29,6 +29,7 @@ import org.koitharu.kotatsu.databinding.ActivitySettingsBinding import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.settings.about.AboutSettingsFragment +import org.koitharu.kotatsu.settings.about.AppUpdateDialog import org.koitharu.kotatsu.settings.sources.SourceSettingsFragment import org.koitharu.kotatsu.settings.sources.SourcesManageFragment import org.koitharu.kotatsu.settings.tracker.TrackerSettingsFragment @@ -41,6 +42,8 @@ class SettingsActivity : AppBarOwner, FragmentManager.OnBackStackChangedListener { + val appUpdateDialog = AppUpdateDialog(this) + override val appBar: AppBarLayout get() = viewBinding.appbar diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt index cda8c9fdd..d4eb912cf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AboutSettingsFragment.kt @@ -20,6 +20,7 @@ import org.koitharu.kotatsu.core.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observeEvent +import org.koitharu.kotatsu.settings.SettingsActivity import javax.inject.Inject @AndroidEntryPoint @@ -76,7 +77,7 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) { Snackbar.make(listView, R.string.no_update_available, Snackbar.LENGTH_SHORT).show() return } - AppUpdateDialog(context ?: return).show(version) + (activity as SettingsActivity).appUpdateDialog.show(version) } private fun openLink(url: String, title: CharSequence?) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AppUpdateDialog.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AppUpdateDialog.kt index 8b22218d6..cc0587718 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AppUpdateDialog.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/about/AppUpdateDialog.kt @@ -1,10 +1,14 @@ package org.koitharu.kotatsu.settings.about +import android.Manifest import android.app.DownloadManager import android.content.Context import android.content.Intent +import android.os.Build import android.os.Environment import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity import androidx.core.net.toUri import androidx.core.text.buildSpannedString import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -14,19 +18,32 @@ import org.koitharu.kotatsu.core.github.AppVersion import org.koitharu.kotatsu.core.util.FileSize import com.google.android.material.R as materialR -class AppUpdateDialog(private val context: Context) { +class AppUpdateDialog(private val activity: AppCompatActivity) { + + private lateinit var latestVersion: AppVersion + + private val permissionRequest = activity.registerForActivityResult( + ActivityResultContracts.RequestPermission(), + ) { + if (it) { + downloadUpdateImpl() + } else { + openInBrowser() + } + } fun show(version: AppVersion) { + latestVersion = version val message = buildSpannedString { - append(context.getString(R.string.new_version_s, version.name)) + append(activity.getString(R.string.new_version_s, version.name)) appendLine() - append(context.getString(R.string.size_s, FileSize.BYTES.format(context, version.apkSize))) + append(activity.getString(R.string.size_s, FileSize.BYTES.format(activity, version.apkSize))) appendLine() appendLine() - append(Markwon.create(context).toMarkdown(version.description)) + append(Markwon.create(activity).toMarkdown(version.description)) } MaterialAlertDialogBuilder( - context, + activity, materialR.style.ThemeOverlay_Material3_MaterialAlertDialog_Centered, ) .setTitle(R.string.app_update_available) @@ -34,24 +51,38 @@ class AppUpdateDialog(private val context: Context) { .setIcon(R.drawable.ic_app_update) .setNeutralButton(R.string.open_in_browser) { _, _ -> val intent = Intent(Intent.ACTION_VIEW, version.url.toUri()) - context.startActivity(Intent.createChooser(intent, context.getString(R.string.open_in_browser))) + activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.open_in_browser))) }.setPositiveButton(R.string.update) { _, _ -> - downloadUpdate(version) + downloadUpdate() }.setNegativeButton(android.R.string.cancel, null) .setCancelable(false) .create() .show() } - private fun downloadUpdate(version: AppVersion) { + private fun downloadUpdate() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + permissionRequest.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } else { + downloadUpdateImpl() + } + } + + private fun downloadUpdateImpl() { + val version = latestVersion val url = version.apkUrl.toUri() - val dm = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + val dm = activity.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager val request = DownloadManager.Request(url) - .setTitle("${context.getString(R.string.app_name)} v${version.name}") + .setTitle("${activity.getString(R.string.app_name)} v${version.name}") .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, url.lastPathSegment) .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) .setMimeType("application/vnd.android.package-archive") dm.enqueue(request) - Toast.makeText(context, R.string.download_started, Toast.LENGTH_SHORT).show() + Toast.makeText(activity, R.string.download_started, Toast.LENGTH_SHORT).show() + } + + private fun openInBrowser() { + val intent = Intent(Intent.ACTION_VIEW, latestVersion.url.toUri()) + activity.startActivity(Intent.createChooser(intent, activity.getString(R.string.open_in_browser))) } }