mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 12:05:30 +00:00
Module json add changelog
This commit is contained in:
parent
691e41e22e
commit
bf8b74e996
@ -78,18 +78,13 @@ dependencies {
|
|||||||
implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.2.0")
|
implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.2.0")
|
||||||
implementation("dev.rikka.rikkax.insets:insets:1.1.1")
|
implementation("dev.rikka.rikkax.insets:insets:1.1.1")
|
||||||
implementation("dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.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 vBAdapt = "4.0.0"
|
||||||
val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter"
|
val bindingAdapter = "me.tatarka.bindingcollectionadapter2:bindingcollectionadapter"
|
||||||
implementation("${bindingAdapter}:${vBAdapt}")
|
implementation("${bindingAdapter}:${vBAdapt}")
|
||||||
implementation("${bindingAdapter}-recyclerview:${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"
|
val vLibsu = "3.2.1"
|
||||||
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
|
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
|
||||||
implementation("com.github.topjohnwu.libsu:io:${vLibsu}")
|
implementation("com.github.topjohnwu.libsu:io:${vLibsu}")
|
||||||
|
@ -14,20 +14,19 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.core.ForegroundTracker
|
import com.topjohnwu.magisk.core.ForegroundTracker
|
||||||
import com.topjohnwu.magisk.core.base.BaseService
|
import com.topjohnwu.magisk.core.base.BaseService
|
||||||
import com.topjohnwu.magisk.core.intent
|
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.core.utils.ProgressInputStream
|
||||||
import com.topjohnwu.magisk.di.ServiceLocator
|
import com.topjohnwu.magisk.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.ktx.copyAndClose
|
|
||||||
import com.topjohnwu.magisk.ktx.synchronized
|
import com.topjohnwu.magisk.ktx.synchronized
|
||||||
import com.topjohnwu.magisk.view.Notifications
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
import com.topjohnwu.magisk.view.Notifications.mgr
|
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 okhttp3.ResponseBody
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.*
|
|
||||||
import kotlin.collections.HashMap
|
|
||||||
|
|
||||||
class DownloadService : BaseService() {
|
class DownloadService : BaseService() {
|
||||||
|
|
||||||
@ -67,11 +66,11 @@ class DownloadService : BaseService() {
|
|||||||
val stream = service.fetchFile(subject.url).toProgressStream(subject)
|
val stream = service.fetchFile(subject.url).toProgressStream(subject)
|
||||||
when (subject) {
|
when (subject) {
|
||||||
is Subject.Manager -> handleAPK(subject, stream)
|
is Subject.Manager -> handleAPK(subject, stream)
|
||||||
else -> stream.copyAndClose(subject.file.outputStream())
|
else -> stream.toModule(subject.file, service.fetchInstaller().byteStream())
|
||||||
}
|
}
|
||||||
if (ForegroundTracker.hasForeground) {
|
if (ForegroundTracker.hasForeground) {
|
||||||
remove(subject.notifyId)
|
remove(subject.notifyId)
|
||||||
subject.pendingIntent(this@DownloadService).send()
|
subject.pendingIntent(this@DownloadService)?.send()
|
||||||
} else {
|
} else {
|
||||||
notifyFinish(subject)
|
notifyFinish(subject)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package com.topjohnwu.magisk.core.download
|
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 androidx.core.net.toFile
|
||||||
import com.topjohnwu.magisk.DynAPK
|
import com.topjohnwu.magisk.DynAPK
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.core.ForegroundTracker
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||||
import com.topjohnwu.magisk.ktx.copyAndClose
|
import com.topjohnwu.magisk.ktx.copyAndClose
|
||||||
import com.topjohnwu.magisk.ktx.relaunchApp
|
|
||||||
import com.topjohnwu.magisk.ktx.writeTo
|
import com.topjohnwu.magisk.ktx.writeTo
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -55,9 +59,17 @@ suspend fun DownloadService.handleAPK(subject: Subject.Manager, stream: InputStr
|
|||||||
apk.delete()
|
apk.delete()
|
||||||
patched.renameTo(apk)
|
patched.renameTo(apk)
|
||||||
} else {
|
} 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<AlarmManager>()
|
||||||
|
alarm!!.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pending)
|
||||||
|
}
|
||||||
stopSelf()
|
stopSelf()
|
||||||
relaunchApp(this)
|
Runtime.getRuntime().exit(0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write(subject.file.outputStream())
|
write(subject.file.outputStream())
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,7 @@ sealed class Subject : Parcelable {
|
|||||||
abstract val title: String
|
abstract val title: String
|
||||||
abstract val notifyId: Int
|
abstract val notifyId: Int
|
||||||
|
|
||||||
abstract fun pendingIntent(context: Context): PendingIntent
|
abstract fun pendingIntent(context: Context): PendingIntent?
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class Module(
|
class Module(
|
||||||
@ -53,7 +53,7 @@ sealed class Subject : Parcelable {
|
|||||||
|
|
||||||
override fun pendingIntent(context: Context) = when (action) {
|
override fun pendingIntent(context: Context) = when (action) {
|
||||||
Action.Flash -> FlashFragment.installIntent(context, file)
|
Action.Flash -> FlashFragment.installIntent(context, file)
|
||||||
else -> Intent().toPending(context)
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ data class ModuleJson(
|
|||||||
val version: String,
|
val version: String,
|
||||||
val versionCode: Int,
|
val versionCode: Int,
|
||||||
val zipUrl: String,
|
val zipUrl: String,
|
||||||
|
val changelog: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
|
@ -11,9 +11,10 @@ data class OnlineModule(
|
|||||||
override var version: String,
|
override var version: String,
|
||||||
override var versionCode: Int,
|
override var versionCode: Int,
|
||||||
val zipUrl: String,
|
val zipUrl: String,
|
||||||
|
val changelog: String,
|
||||||
) : Module(), Parcelable {
|
) : Module(), Parcelable {
|
||||||
constructor(local: LocalModule, json: ModuleJson) :
|
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()
|
val downloadFilename get() = "$name-$version($versionCode).zip".legalFilename()
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import android.animation.ValueAnimator
|
|||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.text.Spanned
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -29,11 +30,8 @@ import com.google.android.material.chip.Chip
|
|||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.di.ServiceLocator
|
import com.topjohnwu.magisk.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.ktx.coroutineScope
|
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
import com.topjohnwu.widget.IndeterminateCheckBox
|
import com.topjohnwu.widget.IndeterminateCheckBox
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@BindingAdapter("gone")
|
@BindingAdapter("gone")
|
||||||
@ -57,10 +55,8 @@ fun setInvisibleUnless(view: View, invisibleUnless: Boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@BindingAdapter("markdownText")
|
@BindingAdapter("markdownText")
|
||||||
fun setMarkdownText(tv: TextView, text: CharSequence) {
|
fun setMarkdownText(tv: TextView, markdown: Spanned) {
|
||||||
tv.coroutineScope.launch(Dispatchers.IO) {
|
ServiceLocator.markwon.setParsedMarkdown(tv, markdown)
|
||||||
ServiceLocator.markwon.setMarkdown(tv, text.toString())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@BindingAdapter("onNavigationClick")
|
@BindingAdapter("onNavigationClick")
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
package com.topjohnwu.magisk.di
|
package com.topjohnwu.magisk.di
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
import com.topjohnwu.magisk.BuildConfig
|
||||||
import com.topjohnwu.magisk.ProviderInstaller
|
import com.topjohnwu.magisk.ProviderInstaller
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.ktx.precomputedText
|
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||||
import com.topjohnwu.magisk.utils.MarkwonImagePlugin
|
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import io.noties.markwon.html.HtmlPlugin
|
import io.noties.markwon.utils.NoCopySpannableFactory
|
||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
|
import okhttp3.ConnectionSpec
|
||||||
import okhttp3.Dns
|
import okhttp3.Dns
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -46,7 +47,8 @@ private class DnsResolver(client: OkHttpClient) : Dns {
|
|||||||
if (Config.doh) {
|
if (Config.doh) {
|
||||||
try {
|
try {
|
||||||
return doh.lookup(hostname)
|
return doh.lookup(hostname)
|
||||||
} catch (e: UnknownHostException) {}
|
} catch (e: UnknownHostException) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Dns.SYSTEM.lookup(hostname)
|
return Dns.SYSTEM.lookup(hostname)
|
||||||
}
|
}
|
||||||
@ -61,11 +63,16 @@ fun createOkHttpClient(context: Context): OkHttpClient {
|
|||||||
builder.addInterceptor(HttpLoggingInterceptor().apply {
|
builder.addInterceptor(HttpLoggingInterceptor().apply {
|
||||||
level = HttpLoggingInterceptor.Level.BASIC
|
level = HttpLoggingInterceptor.Level.BASIC
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
builder.connectionSpecs(listOf(ConnectionSpec.RESTRICTED_TLS))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.dns(DnsResolver(builder.build()))
|
||||||
|
|
||||||
builder.addInterceptor { chain ->
|
builder.addInterceptor { chain ->
|
||||||
val request = chain.request().newBuilder()
|
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())
|
chain.proceed(request.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +80,6 @@ fun createOkHttpClient(context: Context): OkHttpClient {
|
|||||||
Info.hasGMS = false
|
Info.hasGMS = false
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.dns(DnsResolver(builder.build()))
|
|
||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,13 +102,17 @@ inline fun <reified T> createApiService(retrofitBuilder: Retrofit.Builder, baseU
|
|||||||
.create(T::class.java)
|
.create(T::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createMarkwon(context: Context, okHttpClient: OkHttpClient): Markwon {
|
fun createMarkwon(context: Context): Markwon {
|
||||||
return Markwon.builder(context)
|
return Markwon.builder(context)
|
||||||
.textSetter { textView, spanned, _, onComplete ->
|
.textSetter { textView, spanned, bufferType, onComplete ->
|
||||||
textView.tag = onComplete
|
textView.apply {
|
||||||
textView.precomputedText = spanned
|
post {
|
||||||
|
movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
setSpannableFactory(NoCopySpannableFactory.getInstance())
|
||||||
|
setText(spanned, bufferType)
|
||||||
|
onComplete.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.usePlugin(HtmlPlugin.create())
|
|
||||||
.usePlugin(MarkwonImagePlugin(okHttpClient))
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ object ServiceLocator {
|
|||||||
// Networking
|
// Networking
|
||||||
val okhttp by lazy { createOkHttpClient(context) }
|
val okhttp by lazy { createOkHttpClient(context) }
|
||||||
val retrofit by lazy { createRetrofit(okhttp) }
|
val retrofit by lazy { createRetrofit(okhttp) }
|
||||||
val markwon by lazy { createMarkwon(context, okhttp) }
|
val markwon by lazy { createMarkwon(context) }
|
||||||
val networkService by lazy {
|
val networkService by lazy {
|
||||||
NetworkService(
|
NetworkService(
|
||||||
createApiService(retrofit, Const.Url.GITHUB_PAGE_URL),
|
createApiService(retrofit, Const.Url.GITHUB_PAGE_URL),
|
||||||
|
@ -10,9 +10,8 @@ import com.topjohnwu.magisk.di.ServiceLocator
|
|||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.coroutines.cancellation.CancellationException
|
import java.io.IOException
|
||||||
|
|
||||||
abstract class MarkDownDialog : DialogEvent() {
|
abstract class MarkDownDialog : DialogEvent() {
|
||||||
|
|
||||||
@ -23,17 +22,13 @@ abstract class MarkDownDialog : DialogEvent() {
|
|||||||
with(dialog) {
|
with(dialog) {
|
||||||
val view = LayoutInflater.from(context).inflate(R.layout.markdown_window_md2, null)
|
val view = LayoutInflater.from(context).inflate(R.layout.markdown_window_md2, null)
|
||||||
setView(view)
|
setView(view)
|
||||||
(ownerActivity as BaseActivity).lifecycleScope.launch {
|
val tv = view.findViewById<TextView>(R.id.md_txt)
|
||||||
val tv = view.findViewById<TextView>(R.id.md_txt)
|
(ownerActivity as BaseActivity).lifecycleScope.launch(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
try {
|
||||||
try {
|
ServiceLocator.markwon.setMarkdown(tv, getMarkdownText())
|
||||||
ServiceLocator.markwon.setMarkdown(tv, getMarkdownText())
|
} catch (e: IOException) {
|
||||||
} catch (e: Exception) {
|
Timber.e(e)
|
||||||
if (e is CancellationException)
|
tv.post { tv.setText(R.string.download_file_error) }
|
||||||
throw e
|
|
||||||
Timber.e(e)
|
|
||||||
tv.post { tv.setText(R.string.download_file_error) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
package com.topjohnwu.magisk.events.dialog
|
package com.topjohnwu.magisk.events.dialog
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.Info
|
|
||||||
import com.topjohnwu.magisk.core.download.Action
|
import com.topjohnwu.magisk.core.download.Action
|
||||||
import com.topjohnwu.magisk.core.download.DownloadService
|
import com.topjohnwu.magisk.core.download.DownloadService
|
||||||
import com.topjohnwu.magisk.core.download.Subject
|
import com.topjohnwu.magisk.core.download.Subject
|
||||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||||
|
import com.topjohnwu.magisk.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
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) {
|
override fun build(dialog: MagiskDialog) {
|
||||||
|
super.build(dialog)
|
||||||
dialog.apply {
|
dialog.apply {
|
||||||
|
|
||||||
fun download(install: Boolean) {
|
fun download(install: Boolean) {
|
||||||
@ -19,21 +27,21 @@ class ModuleInstallDialog(private val item: OnlineModule) : DialogEvent() {
|
|||||||
DownloadService.start(context, subject)
|
DownloadService.start(context, subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTitle(context.getString(R.string.repo_install_title, item.name))
|
val title = context.getString(R.string.repo_install_title,
|
||||||
setMessage(context.getString(R.string.repo_install_msg, item.downloadFilename))
|
item.name, item.version, item.versionCode)
|
||||||
|
|
||||||
|
setTitle(title)
|
||||||
setCancelable(true)
|
setCancelable(true)
|
||||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
text = R.string.download
|
text = R.string.download
|
||||||
icon = R.drawable.ic_download_md2
|
|
||||||
onClick { download(false) }
|
onClick { download(false) }
|
||||||
}
|
}
|
||||||
|
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
if (Info.env.isActive) {
|
text = R.string.install
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
onClick { download(true) }
|
||||||
text = R.string.install
|
}
|
||||||
icon = R.drawable.ic_install
|
setButton(MagiskDialog.ButtonType.NEUTRAL) {
|
||||||
onClick { download(true) }
|
text = android.R.string.cancel
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
@SuppressLint("PrivateApi")
|
||||||
fun getProperty(key: String, def: String): String {
|
fun getProperty(key: String, def: String): String {
|
||||||
runCatching {
|
runCatching {
|
||||||
|
@ -4,12 +4,10 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||||
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
|
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
|
||||||
import com.topjohnwu.magisk.di.viewModel
|
import com.topjohnwu.magisk.di.viewModel
|
||||||
import com.topjohnwu.magisk.ktx.coroutineScope
|
|
||||||
|
|
||||||
class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Binding>() {
|
class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Binding>() {
|
||||||
|
|
||||||
@ -19,9 +17,6 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi
|
|||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
requireActivity().setTitle(R.string.install)
|
requireActivity().setTitle(R.string.install)
|
||||||
|
|
||||||
// Allow markwon to run in viewmodel scope
|
|
||||||
binding.releaseNotes.coroutineScope = viewModel.viewModelScope
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.topjohnwu.magisk.ui.install
|
package com.topjohnwu.magisk.ui.install
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.text.Spanned
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
@ -12,10 +14,12 @@ import com.topjohnwu.magisk.core.Info
|
|||||||
import com.topjohnwu.magisk.data.repository.NetworkService
|
import com.topjohnwu.magisk.data.repository.NetworkService
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.di.AppContext
|
import com.topjohnwu.magisk.di.AppContext
|
||||||
|
import com.topjohnwu.magisk.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.events.MagiskInstallFileEvent
|
import com.topjohnwu.magisk.events.MagiskInstallFileEvent
|
||||||
import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog
|
import com.topjohnwu.magisk.events.dialog.SecondSlotWarningDialog
|
||||||
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -55,23 +59,23 @@ class InstallViewModel(
|
|||||||
set(value) = set(value, field, { field = it }, BR.data)
|
set(value) = set(value, field, { field = it }, BR.data)
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var notes = ""
|
var notes: Spanned = SpannableStringBuilder()
|
||||||
set(value) = set(value, field, { field = it }, BR.notes)
|
set(value) = set(value, field, { field = it }, BR.notes)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
File(AppContext.cacheDir, "${BuildConfig.VERSION_CODE}.md").run {
|
val file = File(AppContext.cacheDir, "${BuildConfig.VERSION_CODE}.md")
|
||||||
notes = when {
|
val text = when {
|
||||||
exists() -> readText()
|
file.exists() -> file.readText()
|
||||||
Const.Url.CHANGELOG_URL.isEmpty() -> ""
|
Const.Url.CHANGELOG_URL.isEmpty() -> ""
|
||||||
else -> {
|
else -> {
|
||||||
val text = svc.fetchString(Const.Url.CHANGELOG_URL)
|
val str = svc.fetchString(Const.Url.CHANGELOG_URL)
|
||||||
writeText(text)
|
file.writeText(str)
|
||||||
text
|
str
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
notes = ServiceLocator.markwon.toMarkdown(text)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
}
|
}
|
||||||
|
@ -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<String, SchemeHandler>(3)
|
|
||||||
private val mediaDecoders = HashMap<String, MediaDecoder>(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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,12 +26,11 @@ object Notifications {
|
|||||||
|
|
||||||
fun setup(context: Context) {
|
fun setup(context: Context) {
|
||||||
if (SDK_INT >= 26) {
|
if (SDK_INT >= 26) {
|
||||||
var channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL,
|
val channel = NotificationChannel(UPDATE_NOTIFICATION_CHANNEL,
|
||||||
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
|
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
mgr.createNotificationChannel(channel)
|
val channel2 = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL,
|
||||||
channel = NotificationChannel(PROGRESS_NOTIFICATION_CHANNEL,
|
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
|
||||||
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
|
mgr.createNotificationChannels(listOf(channel, channel2))
|
||||||
mgr.createNotificationChannel(channel)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,11 +223,11 @@
|
|||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
style="@style/WidgetFoundation.Card"
|
style="@style/WidgetFoundation.Card"
|
||||||
gone="@{viewModel.notes.empty}"
|
gone="@{viewModel.notes.length == 0}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/l1"
|
|
||||||
android:layout_marginStart="@dimen/l1"
|
android:layout_marginStart="@dimen/l1"
|
||||||
|
android:layout_marginTop="@dimen/l1"
|
||||||
android:layout_marginEnd="@dimen/l1"
|
android:layout_marginEnd="@dimen/l1"
|
||||||
android:focusable="false">
|
android:focusable="false">
|
||||||
|
|
||||||
@ -237,8 +237,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="15dp"
|
android:layout_margin="15dp"
|
||||||
|
android:breakStrategy="simple"
|
||||||
|
android:hyphenationFrequency="none"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
android:textAppearance="@style/AppearanceFoundation.Caption"
|
||||||
android:visibility="gone"
|
tools:ignore="UnusedAttribute"
|
||||||
tools:maxLines="5"
|
tools:maxLines="5"
|
||||||
tools:text="@tools:sample/lorem/random"
|
tools:text="@tools:sample/lorem/random"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
@ -9,7 +10,10 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="15dp"
|
android:layout_marginStart="15dp"
|
||||||
android:layout_marginEnd="15dp"
|
android:layout_marginEnd="15dp"
|
||||||
|
android:breakStrategy="simple"
|
||||||
|
android:hyphenationFrequency="none"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption" />
|
android:textAppearance="@style/AppearanceFoundation.Caption"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -174,7 +174,6 @@
|
|||||||
<string name="yes">نعم</string>
|
<string name="yes">نعم</string>
|
||||||
<string name="no">لا</string>
|
<string name="no">لا</string>
|
||||||
<string name="repo_install_title">تثبيت %1$s</string>
|
<string name="repo_install_title">تثبيت %1$s</string>
|
||||||
<string name="repo_install_msg">هل تريد تثبيت %1$s ?</string>
|
|
||||||
<string name="download">تنزيل</string>
|
<string name="download">تنزيل</string>
|
||||||
<string name="reboot">إعادة التشغيل</string>
|
<string name="reboot">إعادة التشغيل</string>
|
||||||
<string name="release_notes">معلومات الأصدار الجديد</string>
|
<string name="release_notes">معلومات الأصدار الجديد</string>
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="repo_install_title">%1$s faylını yüklə</string>
|
<string name="repo_install_title">%1$s faylını yüklə</string>
|
||||||
<string name="repo_install_msg">%1$s faylını indi yükləmək istəyirsiniz?</string>
|
|
||||||
<string name="download">Yüklə</string>
|
<string name="download">Yüklə</string>
|
||||||
<string name="reboot">Yenidən Başlat</string>
|
<string name="reboot">Yenidən Başlat</string>
|
||||||
<string name="release_notes">Yeniliklər</string>
|
<string name="release_notes">Yeniliklər</string>
|
||||||
|
@ -172,8 +172,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Так</string>
|
<string name="yes">Так</string>
|
||||||
<string name="no">Не</string>
|
<string name="no">Не</string>
|
||||||
<string name="repo_install_title">Усталяваць %1$s</string>
|
<string name="repo_install_title">Усталяваць %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Усталяваць %1$s?</string>
|
|
||||||
<string name="download">Спампаваць</string>
|
<string name="download">Спампаваць</string>
|
||||||
<string name="reboot">Перазапуск</string>
|
<string name="reboot">Перазапуск</string>
|
||||||
<string name="release_notes">Пра выпуск</string>
|
<string name="release_notes">Пра выпуск</string>
|
||||||
|
@ -36,8 +36,7 @@
|
|||||||
<string name="app_changelog">Списък с промени</string>
|
<string name="app_changelog">Списък с промени</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="repo_install_title">Инсталиране на %1$s</string>
|
<string name="repo_install_title">Инсталиране на %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Желаете ли да инсталирате %1$s сега?</string>
|
|
||||||
<string name="download">Изтегляне</string>
|
<string name="download">Изтегляне</string>
|
||||||
<string name="reboot">Рестартиране</string>
|
<string name="reboot">Рестартиране</string>
|
||||||
<string name="magisk_update_title">Достъпно е издание на Magisk.</string>
|
<string name="magisk_update_title">Достъпно е издание на Magisk.</string>
|
||||||
|
@ -186,8 +186,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Sí</string>
|
<string name="yes">Sí</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
<string name="repo_install_title">Instal·lar %1$s</string>
|
<string name="repo_install_title">Instal·lar %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Vol instal·lar %1$s ara?</string>
|
|
||||||
<string name="download">Baixar</string>
|
<string name="download">Baixar</string>
|
||||||
<string name="reboot">Reiniciar</string>
|
<string name="reboot">Reiniciar</string>
|
||||||
<string name="release_notes">Notes de llançament</string>
|
<string name="release_notes">Notes de llançament</string>
|
||||||
|
@ -185,8 +185,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">ANO</string>
|
<string name="yes">ANO</string>
|
||||||
<string name="no">NE</string>
|
<string name="no">NE</string>
|
||||||
<string name="repo_install_title">Instalovat %1$s</string>
|
<string name="repo_install_title">Instalovat %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
|
|
||||||
<string name="download">Stáhnout</string>
|
<string name="download">Stáhnout</string>
|
||||||
<string name="reboot">Restartovat</string>
|
<string name="reboot">Restartovat</string>
|
||||||
<string name="release_notes">Poznámky k vydání</string>
|
<string name="release_notes">Poznámky k vydání</string>
|
||||||
|
@ -194,7 +194,6 @@
|
|||||||
<string name="yes">Ja</string>
|
<string name="yes">Ja</string>
|
||||||
<string name="no">Nein</string>
|
<string name="no">Nein</string>
|
||||||
<string name="repo_install_title">%1$s installieren</string>
|
<string name="repo_install_title">%1$s installieren</string>
|
||||||
<string name="repo_install_msg">Möchten Sie %1$s jetzt installieren?</string>
|
|
||||||
<string name="download">Herunterladen</string>
|
<string name="download">Herunterladen</string>
|
||||||
<string name="reboot">Neustart</string>
|
<string name="reboot">Neustart</string>
|
||||||
<string name="release_notes">Anmerkungen zur Veröffentlichung</string>
|
<string name="release_notes">Anmerkungen zur Veröffentlichung</string>
|
||||||
|
@ -185,8 +185,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Ναι</string>
|
<string name="yes">Ναι</string>
|
||||||
<string name="no">Όχι</string>
|
<string name="no">Όχι</string>
|
||||||
<string name="repo_install_title">Εγκατάσταση %1$s</string>
|
<string name="repo_install_title">Εγκατάσταση %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Θέλετε να εγκαταστήσετε το %1$s τώρα;</string>
|
|
||||||
<string name="download">Λήψη</string>
|
<string name="download">Λήψη</string>
|
||||||
<string name="reboot">Επανεκκίνηση</string>
|
<string name="reboot">Επανεκκίνηση</string>
|
||||||
<string name="release_notes">Σημειώσεις έκδοσης</string>
|
<string name="release_notes">Σημειώσεις έκδοσης</string>
|
||||||
|
@ -195,8 +195,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Sí</string>
|
<string name="yes">Sí</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
<string name="repo_install_title">Instalar %1$s</string>
|
<string name="repo_install_title">Instalar %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">¿Desea instalar %1$s ahora?</string>
|
|
||||||
<string name="download">Descargar</string>
|
<string name="download">Descargar</string>
|
||||||
<string name="reboot">Reiniciar</string>
|
<string name="reboot">Reiniciar</string>
|
||||||
<string name="release_notes">Notas de lanzamiento</string>
|
<string name="release_notes">Notas de lanzamiento</string>
|
||||||
|
@ -175,8 +175,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Jah</string>
|
<string name="yes">Jah</string>
|
||||||
<string name="no">Ei</string>
|
<string name="no">Ei</string>
|
||||||
<string name="repo_install_title">Installi %1$s</string>
|
<string name="repo_install_title">Installi %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Kas soovid kohe installida %1$s?</string>
|
|
||||||
<string name="download">Allalaadimine</string>
|
<string name="download">Allalaadimine</string>
|
||||||
<string name="reboot">Taaskäivita</string>
|
<string name="reboot">Taaskäivita</string>
|
||||||
<string name="release_notes">Väljalaskemärkmed</string>
|
<string name="release_notes">Väljalaskemärkmed</string>
|
||||||
|
@ -171,7 +171,6 @@
|
|||||||
<string name="yes">بله</string>
|
<string name="yes">بله</string>
|
||||||
<string name="no">نه</string>
|
<string name="no">نه</string>
|
||||||
<string name="repo_install_title">نصب کرد %1$s</string>
|
<string name="repo_install_title">نصب کرد %1$s</string>
|
||||||
<string name="repo_install_msg">آیا می خواهید %1$s نصب شود؟</string>
|
|
||||||
<string name="download">انلود کردن</string>
|
<string name="download">انلود کردن</string>
|
||||||
<string name="reboot">راه اندازی مجدد</string>
|
<string name="reboot">راه اندازی مجدد</string>
|
||||||
<string name="release_notes">نکته های نسخه</string>
|
<string name="release_notes">نکته های نسخه</string>
|
||||||
|
@ -195,8 +195,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Oui</string>
|
<string name="yes">Oui</string>
|
||||||
<string name="no">Non</string>
|
<string name="no">Non</string>
|
||||||
<string name="repo_install_title">Installer %1$s</string>
|
<string name="repo_install_title">Installer %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Voulez‑vous installer %1$s maintenant ?</string>
|
|
||||||
<string name="download">Télécharger</string>
|
<string name="download">Télécharger</string>
|
||||||
<string name="reboot">Redémarrer</string>
|
<string name="reboot">Redémarrer</string>
|
||||||
<string name="release_notes">Notes de version</string>
|
<string name="release_notes">Notes de version</string>
|
||||||
|
@ -177,8 +177,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">हाँ</string>
|
<string name="yes">हाँ</string>
|
||||||
<string name="no">नहीं</string>
|
<string name="no">नहीं</string>
|
||||||
<string name="repo_install_title">इंस्टॉल %1$s</string>
|
<string name="repo_install_title">इंस्टॉल %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">क्या आप अभी %1$s इंस्टॉल करना चाहते हैं?</string>
|
|
||||||
<string name="download">डाउनलोड</string>
|
<string name="download">डाउनलोड</string>
|
||||||
<string name="reboot">रीबूट</string>
|
<string name="reboot">रीबूट</string>
|
||||||
<string name="release_notes">रिलीज नोट्स</string>
|
<string name="release_notes">रिलीज नोट्स</string>
|
||||||
|
@ -176,8 +176,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Da</string>
|
<string name="yes">Da</string>
|
||||||
<string name="no">Ne</string>
|
<string name="no">Ne</string>
|
||||||
<string name="repo_install_title">Instaliraj %1$s</string>
|
<string name="repo_install_title">Instaliraj %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Da li želite instalirati %1$s sada?</string>
|
|
||||||
<string name="download">Preuzmi</string>
|
<string name="download">Preuzmi</string>
|
||||||
<string name="reboot">Ponovno pokreni</string>
|
<string name="reboot">Ponovno pokreni</string>
|
||||||
<string name="release_notes">Bilješke o izdavanju aplikacije</string>
|
<string name="release_notes">Bilješke o izdavanju aplikacije</string>
|
||||||
|
@ -180,8 +180,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Ya</string>
|
<string name="yes">Ya</string>
|
||||||
<string name="no">Tidak</string>
|
<string name="no">Tidak</string>
|
||||||
<string name="repo_install_title">Instal %1$s</string>
|
<string name="repo_install_title">Instal %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Apakah Anda ingin menginstal %1$s sekarang?</string>
|
|
||||||
<string name="download">Download</string>
|
<string name="download">Download</string>
|
||||||
<string name="reboot">Nyalakan ulang</string>
|
<string name="reboot">Nyalakan ulang</string>
|
||||||
<string name="release_notes">Catatan rilis</string>
|
<string name="release_notes">Catatan rilis</string>
|
||||||
|
@ -193,8 +193,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Sì</string>
|
<string name="yes">Sì</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
<string name="repo_install_title">Installazione di %1$s</string>
|
<string name="repo_install_title">Installazione di %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Vuoi installare %1$s?</string>
|
|
||||||
<string name="download">Download</string>
|
<string name="download">Download</string>
|
||||||
<string name="reboot">Riavvia</string>
|
<string name="reboot">Riavvia</string>
|
||||||
<string name="release_notes">Note di rilascio</string>
|
<string name="release_notes">Note di rilascio</string>
|
||||||
|
@ -183,7 +183,6 @@
|
|||||||
<string name="yes">כן</string>
|
<string name="yes">כן</string>
|
||||||
<string name="no">לא</string>
|
<string name="no">לא</string>
|
||||||
<string name="repo_install_title">התקן %1$s</string>
|
<string name="repo_install_title">התקן %1$s</string>
|
||||||
<string name="repo_install_msg">האם ברצונך להתקין את %1$s כעת?</string>
|
|
||||||
<string name="download">הורדה</string>
|
<string name="download">הורדה</string>
|
||||||
<string name="reboot">הפעלה מחדש</string>
|
<string name="reboot">הפעלה מחדש</string>
|
||||||
<string name="release_notes">הערות שחרור</string>
|
<string name="release_notes">הערות שחרור</string>
|
||||||
|
@ -197,7 +197,6 @@
|
|||||||
<string name="yes">対応</string>
|
<string name="yes">対応</string>
|
||||||
<string name="no">非対応</string>
|
<string name="no">非対応</string>
|
||||||
<string name="repo_install_title">%1$s をインストール</string>
|
<string name="repo_install_title">%1$s をインストール</string>
|
||||||
<string name="repo_install_msg">%1$s をインストールしますか?</string>
|
|
||||||
<string name="download">ダウンロード</string>
|
<string name="download">ダウンロード</string>
|
||||||
<string name="reboot">再起動</string>
|
<string name="reboot">再起動</string>
|
||||||
<string name="release_notes">更新履歴</string>
|
<string name="release_notes">更新履歴</string>
|
||||||
|
@ -187,7 +187,6 @@
|
|||||||
<string name="yes">დიახ</string>
|
<string name="yes">დიახ</string>
|
||||||
<string name="no">არა</string>
|
<string name="no">არა</string>
|
||||||
<string name="repo_install_title">%1$s-ის ინსტალაცია</string>
|
<string name="repo_install_title">%1$s-ის ინსტალაცია</string>
|
||||||
<string name="repo_install_msg">გნებავთ %1$s-ის ახლავე დაინსტალირება?</string>
|
|
||||||
<string name="download">გადმოწერა</string>
|
<string name="download">გადმოწერა</string>
|
||||||
<string name="reboot">გადატვირთვა</string>
|
<string name="reboot">გადატვირთვა</string>
|
||||||
<string name="release_notes">რელიზის შენიშვნები</string>
|
<string name="release_notes">რელიზის შენიშვნები</string>
|
||||||
|
@ -191,7 +191,6 @@
|
|||||||
<string name="yes">예</string>
|
<string name="yes">예</string>
|
||||||
<string name="no">아니오</string>
|
<string name="no">아니오</string>
|
||||||
<string name="repo_install_title">%1$s 설치</string>
|
<string name="repo_install_title">%1$s 설치</string>
|
||||||
<string name="repo_install_msg">정말 %1$s을(를) 설치하시겠습니까?</string>
|
|
||||||
<string name="download">다운로드</string>
|
<string name="download">다운로드</string>
|
||||||
<string name="reboot">다시 시작</string>
|
<string name="reboot">다시 시작</string>
|
||||||
<string name="release_notes">릴리즈 노트</string>
|
<string name="release_notes">릴리즈 노트</string>
|
||||||
|
@ -36,8 +36,7 @@
|
|||||||
<string name="app_changelog">Pakeitimų sąrašas</string>
|
<string name="app_changelog">Pakeitimų sąrašas</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="repo_install_title">Instaliuoti %1$s</string>
|
<string name="repo_install_title">Instaliuoti %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Ar jūs norite instaliuoti %1$s?</string>
|
|
||||||
<string name="download">Atsisiųsti</string>
|
<string name="download">Atsisiųsti</string>
|
||||||
<string name="reboot">Perkrauti</string>
|
<string name="reboot">Perkrauti</string>
|
||||||
<string name="magisk_update_title">Atsirado nauja Magisk versija!</string>
|
<string name="magisk_update_title">Atsirado nauja Magisk versija!</string>
|
||||||
|
@ -52,8 +52,7 @@
|
|||||||
<string name="reboot_delay_toast">Рестартирање за 5 секунди…</string>
|
<string name="reboot_delay_toast">Рестартирање за 5 секунди…</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="repo_install_title">Инсталирај %1$s</string>
|
<string name="repo_install_title">Инсталирај %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Дали сакате да го инсталирате %1$s сега?</string>
|
|
||||||
<string name="download">Преземи</string>
|
<string name="download">Преземи</string>
|
||||||
<string name="reboot">Рестартирај</string>
|
<string name="reboot">Рестартирај</string>
|
||||||
<string name="release_notes">Белешки за изданието</string>
|
<string name="release_notes">Белешки за изданието</string>
|
||||||
|
@ -186,8 +186,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Ja</string>
|
<string name="yes">Ja</string>
|
||||||
<string name="no">Nei</string>
|
<string name="no">Nei</string>
|
||||||
<string name="repo_install_title">Installer %1$s</string>
|
<string name="repo_install_title">Installer %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Installer %1$s nå?</string>
|
|
||||||
<string name="download">Last ned</string>
|
<string name="download">Last ned</string>
|
||||||
<string name="reboot">Omstart</string>
|
<string name="reboot">Omstart</string>
|
||||||
<string name="release_notes">Utgivelsesnotater</string>
|
<string name="release_notes">Utgivelsesnotater</string>
|
||||||
|
@ -172,8 +172,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Ja</string>
|
<string name="yes">Ja</string>
|
||||||
<string name="no">Nee</string>
|
<string name="no">Nee</string>
|
||||||
<string name="repo_install_title">%1$s installeren</string>
|
<string name="repo_install_title">%1$s installeren %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Wil je %1$s nu installeren?</string>
|
|
||||||
<string name="download">Downloaden</string>
|
<string name="download">Downloaden</string>
|
||||||
<string name="reboot">Herstarten</string>
|
<string name="reboot">Herstarten</string>
|
||||||
<string name="release_notes">Wijzigingslog</string>
|
<string name="release_notes">Wijzigingslog</string>
|
||||||
|
@ -177,8 +177,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">ਹਾਂ</string>
|
<string name="yes">ਹਾਂ</string>
|
||||||
<string name="no">ਨਹੀਂ</string>
|
<string name="no">ਨਹੀਂ</string>
|
||||||
<string name="repo_install_title">ਇੰਸਟਾਲ %1$s</string>
|
<string name="repo_install_title">ਇੰਸਟਾਲ %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">ਕੀ ਤੁਸੀਂ ਹੁਣੇ %1$s ਇੰਸਟਾਲ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?</string>
|
|
||||||
<string name="download">ਡਾਊਨਲੋਡ</string>
|
<string name="download">ਡਾਊਨਲੋਡ</string>
|
||||||
<string name="reboot">ਰੀਬੂਟ</string>
|
<string name="reboot">ਰੀਬੂਟ</string>
|
||||||
<string name="release_notes">ਰੀਲਿਜ਼ ਨੋਟਿਸ</string>
|
<string name="release_notes">ਰੀਲਿਜ਼ ਨੋਟਿਸ</string>
|
||||||
|
@ -186,8 +186,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Tak</string>
|
<string name="yes">Tak</string>
|
||||||
<string name="no">Nie</string>
|
<string name="no">Nie</string>
|
||||||
<string name="repo_install_title">Instalacja %1$s</string>
|
<string name="repo_install_title">Instalacja %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Czy chcesz teraz zainstalować %1$s ?</string>
|
|
||||||
<string name="download">Pobierz</string>
|
<string name="download">Pobierz</string>
|
||||||
<string name="reboot">Reboot</string>
|
<string name="reboot">Reboot</string>
|
||||||
<string name="release_notes">Lista zmian</string>
|
<string name="release_notes">Lista zmian</string>
|
||||||
|
@ -190,8 +190,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Sim</string>
|
<string name="yes">Sim</string>
|
||||||
<string name="no">Não</string>
|
<string name="no">Não</string>
|
||||||
<string name="repo_install_title">Instalar %1$s</string>
|
<string name="repo_install_title">Instalar %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Deseja instalar %1$s agora?</string>
|
|
||||||
<string name="download">Download</string>
|
<string name="download">Download</string>
|
||||||
<string name="reboot">Reinicializar</string>
|
<string name="reboot">Reinicializar</string>
|
||||||
<string name="release_notes">Notas de versão</string>
|
<string name="release_notes">Notas de versão</string>
|
||||||
|
@ -32,8 +32,7 @@
|
|||||||
<string name="app_changelog">Lista de alterações da aplicação</string>
|
<string name="app_changelog">Lista de alterações da aplicação</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="repo_install_title">Instalar %1$s</string>
|
<string name="repo_install_title">Instalar %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Deseja instalar%1$s agora?</string>
|
|
||||||
<string name="download">Transferir</string>
|
<string name="download">Transferir</string>
|
||||||
<string name="reboot">Reiniciar</string>
|
<string name="reboot">Reiniciar</string>
|
||||||
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
|
<string name="magisk_update_title">Nova atualização do Magisk disponível!</string>
|
||||||
|
@ -193,8 +193,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Da</string>
|
<string name="yes">Da</string>
|
||||||
<string name="no">Nu</string>
|
<string name="no">Nu</string>
|
||||||
<string name="repo_install_title">Instalează %1$s</string>
|
<string name="repo_install_title">Instalează %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Vrei să instalezi acum %1$s?</string>
|
|
||||||
<string name="download">Descarcă</string>
|
<string name="download">Descarcă</string>
|
||||||
<string name="reboot">Repornește</string>
|
<string name="reboot">Repornește</string>
|
||||||
<string name="release_notes">Note privind versiunea</string>
|
<string name="release_notes">Note privind versiunea</string>
|
||||||
|
@ -196,8 +196,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Да</string>
|
<string name="yes">Да</string>
|
||||||
<string name="no">Нет</string>
|
<string name="no">Нет</string>
|
||||||
<string name="repo_install_title">Установка %1$s</string>
|
<string name="repo_install_title">Установка %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Установить %1$s ?</string>
|
|
||||||
<string name="download">Скачать</string>
|
<string name="download">Скачать</string>
|
||||||
<string name="reboot">Перезагрузка</string>
|
<string name="reboot">Перезагрузка</string>
|
||||||
<string name="release_notes">О версии</string>
|
<string name="release_notes">О версии</string>
|
||||||
|
@ -196,8 +196,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Áno</string>
|
<string name="yes">Áno</string>
|
||||||
<string name="no">Nie</string>
|
<string name="no">Nie</string>
|
||||||
<string name="repo_install_title">Nainštalovať %1$s</string>
|
<string name="repo_install_title">Nainštalovať %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Chcete teraz nainštalovať %1$s?</string>
|
|
||||||
<string name="download">Stiahnuť</string>
|
<string name="download">Stiahnuť</string>
|
||||||
<string name="reboot">Reštartovať</string>
|
<string name="reboot">Reštartovať</string>
|
||||||
<string name="release_notes">Poznámky k vydaniu</string>
|
<string name="release_notes">Poznámky k vydaniu</string>
|
||||||
|
@ -194,8 +194,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Po</string>
|
<string name="yes">Po</string>
|
||||||
<string name="no">Jo</string>
|
<string name="no">Jo</string>
|
||||||
<string name="repo_install_title">Instalo %1$s</string>
|
<string name="repo_install_title">Instalo %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Dëshiron të instalosh %1$s tani?</string>
|
|
||||||
<string name="download">Shkarko</string>
|
<string name="download">Shkarko</string>
|
||||||
<string name="reboot">Rinis</string>
|
<string name="reboot">Rinis</string>
|
||||||
<string name="release_notes">Shënimet e lëshimit</string>
|
<string name="release_notes">Shënimet e lëshimit</string>
|
||||||
|
@ -34,8 +34,7 @@
|
|||||||
<string name="app_changelog">Дневник промена апликације</string>
|
<string name="app_changelog">Дневник промена апликације</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="repo_install_title">Инсталирај %1$s</string>
|
<string name="repo_install_title">Инсталирај %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Да ли желите да инсталирате %1$s?</string>
|
|
||||||
<string name="download">Преузми</string>
|
<string name="download">Преузми</string>
|
||||||
<string name="reboot">Рестартуј</string>
|
<string name="reboot">Рестартуј</string>
|
||||||
<string name="magisk_update_title">Нови Адбејт Магиска Доступан!</string>
|
<string name="magisk_update_title">Нови Адбејт Магиска Доступан!</string>
|
||||||
|
@ -186,8 +186,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Ja</string>
|
<string name="yes">Ja</string>
|
||||||
<string name="no">Nej</string>
|
<string name="no">Nej</string>
|
||||||
<string name="repo_install_title">Installera %1$s</string>
|
<string name="repo_install_title">Installera %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Vill du installera %1$s nu?</string>
|
|
||||||
<string name="download">Ladda ned</string>
|
<string name="download">Ladda ned</string>
|
||||||
<string name="reboot">Omstart</string>
|
<string name="reboot">Omstart</string>
|
||||||
<string name="release_notes">Utgivningsanmärkningar</string>
|
<string name="release_notes">Utgivningsanmärkningar</string>
|
||||||
|
@ -186,8 +186,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">ஆம்</string>
|
<string name="yes">ஆம்</string>
|
||||||
<string name="no">இல்லை</string>
|
<string name="no">இல்லை</string>
|
||||||
<string name="repo_install_title">நிறுவு %1$s</string>
|
<string name="repo_install_title">நிறுவு %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">நீங்கள் இப்போது %1$s ஐ நிறுவ விரும்புகிறீர்களா??</string>
|
|
||||||
<string name="download">பதிவிறக்கம்</string>
|
<string name="download">பதிவிறக்கம்</string>
|
||||||
<string name="reboot">மறுதொடக்கம்</string>
|
<string name="reboot">மறுதொடக்கம்</string>
|
||||||
<string name="release_notes">வெளியீட்டு குறிப்புகள்</string>
|
<string name="release_notes">வெளியீட்டு குறிப்புகள்</string>
|
||||||
|
@ -41,8 +41,7 @@
|
|||||||
<string name="magisk_update_title">มีการอัพเดต Magisk!</string>
|
<string name="magisk_update_title">มีการอัพเดต Magisk!</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="repo_install_title">ติดตั้ง %1$s</string>
|
<string name="repo_install_title">ติดตั้ง %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">ต้องการติดตั้ง %1$s ตอนนี้หรือไม่?</string>
|
|
||||||
<string name="download">ดาวน์โหลด</string>
|
<string name="download">ดาวน์โหลด</string>
|
||||||
<string name="reboot">รีบู๊ต</string>
|
<string name="reboot">รีบู๊ต</string>
|
||||||
<string name="release_notes">-้อมูลเพิ่มเติม</string>
|
<string name="release_notes">-้อมูลเพิ่มเติม</string>
|
||||||
|
@ -187,7 +187,6 @@
|
|||||||
<string name="yes">Evet</string>
|
<string name="yes">Evet</string>
|
||||||
<string name="no">Hayır</string>
|
<string name="no">Hayır</string>
|
||||||
<string name="repo_install_title">%1$s yükle</string>
|
<string name="repo_install_title">%1$s yükle</string>
|
||||||
<string name="repo_install_msg">%1$s yüklensin mi?</string>
|
|
||||||
<string name="download">İndir</string>
|
<string name="download">İndir</string>
|
||||||
<string name="reboot">Yeniden Başlat</string>
|
<string name="reboot">Yeniden Başlat</string>
|
||||||
<string name="release_notes">Sürüm notları</string>
|
<string name="release_notes">Sürüm notları</string>
|
||||||
|
@ -193,8 +193,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Так</string>
|
<string name="yes">Так</string>
|
||||||
<string name="no">Ні</string>
|
<string name="no">Ні</string>
|
||||||
<string name="repo_install_title">Встановити %1$s</string>
|
<string name="repo_install_title">Встановити %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Бажаєте встановити %1$s?</string>
|
|
||||||
<string name="download">Завантажити</string>
|
<string name="download">Завантажити</string>
|
||||||
<string name="reboot">Перезавантажити</string>
|
<string name="reboot">Перезавантажити</string>
|
||||||
<string name="release_notes">Особливості версії</string>
|
<string name="release_notes">Особливості версії</string>
|
||||||
|
@ -193,8 +193,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Đồng ý</string>
|
<string name="yes">Đồng ý</string>
|
||||||
<string name="no">Không</string>
|
<string name="no">Không</string>
|
||||||
<string name="repo_install_title">Cài đặt %1$s</string>
|
<string name="repo_install_title">Cài đặt %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Bạn có muốn cài đặt %1$s ngay bây giờ không?</string>
|
|
||||||
<string name="download">Tải xuống</string>
|
<string name="download">Tải xuống</string>
|
||||||
<string name="reboot">Khởi động lại</string>
|
<string name="reboot">Khởi động lại</string>
|
||||||
<string name="release_notes">Ghi chú bản phát hành</string>
|
<string name="release_notes">Ghi chú bản phát hành</string>
|
||||||
|
@ -196,8 +196,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">是</string>
|
<string name="yes">是</string>
|
||||||
<string name="no">否</string>
|
<string name="no">否</string>
|
||||||
<string name="repo_install_title">安装 %1$s</string>
|
<string name="repo_install_title">安装 %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">确认安装 %1$s?</string>
|
|
||||||
<string name="download">下载</string>
|
<string name="download">下载</string>
|
||||||
<string name="reboot">重启</string>
|
<string name="reboot">重启</string>
|
||||||
<string name="release_notes">发布说明</string>
|
<string name="release_notes">发布说明</string>
|
||||||
|
@ -193,8 +193,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">是</string>
|
<string name="yes">是</string>
|
||||||
<string name="no">否</string>
|
<string name="no">否</string>
|
||||||
<string name="repo_install_title">安裝 %1$s</string>
|
<string name="repo_install_title">安裝 %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">您現在想要安裝 %1$s 嗎?</string>
|
|
||||||
<string name="download">下載</string>
|
<string name="download">下載</string>
|
||||||
<string name="reboot">重新啟動</string>
|
<string name="reboot">重新啟動</string>
|
||||||
<string name="release_notes">發布說明</string>
|
<string name="release_notes">發布說明</string>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<item name="recyclerScrollListener" type="id" />
|
<item name="recyclerScrollListener" type="id" />
|
||||||
<item name="coroutineScope" type="id" />
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -197,8 +197,7 @@
|
|||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
<string name="repo_install_title">Install %1$s</string>
|
<string name="repo_install_title">Install %1$s %2$s(%3$s)</string>
|
||||||
<string name="repo_install_msg">Do you want to install %1$s now?</string>
|
|
||||||
<string name="download">Download</string>
|
<string name="download">Download</string>
|
||||||
<string name="reboot">Reboot</string>
|
<string name="reboot">Reboot</string>
|
||||||
<string name="release_notes">Release notes</string>
|
<string name="release_notes">Release notes</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user