diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 457881bcb..89d3213d7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -78,18 +78,13 @@ dependencies { implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.2.0") implementation("dev.rikka.rikkax.insets:insets:1.1.1") implementation("dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.1") + implementation("io.noties.markwon:core:4.6.2") val vBAdapt = "4.0.0" val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter" implementation("${bindingAdapter}:${vBAdapt}") implementation("${bindingAdapter}-recyclerview:${vBAdapt}") - val vMarkwon = "4.6.2" - implementation("io.noties.markwon:core:${vMarkwon}") - implementation("io.noties.markwon:html:${vMarkwon}") - implementation("io.noties.markwon:image:${vMarkwon}") - implementation("com.caverock:androidsvg:1.4") - val vLibsu = "3.2.1" implementation("com.github.topjohnwu.libsu:core:${vLibsu}") implementation("com.github.topjohnwu.libsu:io:${vLibsu}") diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt index 378daa1cb..fe03cc5bc 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt @@ -14,20 +14,19 @@ import com.topjohnwu.magisk.R import com.topjohnwu.magisk.core.ForegroundTracker import com.topjohnwu.magisk.core.base.BaseService import com.topjohnwu.magisk.core.intent -import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream import com.topjohnwu.magisk.core.utils.ProgressInputStream import com.topjohnwu.magisk.di.ServiceLocator -import com.topjohnwu.magisk.ktx.copyAndClose import com.topjohnwu.magisk.ktx.synchronized import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications.mgr -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch import okhttp3.ResponseBody import timber.log.Timber import java.io.IOException import java.io.InputStream -import java.util.* -import kotlin.collections.HashMap class DownloadService : BaseService() { @@ -67,11 +66,11 @@ class DownloadService : BaseService() { val stream = service.fetchFile(subject.url).toProgressStream(subject) when (subject) { is Subject.Manager -> handleAPK(subject, stream) - else -> stream.copyAndClose(subject.file.outputStream()) + else -> stream.toModule(subject.file, service.fetchInstaller().byteStream()) } if (ForegroundTracker.hasForeground) { remove(subject.notifyId) - subject.pendingIntent(this@DownloadService).send() + subject.pendingIntent(this@DownloadService)?.send() } else { notifyFinish(subject) } diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt index 9e3f0c4f4..ef90b0f61 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt @@ -1,14 +1,18 @@ package com.topjohnwu.magisk.core.download +import android.app.AlarmManager +import android.app.PendingIntent +import android.content.Intent +import androidx.core.content.getSystemService import androidx.core.net.toFile import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.core.ForegroundTracker import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.tasks.HideAPK import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream import com.topjohnwu.magisk.ktx.copyAndClose -import com.topjohnwu.magisk.ktx.relaunchApp import com.topjohnwu.magisk.ktx.writeTo import java.io.File import java.io.InputStream @@ -55,9 +59,17 @@ suspend fun DownloadService.handleAPK(subject: Subject.Manager, stream: InputStr apk.delete() patched.renameTo(apk) } else { - // Simply relaunch the app + val intent = packageManager.getLaunchIntentForPackage(packageName) + intent!!.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + //noinspection InlinedApi + val flag = PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + val pending = PendingIntent.getActivity(this, id, intent, flag) + if (ForegroundTracker.hasForeground) { + val alarm = getSystemService() + alarm!!.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pending) + } stopSelf() - relaunchApp(this) + Runtime.getRuntime().exit(0) } } else { write(subject.file.outputStream()) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/ModuleProcessor.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/ModuleProcessor.kt new file mode 100644 index 000000000..5c0f57232 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/ModuleProcessor.kt @@ -0,0 +1,38 @@ +package com.topjohnwu.magisk.core.download + +import android.net.Uri +import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream +import com.topjohnwu.magisk.ktx.forEach +import com.topjohnwu.magisk.ktx.withStreams +import java.io.InputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream + +fun InputStream.toModule(file: Uri, installer: InputStream) { + + val input = ZipInputStream(buffered()) + val output = ZipOutputStream(file.outputStream().buffered()) + + withStreams(input, output) { zin, zout -> + zout.putNextEntry(ZipEntry("META-INF/")) + zout.putNextEntry(ZipEntry("META-INF/com/")) + zout.putNextEntry(ZipEntry("META-INF/com/google/")) + zout.putNextEntry(ZipEntry("META-INF/com/google/android/")) + zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary")) + installer.copyTo(zout) + + zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script")) + zout.write("#MAGISK\n".toByteArray(charset("UTF-8"))) + + zin.forEach { entry -> + val path = entry.name + if (path.isNotEmpty() && !path.startsWith("META-INF")) { + zout.putNextEntry(ZipEntry(path)) + if (!entry.isDirectory) { + zin.copyTo(zout) + } + } + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt index 529b4cdf3..6fe79972b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt @@ -35,7 +35,7 @@ sealed class Subject : Parcelable { abstract val title: String abstract val notifyId: Int - abstract fun pendingIntent(context: Context): PendingIntent + abstract fun pendingIntent(context: Context): PendingIntent? @Parcelize class Module( @@ -53,7 +53,7 @@ sealed class Subject : Parcelable { override fun pendingIntent(context: Context) = when (action) { Action.Flash -> FlashFragment.installIntent(context, file) - else -> Intent().toPending(context) + else -> null } } diff --git a/app/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt b/app/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt index 1246bc5e3..78b36e412 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/model/UpdateInfo.kt @@ -31,6 +31,7 @@ data class ModuleJson( val version: String, val versionCode: Int, val zipUrl: String, + val changelog: String, ) @JsonClass(generateAdapter = true) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/model/module/OnlineModule.kt b/app/src/main/java/com/topjohnwu/magisk/core/model/module/OnlineModule.kt index 27cfb4100..302a0c924 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/model/module/OnlineModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/model/module/OnlineModule.kt @@ -11,9 +11,10 @@ data class OnlineModule( override var version: String, override var versionCode: Int, val zipUrl: String, + val changelog: String, ) : Module(), Parcelable { constructor(local: LocalModule, json: ModuleJson) : - this(local.id, local.name, json.version, json.versionCode, json.zipUrl) + this(local.id, local.name, json.version, json.versionCode, json.zipUrl, json.changelog) val downloadFilename get() = "$name-$version($versionCode).zip".legalFilename() diff --git a/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt b/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt index c5079a0f4..fd5f09f31 100644 --- a/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt +++ b/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt @@ -4,6 +4,7 @@ import android.animation.ValueAnimator import android.content.res.ColorStateList import android.graphics.Paint import android.graphics.drawable.Drawable +import android.text.Spanned import android.util.TypedValue import android.view.View import android.view.ViewGroup @@ -29,11 +30,8 @@ import com.google.android.material.chip.Chip import com.google.android.material.textfield.TextInputLayout import com.topjohnwu.magisk.R import com.topjohnwu.magisk.di.ServiceLocator -import com.topjohnwu.magisk.ktx.coroutineScope import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.widget.IndeterminateCheckBox -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import kotlin.math.roundToInt @BindingAdapter("gone") @@ -57,10 +55,8 @@ fun setInvisibleUnless(view: View, invisibleUnless: Boolean) { } @BindingAdapter("markdownText") -fun setMarkdownText(tv: TextView, text: CharSequence) { - tv.coroutineScope.launch(Dispatchers.IO) { - ServiceLocator.markwon.setMarkdown(tv, text.toString()) - } +fun setMarkdownText(tv: TextView, markdown: Spanned) { + ServiceLocator.markwon.setParsedMarkdown(tv, markdown) } @BindingAdapter("onNavigationClick") diff --git a/app/src/main/java/com/topjohnwu/magisk/di/Networking.kt b/app/src/main/java/com/topjohnwu/magisk/di/Networking.kt index 21fef91b5..99f5ac66d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/Networking.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/Networking.kt @@ -1,16 +1,17 @@ package com.topjohnwu.magisk.di import android.content.Context +import android.text.method.LinkMovementMethod import com.squareup.moshi.Moshi import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.ProviderInstaller import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Info -import com.topjohnwu.magisk.ktx.precomputedText -import com.topjohnwu.magisk.utils.MarkwonImagePlugin +import com.topjohnwu.magisk.core.utils.currentLocale import io.noties.markwon.Markwon -import io.noties.markwon.html.HtmlPlugin +import io.noties.markwon.utils.NoCopySpannableFactory import okhttp3.Cache +import okhttp3.ConnectionSpec import okhttp3.Dns import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient @@ -46,7 +47,8 @@ private class DnsResolver(client: OkHttpClient) : Dns { if (Config.doh) { try { return doh.lookup(hostname) - } catch (e: UnknownHostException) {} + } catch (e: UnknownHostException) { + } } return Dns.SYSTEM.lookup(hostname) } @@ -61,11 +63,16 @@ fun createOkHttpClient(context: Context): OkHttpClient { builder.addInterceptor(HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BASIC }) + } else { + builder.connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS)) } + builder.dns(DnsResolver(builder.build())) + builder.addInterceptor { chain -> val request = chain.request().newBuilder() - request.header("User-Agent", "Magisk ${BuildConfig.VERSION_CODE}") + request.header("User-Agent", "Magisk/${BuildConfig.VERSION_CODE}") + request.header("Accept-Language", currentLocale.toLanguageTag()) chain.proceed(request.build()) } @@ -73,7 +80,6 @@ fun createOkHttpClient(context: Context): OkHttpClient { Info.hasGMS = false } - builder.dns(DnsResolver(builder.build())) return builder.build() } @@ -96,13 +102,17 @@ inline fun createApiService(retrofitBuilder: Retrofit.Builder, baseU .create(T::class.java) } -fun createMarkwon(context: Context, okHttpClient: OkHttpClient): Markwon { +fun createMarkwon(context: Context): Markwon { return Markwon.builder(context) - .textSetter { textView, spanned, _, onComplete -> - textView.tag = onComplete - textView.precomputedText = spanned + .textSetter { textView, spanned, bufferType, onComplete -> + textView.apply { + post { + movementMethod = LinkMovementMethod.getInstance() + setSpannableFactory(NoCopySpannableFactory.getInstance()) + setText(spanned, bufferType) + onComplete.run() + } + } } - .usePlugin(HtmlPlugin.create()) - .usePlugin(MarkwonImagePlugin(okHttpClient)) .build() } diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ServiceLocator.kt b/app/src/main/java/com/topjohnwu/magisk/di/ServiceLocator.kt index 0d297853e..26780cd67 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/ServiceLocator.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/ServiceLocator.kt @@ -39,7 +39,7 @@ object ServiceLocator { // Networking val okhttp by lazy { createOkHttpClient(context) } val retrofit by lazy { createRetrofit(okhttp) } - val markwon by lazy { createMarkwon(context, okhttp) } + val markwon by lazy { createMarkwon(context) } val networkService by lazy { NetworkService( createApiService(retrofit, Const.Url.GITHUB_PAGE_URL), diff --git a/app/src/main/java/com/topjohnwu/magisk/events/dialog/MarkDownDialog.kt b/app/src/main/java/com/topjohnwu/magisk/events/dialog/MarkDownDialog.kt index 1453ae60a..73a069bc6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/events/dialog/MarkDownDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/events/dialog/MarkDownDialog.kt @@ -10,9 +10,8 @@ import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.view.MagiskDialog import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import timber.log.Timber -import kotlin.coroutines.cancellation.CancellationException +import java.io.IOException abstract class MarkDownDialog : DialogEvent() { @@ -23,17 +22,13 @@ abstract class MarkDownDialog : DialogEvent() { with(dialog) { val view = LayoutInflater.from(context).inflate(R.layout.markdown_window_md2, null) setView(view) - (ownerActivity as BaseActivity).lifecycleScope.launch { - val tv = view.findViewById(R.id.md_txt) - withContext(Dispatchers.IO) { - try { - ServiceLocator.markwon.setMarkdown(tv, getMarkdownText()) - } catch (e: Exception) { - if (e is CancellationException) - throw e - Timber.e(e) - tv.post { tv.setText(R.string.download_file_error) } - } + val tv = view.findViewById(R.id.md_txt) + (ownerActivity as BaseActivity).lifecycleScope.launch(Dispatchers.IO) { + try { + ServiceLocator.markwon.setMarkdown(tv, getMarkdownText()) + } catch (e: IOException) { + Timber.e(e) + tv.post { tv.setText(R.string.download_file_error) } } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt index 03501dd12..4fccf7c44 100644 --- a/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/events/dialog/ModuleInstallDialog.kt @@ -1,16 +1,24 @@ package com.topjohnwu.magisk.events.dialog import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.download.Action import com.topjohnwu.magisk.core.download.DownloadService import com.topjohnwu.magisk.core.download.Subject import com.topjohnwu.magisk.core.model.module.OnlineModule +import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.view.MagiskDialog -class ModuleInstallDialog(private val item: OnlineModule) : DialogEvent() { +class ModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog() { + + private val svc get() = ServiceLocator.networkService + + override suspend fun getMarkdownText(): String { + val str = svc.fetchString(item.changelog) + return if (str.length > 1000) str.substring(0, 1000) else str + } override fun build(dialog: MagiskDialog) { + super.build(dialog) dialog.apply { fun download(install: Boolean) { @@ -19,21 +27,21 @@ class ModuleInstallDialog(private val item: OnlineModule) : DialogEvent() { DownloadService.start(context, subject) } - setTitle(context.getString(R.string.repo_install_title, item.name)) - setMessage(context.getString(R.string.repo_install_msg, item.downloadFilename)) + val title = context.getString(R.string.repo_install_title, + item.name, item.version, item.versionCode) + + setTitle(title) setCancelable(true) setButton(MagiskDialog.ButtonType.NEGATIVE) { text = R.string.download - icon = R.drawable.ic_download_md2 onClick { download(false) } } - - if (Info.env.isActive) { - setButton(MagiskDialog.ButtonType.POSITIVE) { - text = R.string.install - icon = R.drawable.ic_install - onClick { download(true) } - } + setButton(MagiskDialog.ButtonType.POSITIVE) { + text = R.string.install + onClick { download(true) } + } + setButton(MagiskDialog.ButtonType.NEUTRAL) { + text = android.R.string.cancel } } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ktx/XAndroid.kt b/app/src/main/java/com/topjohnwu/magisk/ktx/XAndroid.kt index d3e65c361..711082f75 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ktx/XAndroid.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ktx/XAndroid.kt @@ -299,53 +299,6 @@ val View.activity: Activity get() { } } -var View.coroutineScope: CoroutineScope - get() = getTag(R.id.coroutineScope) as? CoroutineScope - ?: (activity as? BaseActivity)?.lifecycleScope - ?: GlobalScope - set(value) = setTag(R.id.coroutineScope, value) - -@set:BindingAdapter("precomputedText") -var TextView.precomputedText: CharSequence - get() = text - set(value) { - val callback = tag as? Runnable - - coroutineScope.launch(Dispatchers.IO) { - if (SDK_INT >= 29) { - // Internally PrecomputedTextCompat will use platform API on API 29+ - // Due to some stupid crap OEM (Samsung) implementation, this can actually - // crash our app. Directly use platform APIs with some workarounds - val pre = PrecomputedText.create(value, textMetricsParams) - post { - try { - text = pre - } catch (e: IllegalArgumentException) { - // Override to computed params to workaround crashes - textMetricsParams = pre.params - text = pre - } - isGone = false - callback?.run() - } - } else { - val tv = this@precomputedText - val params = TextViewCompat.getTextMetricsParams(tv) - val pre = PrecomputedTextCompat.create(value, params) - post { - TextViewCompat.setPrecomputedText(tv, pre) - isGone = false - callback?.run() - } - } - } - } - -fun Int.dpInPx(): Int { - val scale = AppContext.resources.displayMetrics.density - return (this * scale + 0.5).toInt() -} - @SuppressLint("PrivateApi") fun getProperty(key: String, def: String): String { runCatching { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt index c9763c292..e4ce11e78 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallFragment.kt @@ -4,12 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.lifecycle.viewModelScope import com.topjohnwu.magisk.R import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding import com.topjohnwu.magisk.di.viewModel -import com.topjohnwu.magisk.ktx.coroutineScope class InstallFragment : BaseUIFragment() { @@ -19,9 +17,6 @@ class InstallFragment : BaseUIFragment readText() - Const.Url.CHANGELOG_URL.isEmpty() -> "" - else -> { - val text = svc.fetchString(Const.Url.CHANGELOG_URL) - writeText(text) - text - } + val file = File(AppContext.cacheDir, "${BuildConfig.VERSION_CODE}.md") + val text = when { + file.exists() -> file.readText() + Const.Url.CHANGELOG_URL.isEmpty() -> "" + else -> { + val str = svc.fetchString(Const.Url.CHANGELOG_URL) + file.writeText(str) + str } } + notes = ServiceLocator.markwon.toMarkdown(text) } catch (e: IOException) { Timber.e(e) } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/MarkwonImagePlugin.kt b/app/src/main/java/com/topjohnwu/magisk/utils/MarkwonImagePlugin.kt deleted file mode 100644 index f87de7c07..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/utils/MarkwonImagePlugin.kt +++ /dev/null @@ -1,233 +0,0 @@ -package com.topjohnwu.magisk.utils - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.Rect -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.Drawable -import android.graphics.drawable.PictureDrawable -import android.graphics.drawable.ShapeDrawable -import android.net.Uri -import android.text.Spanned -import android.text.style.DynamicDrawableSpan -import android.widget.TextView -import androidx.annotation.WorkerThread -import com.caverock.androidsvg.SVG -import com.caverock.androidsvg.SVGParseException -import com.topjohnwu.magisk.di.AppContext -import com.topjohnwu.superuser.internal.WaitRunnable -import io.noties.markwon.AbstractMarkwonPlugin -import io.noties.markwon.MarkwonSpansFactory -import io.noties.markwon.image.* -import io.noties.markwon.image.data.DataUriSchemeHandler -import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler -import kotlinx.coroutines.* -import okhttp3.OkHttpClient -import org.commonmark.node.Image -import timber.log.Timber -import java.io.InputStream - -// Differences with Markwon stock ImagePlugin: -// -// We assume beforeSetText() will be run in a background thread, and in that method -// we download/decode all drawables before sending the spanned markdown CharSequence -// to the next stage. We also get our surrounding TextView width to properly -// resize our images. -// -// This is required for PrecomputedText to properly take the images into account -// when precomputing the metrics of TextView -// -// Basically, we want nothing to do with AsyncDrawable -class MarkwonImagePlugin(okHttp: OkHttpClient) : AbstractMarkwonPlugin() { - - override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) { - builder.setFactory(Image::class.java) { _, props -> - val dest = ImageProps.DESTINATION.require(props) - val size = ImageProps.IMAGE_SIZE.get(props) - ImageSpan(dest, size) - } - } - - @WorkerThread - override fun beforeSetText(tv: TextView, markdown: Spanned) { - if (markdown.isEmpty()) - return - - val spans = markdown.getSpans(0, markdown.length, ImageSpan::class.java) - if (spans == null || spans.isEmpty()) - return - - // Get TextView sizes before setText() to resize all images - val wr = WaitRunnable { - val width = tv.width - tv.paddingLeft - tv.paddingRight - spans.forEach { it.canvasWidth = width } - } - tv.post(wr) - - runBlocking { - // Wait for drawable to be set - spans.forEach { it.await() } - // Wait for canvasWidth to be set - wr.waitUntilDone() - } - } - - private val schemeHandlers = HashMap(3) - private val mediaDecoders = HashMap(0) - private val defaultMediaDecoder = DefaultMediaDecoder.create() - - init { - addSchemeHandler(DataUriSchemeHandler.create()) - addSchemeHandler(OkHttpNetworkSchemeHandler.create(okHttp)) - addMediaDecoder(SVGDecoder()) - } - - private fun addSchemeHandler(schemeHandler: SchemeHandler) { - for (scheme in schemeHandler.supportedSchemes()) { - schemeHandlers[scheme] = schemeHandler - } - } - - private fun addMediaDecoder(mediaDecoder: MediaDecoder) { - for (type in mediaDecoder.supportedTypes()) { - mediaDecoders[type] = mediaDecoder - } - } - - // Modified from AsyncDrawableLoaderImpl.execute(asyncDrawable) - fun loadDrawable(destination: String): Drawable? { - val uri = Uri.parse(destination) - var drawable: Drawable? = null - - try { - val scheme = uri.scheme - check(scheme != null && scheme.isNotEmpty()) { - "No scheme is found: $destination" - } - - // obtain scheme handler - val schemeHandler = schemeHandlers[scheme] - ?: throw IllegalStateException("No scheme-handler is found: $destination") - - // handle scheme - val imageItem = schemeHandler.handle(destination, uri) - - // if resulting imageItem needs further decoding -> proceed - drawable = if (imageItem.hasDecodingNeeded()) { - val withDecodingNeeded = imageItem.asWithDecodingNeeded - val mediaDecoder = mediaDecoders[withDecodingNeeded.contentType()] - ?: defaultMediaDecoder - mediaDecoder.decode( - withDecodingNeeded.contentType(), - withDecodingNeeded.inputStream() - ) - } else { - imageItem.asWithResult.result() - } - } catch (t: Throwable) { - Timber.e(t, "Error loading image: $destination") - } - - // apply intrinsic bounds (but only if they are empty) - if (drawable != null && drawable.bounds.isEmpty) - DrawableUtils.applyIntrinsicBounds(drawable) - - return drawable - } - - inner class ImageSpan( - dest: String, - private val size: ImageSize? - ) : DynamicDrawableSpan(ALIGN_BOTTOM) { - - var canvasWidth = 0 - private var measured = false - private lateinit var draw: Drawable - private val job: Job - - init { - // Asynchronously download/decode images in the background - job = GlobalScope.launch(Dispatchers.IO) { - draw = loadDrawable(dest) ?: ShapeDrawable() - } - } - - suspend fun await() = job.join() - - override fun getDrawable() = draw - - private fun defaultBounds(): Rect { - val bounds: Rect = draw.bounds - if (!bounds.isEmpty) { - return bounds - } - val intrinsicBounds = DrawableUtils.intrinsicBounds(draw) - if (!intrinsicBounds.isEmpty) { - return intrinsicBounds - } - return Rect(0, 0, 1, 1) - } - - private fun measure(paint: Paint) { - if (measured || canvasWidth == 0) - return - measured = true - val bound = - SizeResolver.resolveImageSize(size, defaultBounds(), canvasWidth, paint.textSize) - draw.bounds = bound - } - - override fun getSize( - paint: Paint, text: CharSequence?, start: Int, end: Int, fm: Paint.FontMetricsInt? - ): Int { - measure(paint) - return super.getSize(paint, text, start, end, fm) - } - } - - object SizeResolver : ImageSizeResolverDef() { - // Expose protected API - public override fun resolveImageSize( - imageSize: ImageSize?, - imageBounds: Rect, - canvasWidth: Int, - textSize: Float - ): Rect { - return super.resolveImageSize(imageSize, imageBounds, canvasWidth, textSize) - } - } - - class SVGDecoder: MediaDecoder() { - override fun supportedTypes() = listOf("image/svg+xml") - - override fun decode(contentType: String?, inputStream: InputStream): Drawable { - val svg = try { - SVG.getFromInputStream(inputStream) - } catch (e: SVGParseException) { - throw IllegalStateException("Exception decoding SVG", e) - } - - val w = svg.documentWidth - val h = svg.documentHeight - - if (w <= 0 || h <= 0) { - val picture = svg.renderToPicture() - return PictureDrawable(picture) - } - - val density: Float = AppContext.resources.displayMetrics.density - - val width = (w * density + .5f).toInt() - val height = (h * density + .5f).toInt() - - val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - canvas.scale(density, density) - svg.renderToCanvas(canvas) - - return BitmapDrawable(AppContext.resources, bitmap) - } - - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt index f095f7de0..c5c54f169 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt @@ -26,12 +26,11 @@ object Notifications { fun setup(context: Context) { if (SDK_INT >= 26) { - var channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL, - context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT) - mgr.createNotificationChannel(channel) - channel = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL, - context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW) - mgr.createNotificationChannel(channel) + val channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL, + context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT) + val channel2 = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL, + context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW) + mgr.createNotificationChannels(listOf(channel, channel2)) } } diff --git a/app/src/main/res/layout/fragment_install_md2.xml b/app/src/main/res/layout/fragment_install_md2.xml index b814c1920..59a8fd06b 100644 --- a/app/src/main/res/layout/fragment_install_md2.xml +++ b/app/src/main/res/layout/fragment_install_md2.xml @@ -223,11 +223,11 @@ @@ -237,8 +237,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" + android:breakStrategy="simple" + android:hyphenationFrequency="none" android:textAppearance="@style/AppearanceFoundation.Caption" - android:visibility="gone" + tools:ignore="UnusedAttribute" tools:maxLines="5" tools:text="@tools:sample/lorem/random" tools:visibility="visible" /> diff --git a/app/src/main/res/layout/markdown_window_md2.xml b/app/src/main/res/layout/markdown_window_md2.xml index f0fd7ac4f..da63f557e 100644 --- a/app/src/main/res/layout/markdown_window_md2.xml +++ b/app/src/main/res/layout/markdown_window_md2.xml @@ -1,5 +1,6 @@ @@ -9,7 +10,10 @@ android:layout_height="wrap_content" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" + android:breakStrategy="simple" + android:hyphenationFrequency="none" android:paddingTop="10dp" - android:textAppearance="@style/AppearanceFoundation.Caption" /> + android:textAppearance="@style/AppearanceFoundation.Caption" + tools:ignore="UnusedAttribute" /> - \ No newline at end of file + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 38871da28..d69a0f17a 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -174,7 +174,6 @@ نعم لا تثبيت %1$s - هل تريد تثبيت %1$s ? تنزيل إعادة التشغيل معلومات الأصدار الجديد diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml index 0cb57042c..1a3098fcf 100644 --- a/app/src/main/res/values-az/strings.xml +++ b/app/src/main/res/values-az/strings.xml @@ -44,7 +44,6 @@ %1$s faylını yüklə - %1$s faylını indi yükləmək istəyirsiniz? Yüklə Yenidən Başlat Yeniliklər diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 33ebbcf70..cba21e991 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -172,8 +172,7 @@ Так Не - Усталяваць %1$s - Усталяваць %1$s? + Усталяваць %1$s %2$s(%3$s) Спампаваць Перазапуск Пра выпуск diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index f672f3c98..37422fc9c 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -36,8 +36,7 @@ Списък с промени - Инсталиране на %1$s - Желаете ли да инсталирате %1$s сега? + Инсталиране на %1$s %2$s(%3$s) Изтегляне Рестартиране Достъпно е издание на Magisk. diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index e152381b3..da9586c01 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -186,8 +186,7 @@ No - Instal·lar %1$s - Vol instal·lar %1$s ara? + Instal·lar %1$s %2$s(%3$s) Baixar Reiniciar Notes de llançament diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index d5bc4b815..3f1ed7b17 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -185,8 +185,7 @@ ANO NE - Instalovat %1$s - Chcete nyní nainstalovat %1$s? + Instalovat %1$s %2$s(%3$s) Stáhnout Restartovat Poznámky k vydání diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index dfe93809e..ecc3e4196 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -194,7 +194,6 @@ Ja Nein %1$s installieren - Möchten Sie %1$s jetzt installieren? Herunterladen Neustart Anmerkungen zur Veröffentlichung diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 274521d17..9d68e50a2 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -185,8 +185,7 @@ Ναι Όχι - Εγκατάσταση %1$s - Θέλετε να εγκαταστήσετε το %1$s τώρα; + Εγκατάσταση %1$s %2$s(%3$s) Λήψη Επανεκκίνηση Σημειώσεις έκδοσης diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ef58f4b96..7f6ce9efe 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -195,8 +195,7 @@ No - Instalar %1$s - ¿Desea instalar %1$s ahora? + Instalar %1$s %2$s(%3$s) Descargar Reiniciar Notas de lanzamiento diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index d45d7fdca..08990027b 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -175,8 +175,7 @@ Jah Ei - Installi %1$s - Kas soovid kohe installida %1$s? + Installi %1$s %2$s(%3$s) Allalaadimine Taaskäivita Väljalaskemärkmed diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 00b1f6aa0..e6294cb9e 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -171,7 +171,6 @@ بله نه نصب کرد %1$s - آیا می خواهید %1$s نصب شود؟ انلود کردن راه اندازی مجدد نکته های نسخه diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 5ae9890f0..222a41062 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -195,8 +195,7 @@ Oui Non - Installer %1$s - Voulez‑vous installer %1$s maintenant ? + Installer %1$s %2$s(%3$s) Télécharger Redémarrer Notes de version diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 93363d9e2..d807af45a 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -177,8 +177,7 @@ हाँ नहीं - इंस्टॉल %1$s - क्या आप अभी %1$s इंस्टॉल करना चाहते हैं? + इंस्टॉल %1$s %2$s(%3$s) डाउनलोड रीबूट रिलीज नोट्स diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index ff3df236b..8535b4fc6 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -176,8 +176,7 @@ Da Ne - Instaliraj %1$s - Da li želite instalirati %1$s sada? + Instaliraj %1$s %2$s(%3$s) Preuzmi Ponovno pokreni Bilješke o izdavanju aplikacije diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 95ee9ff56..dc95b470a 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -180,8 +180,7 @@ Ya Tidak - Instal %1$s - Apakah Anda ingin menginstal %1$s sekarang? + Instal %1$s %2$s(%3$s) Download Nyalakan ulang Catatan rilis diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 56c4e0d37..d388dc63d 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -193,8 +193,7 @@ No - Installazione di %1$s - Vuoi installare %1$s? + Installazione di %1$s %2$s(%3$s) Download Riavvia Note di rilascio diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 714be8ebb..d3e20ca43 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -183,7 +183,6 @@ כן לא התקן %1$s - האם ברצונך להתקין את %1$s כעת? הורדה הפעלה מחדש הערות שחרור diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 98ae5e6ea..99719903a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -197,7 +197,6 @@ 対応 非対応 %1$s をインストール - %1$s をインストールしますか? ダウンロード 再起動 更新履歴 diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index cb7e8a038..8a67567a1 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -187,7 +187,6 @@ დიახ არა %1$s-ის ინსტალაცია - გნებავთ %1$s-ის ახლავე დაინსტალირება? გადმოწერა გადატვირთვა რელიზის შენიშვნები diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 0cd8093cc..31b182b4b 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -191,7 +191,6 @@ 아니오 %1$s 설치 - 정말 %1$s을(를) 설치하시겠습니까? 다운로드 다시 시작 릴리즈 노트 diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml index 0a181631c..1b6d34d21 100644 --- a/app/src/main/res/values-lt/strings.xml +++ b/app/src/main/res/values-lt/strings.xml @@ -36,8 +36,7 @@ Pakeitimų sąrašas - Instaliuoti %1$s - Ar jūs norite instaliuoti %1$s? + Instaliuoti %1$s %2$s(%3$s) Atsisiųsti Perkrauti Atsirado nauja Magisk versija! diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index c7d3a3b0b..947690512 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -52,8 +52,7 @@ Рестартирање за 5 секунди… - Инсталирај %1$s - Дали сакате да го инсталирате %1$s сега? + Инсталирај %1$s %2$s(%3$s) Преземи Рестартирај Белешки за изданието diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml index 2e1c67a57..fcf8d286c 100644 --- a/app/src/main/res/values-nb/strings.xml +++ b/app/src/main/res/values-nb/strings.xml @@ -186,8 +186,7 @@ Ja Nei - Installer %1$s - Installer %1$s nå? + Installer %1$s %2$s(%3$s) Last ned Omstart Utgivelsesnotater diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 31de9afba..663c1a460 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -172,8 +172,7 @@ Ja Nee - %1$s installeren - Wil je %1$s nu installeren? + %1$s installeren %2$s(%3$s) Downloaden Herstarten Wijzigingslog diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index 43ca33653..79c4f3dd7 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -177,8 +177,7 @@ ਹਾਂ ਨਹੀਂ - ਇੰਸਟਾਲ %1$s - ਕੀ ਤੁਸੀਂ ਹੁਣੇ %1$s ਇੰਸਟਾਲ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? + ਇੰਸਟਾਲ %1$s %2$s(%3$s) ਡਾਊਨਲੋਡ ਰੀਬੂਟ ਰੀਲਿਜ਼ ਨੋਟਿਸ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 89b6f9466..5fda82ee6 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -186,8 +186,7 @@ Tak Nie - Instalacja %1$s - Czy chcesz teraz zainstalować %1$s ? + Instalacja %1$s %2$s(%3$s) Pobierz Reboot Lista zmian diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 153a2ba52..632ed7006 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -190,8 +190,7 @@ Sim Não - Instalar %1$s - Deseja instalar %1$s agora? + Instalar %1$s %2$s(%3$s) Download Reinicializar Notas de versão diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index f7f0ca42c..16f01a6c6 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -32,8 +32,7 @@ Lista de alterações da aplicação - Instalar %1$s - Deseja instalar%1$s agora? + Instalar %1$s %2$s(%3$s) Transferir Reiniciar Nova atualização do Magisk disponível! diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 67b6a039e..e7493a907 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -193,8 +193,7 @@ Da Nu - Instalează %1$s - Vrei să instalezi acum %1$s? + Instalează %1$s %2$s(%3$s) Descarcă Repornește Note privind versiunea diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6dd995081..3d6b43ff0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -196,8 +196,7 @@ Да Нет - Установка %1$s - Установить %1$s ? + Установка %1$s %2$s(%3$s) Скачать Перезагрузка О версии diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index c98af4e5f..39f5cd9ae 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -196,8 +196,7 @@ Áno Nie - Nainštalovať %1$s - Chcete teraz nainštalovať %1$s? + Nainštalovať %1$s %2$s(%3$s) Stiahnuť Reštartovať Poznámky k vydaniu diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index 962233a54..9e65aa7c9 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -194,8 +194,7 @@ Po Jo - Instalo %1$s - Dëshiron të instalosh %1$s tani? + Instalo %1$s %2$s(%3$s) Shkarko Rinis Shënimet e lëshimit diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index e2c9a618a..00ada4f4d 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -34,8 +34,7 @@ Дневник промена апликације - Инсталирај %1$s - Да ли желите да инсталирате %1$s? + Инсталирај %1$s %2$s(%3$s) Преузми Рестартуј Нови Адбејт Магиска Доступан! diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 6a8555553..9edc3b1af 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -186,8 +186,7 @@ Ja Nej - Installera %1$s - Vill du installera %1$s nu? + Installera %1$s %2$s(%3$s) Ladda ned Omstart Utgivningsanmärkningar diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index 6cb6d64e5..c5abcdd38 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -186,8 +186,7 @@ ஆம் இல்லை - நிறுவு %1$s - நீங்கள் இப்போது %1$s ஐ நிறுவ விரும்புகிறீர்களா?? + நிறுவு %1$s %2$s(%3$s) பதிவிறக்கம் மறுதொடக்கம் வெளியீட்டு குறிப்புகள் diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 8ab8b617f..33c49171e 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -41,8 +41,7 @@ มีการอัพเดต Magisk! - ติดตั้ง %1$s - ต้องการติดตั้ง %1$s ตอนนี้หรือไม่? + ติดตั้ง %1$s %2$s(%3$s) ดาวน์โหลด รีบู๊ต -้อมูลเพิ่มเติม diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 0dcd65c18..4ea0f69f1 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -187,7 +187,6 @@ Evet Hayır %1$s yükle - %1$s yüklensin mi? İndir Yeniden Başlat Sürüm notları diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 8252efaf7..a51c59477 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -193,8 +193,7 @@ Так Ні - Встановити %1$s - Бажаєте встановити %1$s? + Встановити %1$s %2$s(%3$s) Завантажити Перезавантажити Особливості версії diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 173bb765a..cd51ed772 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -193,8 +193,7 @@ Đồng ý Không - Cài đặt %1$s - Bạn có muốn cài đặt %1$s ngay bây giờ không? + Cài đặt %1$s %2$s(%3$s) Tải xuống Khởi động lại Ghi chú bản phát hành diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index d10acf6ac..a4b89533c 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -196,8 +196,7 @@ - 安装 %1$s - 确认安装 %1$s? + 安装 %1$s %2$s(%3$s) 下载 重启 发布说明 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 7bb102697..3e651e783 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -193,8 +193,7 @@ - 安裝 %1$s - 您現在想要安裝 %1$s 嗎? + 安裝 %1$s %2$s(%3$s) 下載 重新啟動 發布說明 diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index ec81f4f39..e89a6819c 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d8d0e432f..5de4286f9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -197,8 +197,7 @@ Yes No - Install %1$s - Do you want to install %1$s now? + Install %1$s %2$s(%3$s) Download Reboot Release notes