Merge pull request #25 from Iamlooker/root-installation

Root installation
This commit is contained in:
LooKeR 2021-10-13 00:35:41 +05:30 committed by GitHub
commit a2bb4632fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 923 additions and 1198 deletions

View File

@ -1,7 +1,5 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
name: Bug report about: Create a report to help us improve title: ''
labels: ''
assignees: ''
@ -12,6 +10,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@ -24,11 +23,13 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]

View File

@ -1,7 +1,5 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
name: Custom issue template about: Describe this issue template's purpose here. title: ''
labels: ''
assignees: ''

View File

@ -1,7 +1,5 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
name: Feature request about: Suggest an idea for this project title: ''
labels: ''
assignees: ''

View File

@ -6,7 +6,8 @@ Material-ify with Droid-ify.
Unofficial F-Droid client with Material UI.
This app is an Direct Adaptation/Modification of [Foxy-Droid](https://github.com/kitsunyan/foxy-droid/)
This app is an Direct Adaptation/Modification
of [Foxy-Droid](https://github.com/kitsunyan/foxy-droid/)
### Features
@ -21,7 +22,8 @@ This app is an Direct Adaptation/Modification of [Foxy-Droid](https://github.com
## Building and Installing
Specify your Android SDK path either using the `ANDROID_HOME` environment variable, or by filling out the `sdk.dir`
Specify your Android SDK path either using the `ANDROID_HOME` environment variable, or by filling
out the `sdk.dir`
property in `local.properties`.
Signing can be done automatically using `keystore.properties` as follows:
@ -33,8 +35,10 @@ key.alias=key-alias
key.password=key-password
```
Run `./gradlew assembleRelease` to build the package, which can be installed using the Android package manager.
Run `./gradlew assembleRelease` to build the package, which can be installed using the Android
package manager.
## License
Droid-ify is available under the terms of the GNU General Public License v3 or later. Copyright © 2020 Iamlooker.
Droid-ify is available under the terms of the GNU General Public License v3 or later. Copyright ©
2020 Iamlooker.

View File

@ -1,27 +0,0 @@
#!/bin/bash
set -e
cd "`dirname "$0"`"
dimensions=(mdpi:1 hdpi:1.5 xhdpi:2 xxhdpi:3 xxxhdpi:4)
res='../src/main/res'
cp 'launcher.svg' 'launcher-foreground.svg'
inkscape --select circle --verb EditDelete --verb=FileSave --verb=FileQuit \
'launcher-foreground.svg'
for dimension in ${dimensions[@]}; do
resource="${dimension%:*}"
scale="${dimension#*:}"
mkdir -p "$res/mipmap-$resource" "$res/drawable-$resource"
size="`bc <<< "48 * $scale"`"
inkscape 'launcher.svg' -a 15:15:93:93 -w "$size" -h "$size" \
-e "$res/mipmap-$resource/ic_launcher.png"
optipng "$res/mipmap-$resource/ic_launcher.png"
size="`bc <<< "108 * $scale"`"
inkscape 'launcher-foreground.svg' -w "$size" -h "$size" \
-e "$res/drawable-$resource/ic_launcher_foreground.png"
optipng "$res/drawable-$resource/ic_launcher_foreground.png"
done
rm 'launcher-foreground.svg'

View File

@ -1,273 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
style="enable-background:new"
id="svg3"
version="1.1"
viewBox="0 0 108 108"
height="108"
width="108">
<metadata
id="metadata55">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs17">
<clipPath
id="paper-clip"
clipPathUnits="userSpaceOnUse">
<path
id="paper-clip-path"
d="m 67.759585,28.469613 -18.355472,18.146485 -21.453125,-4.732422 9.087891,24.064453 25.894536,12.974609 12.37695,-23.86914 -1.93359,-0.66211 z" />
</clipPath>
<filter
id="paper-inner-shadow">
<feFlood
id="feFlood6"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.2" />
<feComposite
id="feComposite8"
result="composite1"
operator="in"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur10"
result="blur"
stdDeviation="2"
in="composite1" />
<feOffset
id="feOffset12"
result="offset"
dy="0"
dx="0" />
<feComposite
id="feComposite14"
result="composite2"
operator="over"
in2="offset"
in="SourceGraphic" />
</filter>
<filter
id="paper-edge-1"
style="color-interpolation-filters:sRGB">
<feFlood
id="feFlood958"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.2" />
<feComposite
id="feComposite960"
result="composite1"
operator="out"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur962"
result="blur"
stdDeviation="0"
in="composite1" />
<feOffset
id="feOffset964"
result="offset"
dy="0.2"
dx="0.2" />
<feComposite
id="feComposite966"
result="composite2"
operator="atop"
in2="SourceGraphic"
in="offset" />
</filter>
<filter
id="paper-edge-2"
style="color-interpolation-filters:sRGB">
<feFlood
id="feFlood1388"
result="flood"
flood-color="rgb(255,255,255)"
flood-opacity="0.2" />
<feComposite
id="feComposite1390"
result="composite1"
operator="out"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur1392"
result="blur"
stdDeviation="0"
in="composite1" />
<feOffset
id="feOffset1394"
result="offset"
dy="-0.1"
dx="0.3" />
<feComposite
id="feComposite1396"
result="composite2"
operator="atop"
in2="SourceGraphic"
in="offset" />
</filter>
<filter
id="paper-shadow"
style="color-interpolation-filters:sRGB">
<feFlood
id="feFlood1506"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.4" />
<feComposite
id="feComposite1508"
result="composite1"
operator="in"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur1510"
result="blur"
stdDeviation="2"
in="composite1" />
<feOffset
id="feOffset1512"
result="offset"
dy="0"
dx="0" />
<feComposite
id="feComposite1514"
result="composite2"
operator="over"
in2="offset"
in="SourceGraphic" />
</filter>
<filter
id="circle-shadow"
style="color-interpolation-filters:sRGB">
<feFlood
id="feFlood1626"
result="flood"
flood-color="rgb(255,255,255)"
flood-opacity="0.2" />
<feComposite
id="feComposite1628"
result="composite1"
operator="out"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur1630"
result="blur"
stdDeviation="0"
in="composite1" />
<feOffset
id="feOffset1632"
result="offset"
dy="0.5"
dx="0" />
<feComposite
id="feComposite1634"
result="fbSourceGraphic"
operator="atop"
in2="SourceGraphic"
in="offset" />
<feFlood
in="fbSourceGraphic"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.2"
id="feFlood1640" />
<feComposite
result="composite1"
operator="out"
in="flood"
id="feComposite1642"
in2="fbSourceGraphic" />
<feGaussianBlur
result="blur"
stdDeviation="0"
in="composite1"
id="feGaussianBlur1644" />
<feOffset
result="offset"
dy="-0.5"
dx="0"
id="feOffset1646" />
<feComposite
result="fbSourceGraphic"
operator="atop"
in="offset"
id="feComposite1648"
in2="fbSourceGraphic" />
<feFlood
in="fbSourceGraphic"
result="flood"
flood-color="rgb(0,0,0)"
flood-opacity="0.2"
id="feFlood1664" />
<feComposite
result="composite1"
operator="in"
in="flood"
id="feComposite1666"
in2="fbSourceGraphic" />
<feGaussianBlur
result="blur"
stdDeviation="1"
in="composite1"
id="feGaussianBlur1668" />
<feOffset
result="offset"
dy="1"
dx="0"
id="feOffset1670" />
<feComposite
result="composite2"
operator="over"
in="fbSourceGraphic"
id="feComposite1672"
in2="offset" />
</filter>
</defs>
<circle
r="36"
cy="54"
cx="54"
id="circle"
style="fill:#262c38;filter:url(#circle-shadow)" />
<g
style="filter:url(#paper-shadow)"
id="paper-group">
<path
d="m 67.75836,28.470764 -23.382292,23.115602 -0.0887,1.254642 29.189963,2.017946 z"
style="fill:#1976d2"
id="paper-4" />
<path
style="fill:#47a2fc;filter:url(#paper-inner-shadow)"
d="m 27.949219,41.884766 9.08789,24.064453 25.894532,12.974609 12.376953,-23.86914 -22.298828,-7.638672 v -0.002 z"
clip-path="url(#paper-clip)"
id="paper-3" />
<path
d="m 53.009473,47.414648 -15.970174,18.53113 25.894116,12.97696 z"
style="fill:#1976d2;filter:url(#paper-edge-1)"
id="paper-2" />
<path
style="fill:#47a2fc;filter:url(#paper-edge-2)"
d="m 53.009766,47.414016 9.923828,31.503906 12.375,-23.865234 z"
id="paper-1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -5,21 +5,17 @@ import android.app.Application
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.*
import android.content.pm.PackageInfo
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.content.ProductPreferences
import com.looker.droidify.database.Database
import com.looker.droidify.entity.InstalledItem
import com.looker.droidify.index.RepositoryUpdater
import com.looker.droidify.network.Downloader
import com.looker.droidify.network.PicassoDownloader
import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService
import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.Utils.toInstalledItem
import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.extension.android.singleSignature
import com.looker.droidify.utility.extension.android.versionCodeCompat
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import java.net.InetSocketAddress
@ -27,10 +23,6 @@ import java.net.Proxy
@Suppress("unused")
class MainApplication : Application() {
private fun PackageInfo.toInstalledItem(): InstalledItem {
val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty()
return InstalledItem(packageName, versionName.orEmpty(), versionCodeCompat, signatureString)
}
override fun onCreate() {
super.onCreate()

View File

@ -26,6 +26,8 @@ import com.looker.droidify.service.Connection
import com.looker.droidify.service.DownloadService
import com.looker.droidify.utility.RxUtils
import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.Utils.startPackageInstaller
import com.looker.droidify.utility.Utils.startUpdate
import com.looker.droidify.utility.extension.android.*
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
@ -134,7 +136,6 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks {
}
addOnScrollListener(scrollListener)
addItemDecoration(adapter.gridItemDecoration)
// addItemDecoration(DividerItemDecoration(context, adapter::configureDivider))
savedInstanceState?.getParcelable<ProductAdapter.SavedState>(STATE_ADAPTER)
?.let(adapter::restoreState)
layoutManagerState = savedInstanceState?.getParcelable(STATE_LAYOUT_MANAGER)
@ -385,27 +386,7 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks {
ProductAdapter.Action.INSTALL,
ProductAdapter.Action.UPDATE -> {
val installedItem = installed?.installedItem
val productRepository = Product.findSuggested(products, installedItem) { it.first }
val compatibleReleases = productRepository?.first?.selectedReleases.orEmpty()
.filter { installedItem == null || installedItem.signature == it.signature }
val release = if (compatibleReleases.size >= 2) {
compatibleReleases
.filter { it.platforms.contains(Android.primaryPlatform) }
.minByOrNull { it.platforms.size }
?: compatibleReleases.minByOrNull { it.platforms.size }
?: compatibleReleases.firstOrNull()
} else {
compatibleReleases.firstOrNull()
}
val binder = downloadConnection.binder
if (productRepository != null && release != null && binder != null) {
binder.enqueue(
packageName,
productRepository.first.name,
productRepository.second,
release
)
} else Unit
startUpdate(packageName, installedItem, products, downloadConnection)
}
ProductAdapter.Action.LAUNCH -> {
val launcherActivities = installed?.launcherActivities.orEmpty()

View File

@ -1,7 +1,6 @@
package com.looker.droidify.screen
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcel
import android.view.ViewGroup
@ -11,11 +10,10 @@ import android.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.looker.droidify.R
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.database.CursorOwner
import com.looker.droidify.utility.KParcelable
import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.Utils.startPackageInstaller
import com.looker.droidify.utility.extension.resources.getDrawableFromAttr
import com.looker.droidify.utility.extension.text.nullIfEmpty
@ -217,11 +215,7 @@ abstract class ScreenActivity : FragmentActivity() {
is SpecialIntent.Install -> {
val packageName = specialIntent.packageName
if (!packageName.isNullOrEmpty()) {
val fragment = currentFragment
if (fragment !is ProductFragment || fragment.packageName != packageName) {
pushFragment(ProductFragment(packageName))
}
specialIntent.cacheFileName?.let(::startPackageInstaller)
specialIntent.cacheFileName?.let { startPackageInstaller(it) }
}
Unit
}
@ -242,20 +236,6 @@ abstract class ScreenActivity : FragmentActivity() {
}
}
internal fun startPackageInstaller(cacheFileName: String) {
val (uri, flags) = if (Android.sdk(24)) {
Pair(Cache.getReleaseUri(this, cacheFileName), Intent.FLAG_GRANT_READ_URI_PERMISSION)
} else {
Pair(Uri.fromFile(Cache.getReleaseFile(this, cacheFileName)), 0)
}
// TODO Handle deprecation
@Suppress("DEPRECATION")
startActivity(
Intent(Intent.ACTION_INSTALL_PACKAGE)
.setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags)
)
}
internal fun navigateProduct(packageName: String) = pushFragment(ProductFragment(packageName))
internal fun navigateRepositories() = pushFragment(RepositoriesFragment())
internal fun navigatePreferences() = pushFragment(SettingsFragment())

View File

@ -19,6 +19,7 @@ import com.looker.droidify.BuildConfig
import com.looker.droidify.R
import com.looker.droidify.content.Preferences
import com.looker.droidify.utility.extension.resources.*
import com.topjohnwu.superuser.Shell
import io.reactivex.rxjava3.disposables.Disposable
@ -125,7 +126,7 @@ class SettingsFragment : ScreenFragment() {
}
}
addText(
title = "Droid-ify",
title = getString(R.string.application_name),
summary = "v ${BuildConfig.VERSION_NAME}"
)
}
@ -181,6 +182,9 @@ class SettingsFragment : ScreenFragment() {
preferences[Preferences.Key.ProxyHost]?.setEnabled(enabled)
preferences[Preferences.Key.ProxyPort]?.setEnabled(enabled)
}
preferences[Preferences.Key.RootPermission]?.setEnabled(
Shell.getCachedShell()?.isRoot ?: Shell.getShell().isRoot
)
if (key == Preferences.Key.Theme) {
requireActivity().recreate()
}

View File

@ -14,6 +14,7 @@ import com.looker.droidify.Common
import com.looker.droidify.MainActivity
import com.looker.droidify.R
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.entity.Release
import com.looker.droidify.entity.Repository
import com.looker.droidify.network.Downloader
@ -300,9 +301,17 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
stateSubject.onNext(State.Success(task.packageName, task.name, task.release) {
consumed = true
})
if (!consumed) {
showNotificationInstall(task)
}
if (consumed || (Preferences[Preferences.Key.RootPermission])) {
PendingIntent.getBroadcast(
this,
0,
Intent(this, Receiver::class.java)
.setAction("$ACTION_INSTALL.${task.packageName}")
.putExtra(EXTRA_CACHE_FILE_NAME, task.release.cacheFileName),
PendingIntent.FLAG_UPDATE_CURRENT
)
.send()
} else showNotificationInstall(task)
}
private fun validatePackage(task: Task, file: File): ValidationError? {
@ -436,7 +445,7 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result, throwable ->
currentTask = null
throwable?.printStackTrace()
throwable.printStackTrace()
if (result == null || !result.success) {
showNotificationError(
task,

View File

@ -1,15 +1,31 @@
package com.looker.droidify.utility
import android.animation.ValueAnimator
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.Signature
import android.graphics.drawable.Drawable
import android.net.Uri
import android.provider.Settings
import android.util.Log
import com.looker.droidify.R
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.entity.InstalledItem
import com.looker.droidify.entity.Product
import com.looker.droidify.entity.Repository
import com.looker.droidify.service.Connection
import com.looker.droidify.service.DownloadService
import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.extension.android.singleSignature
import com.looker.droidify.utility.extension.android.versionCodeCompat
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.resources.getDrawableCompat
import com.looker.droidify.utility.extension.text.hex
import com.topjohnwu.superuser.Shell
import java.io.File
import java.security.MessageDigest
import java.security.cert.Certificate
import java.security.cert.CertificateEncodingException
@ -21,6 +37,11 @@ object Utils {
.apply { setTintList(context.getColorFromAttr(tintAttrResId)) }
}
fun PackageInfo.toInstalledItem(): InstalledItem {
val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty()
return InstalledItem(packageName, versionName.orEmpty(), versionCodeCompat, signatureString)
}
fun getDefaultApplicationIcons(context: Context): Pair<Drawable, Drawable> {
val progressIcon: Drawable =
createDefaultApplicationIcon(context, android.R.attr.textColorSecondary)
@ -78,4 +99,92 @@ object Utils {
) != 0f
}
}
internal fun Activity.startPackageInstaller(cacheFileName: String) {
val file = Cache.getReleaseFile(this, cacheFileName)
if (Preferences[Preferences.Key.RootPermission]) {
val commandBuilder = StringBuilder()
val verifyState = getVerifyState()
if (verifyState == "1") commandBuilder.append("settings put global verifier_verify_adb_installs 0 ; ")
commandBuilder.append(getPackageInstallCommand(file))
commandBuilder.append(" ; settings put global verifier_verify_adb_installs $verifyState")
val result = Shell.su(commandBuilder.toString()).exec()
if (result.isSuccess) Shell.su("${getUtilBoxPath()} rm ${quote(file.absolutePath)}")
} else {
val (uri, flags) = if (Android.sdk(24)) {
Pair(
Cache.getReleaseUri(this, cacheFileName),
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
} else {
Pair(Uri.fromFile(file), 0)
}
// TODO Handle deprecation
@Suppress("DEPRECATION")
startActivity(
Intent(Intent.ACTION_INSTALL_PACKAGE)
.setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags)
)
}
}
fun startUpdate(
packageName: String,
installedItem: InstalledItem?,
products: List<Pair<Product, Repository>>,
downloadConnection: Connection<DownloadService.Binder, DownloadService>
) {
val productRepository = Product.findSuggested(products, installedItem) { it.first }
val compatibleReleases = productRepository?.first?.selectedReleases.orEmpty()
.filter { installedItem == null || installedItem.signature == it.signature }
val release = if (compatibleReleases.size >= 2) {
compatibleReleases
.filter { it.platforms.contains(Android.primaryPlatform) }
.minByOrNull { it.platforms.size }
?: compatibleReleases.minByOrNull { it.platforms.size }
?: compatibleReleases.firstOrNull()
} else {
compatibleReleases.firstOrNull()
}
val binder = downloadConnection.binder
if (productRepository != null && release != null && binder != null) {
binder.enqueue(
packageName,
productRepository.first.name,
productRepository.second,
release
)
} else Unit
}
private fun getPackageInstallCommand(cacheFile: File): String =
"cat \"${cacheFile.absolutePath}\" | pm install -t -r -S ${cacheFile.length()}"
private fun getVerifyState(): String =
Shell.sh("settings get global verifier_verify_adb_installs").exec().out[0]
private fun quote(string: String) =
"\"${string.replace(Regex("""[\\$"`]""")) { c -> "\\${c.value}" }}\""
private fun getUtilBoxPath(): String {
listOf("toybox", "busybox").forEach {
var shellResult = Shell.su("which $it").exec()
if (shellResult.out.isNotEmpty()) {
val utilBoxPath = shellResult.out.joinToString("")
if (utilBoxPath.isNotEmpty()) {
val utilBoxQuoted = quote(utilBoxPath)
shellResult = Shell.su("$utilBoxQuoted --version").exec()
if (shellResult.out.isNotEmpty()) {
val utilBoxVersion = shellResult.out.joinToString("")
Log.i(
this.javaClass.canonicalName,
"Using Utilbox $it : $utilBoxQuoted $utilBoxVersion"
)
}
return utilBoxQuoted
}
}
}
return ""
}
}

View File

@ -1,19 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="100"
android:interpolator="@android:interpolator/decelerate_quad"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:duration="100"
android:interpolator="@android:interpolator/decelerate_quad" />
android:valueTo="1" />
<objectAnimator
android:duration="175"
android:interpolator="@android:interpolator/decelerate_quad"
android:propertyName="percentTranslationY"
android:valueFrom="0.08"
android:valueTo="0"
android:duration="175"
android:interpolator="@android:interpolator/decelerate_quad" />
android:valueTo="0" />
</set>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="175" />

View File

@ -1,20 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android">
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:startOffset="50"
android:duration="75"
android:interpolator="@android:interpolator/linear" />
android:interpolator="@android:interpolator/linear"
android:propertyName="alpha"
android:startOffset="50"
android:valueFrom="1"
android:valueTo="0" />
<objectAnimator
android:duration="125"
android:interpolator="@android:interpolator/accelerate_quad"
android:propertyName="percentTranslationY"
android:valueFrom="0"
android:valueTo="0.08"
android:duration="125"
android:interpolator="@android:interpolator/accelerate_quad" />
android:valueTo="0.08" />
</set>

View File

@ -1,13 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="false"
android:color="@color/accent_default_dark"
android:alpha="0.3" />
<item android:alpha="0.3" android:color="@color/accent_default_dark" android:state_enabled="false" />
<item
android:color="@color/accent_default_dark" />
<item android:color="@color/accent_default_dark" />
</selector>

View File

@ -1,13 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="false"
android:color="@color/accent_default_light"
android:alpha="0.26" />
<item android:alpha="0.26" android:color="@color/accent_default_light" android:state_enabled="false" />
<item
android:color="@color/accent_default_light" />
<item android:color="@color/accent_default_light" />
</selector>

View File

@ -1,13 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="false"
android:color="@color/error_default_dark"
android:alpha="0.3" />
<item android:alpha="0.3" android:color="@color/error_default_dark" android:state_enabled="false" />
<item
android:color="@color/error_default_dark" />
<item android:color="@color/error_default_dark" />
</selector>

View File

@ -1,13 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="false"
android:color="@color/error_default_light"
android:alpha="0.26" />
<item android:alpha="0.26" android:color="@color/error_default_light" android:state_enabled="false" />
<item
android:color="@color/error_default_light" />
<item android:color="@color/error_default_light" />
</selector>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="96dp"
android:height="96dp"
android:viewportWidth="96"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"

View File

@ -31,9 +31,9 @@
android:id="@+id/fragment_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:paddingHorizontal="10dp"
android:paddingTop="10dp"
android:layout_weight="1"
android:background="?android:attr/colorBackground" />
android:background="?android:attr/colorBackground"
android:paddingHorizontal="10dp"
android:paddingTop="10dp" />
</com.looker.droidify.widget.FragmentLinearLayout>

View File

@ -1,20 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:background="?android:attr/selectableItemBackground">
android:paddingEnd="16dp">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:scaleType="centerInside"
android:layout_gravity="center"
android:scaleType="centerInside"
android:tint="?android:attr/textColorSecondary"
android:tintMode="src_in"
tools:ignore="ContentDescription" />
@ -23,8 +22,8 @@
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="32dp"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:textColor="?android:attr/textColor"

View File

@ -3,8 +3,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingVertical="8dp"
android:paddingHorizontal="16dp">
android:paddingHorizontal="16dp"
android:paddingVertical="8dp">
<TextView
android:id="@+id/title"

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="sections_list" />
<item type="id" name="divider_configuration" />
<item type="id" name="fragment_pager" />
<item type="id" name="main_content" />
<item type="id" name="preferences_list" />
<item type="id" name="toolbar_search" />
<item name="sections_list" type="id" />
<item name="divider_configuration" type="id" />
<item name="fragment_pager" type="id" />
<item name="main_content" type="id" />
<item name="preferences_list" type="id" />
<item name="toolbar_search" type="id" />
</resources>