This commit is contained in:
Felitendo
2025-05-20 15:52:19 +02:00
parent a081d24035
commit 22d5a09491
291 changed files with 0 additions and 22064 deletions

View File

@@ -1,276 +0,0 @@
package com.looker.droidify
import android.annotation.SuppressLint
import android.app.Application
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatDelegate
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import androidx.work.NetworkType
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.disk.DiskCache
import coil.memory.MemoryCache
import com.looker.core.common.Constants
import com.looker.core.common.cache.Cache
import com.looker.core.common.extension.getInstalledPackagesCompat
import com.looker.core.common.extension.jobScheduler
import com.looker.core.common.log
import com.looker.core.datastore.SettingsRepository
import com.looker.core.datastore.get
import com.looker.core.datastore.model.AutoSync
import com.looker.core.datastore.model.InstallerType
import com.looker.core.datastore.model.ProxyPreference
import com.looker.core.datastore.model.ProxyType
import com.looker.droidify.content.ProductPreferences
import com.looker.droidify.database.Database
import com.looker.droidify.index.RepositoryUpdater
import com.looker.droidify.receivers.InstalledAppReceiver
import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService
import com.looker.droidify.sync.SyncPreference
import com.looker.droidify.sync.toJobNetworkType
import com.looker.droidify.utility.extension.toInstalledItem
import com.looker.droidify.work.CleanUpWorker
import com.looker.installer.InstallManager
import com.looker.installer.installers.root.RootPermissionHandler
import com.looker.installer.installers.shizuku.ShizukuPermissionHandler
import com.looker.network.Downloader
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.collectIndexed
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
import java.net.InetSocketAddress
import java.net.Proxy
import javax.inject.Inject
import kotlin.time.Duration.Companion.INFINITE
import kotlin.time.Duration.Companion.hours
import com.looker.core.common.R as CommonR
@HiltAndroidApp
class MainApplication : Application(), ImageLoaderFactory, Configuration.Provider {
private val parentJob = SupervisorJob()
private val appScope = CoroutineScope(Dispatchers.Default + parentJob)
@Inject
lateinit var settingsRepository: SettingsRepository
@Inject
lateinit var installer: InstallManager
@Inject
lateinit var downloader: Downloader
@Inject
lateinit var shizukuPermissionHandler: ShizukuPermissionHandler
@Inject
lateinit var rootPermissionHandler: RootPermissionHandler
@Inject
lateinit var workerFactory: HiltWorkerFactory
override fun onCreate() {
super.onCreate()
val databaseUpdated = Database.init(this)
ProductPreferences.init(this, appScope)
RepositoryUpdater.init(appScope, downloader)
listenApplications()
checkLanguage()
updatePreference()
setupInstaller()
if (databaseUpdated) forceSyncAll()
}
override fun onTerminate() {
super.onTerminate()
appScope.cancel("Application Terminated")
installer.close()
}
private fun setupInstaller() {
appScope.launch {
launch {
settingsRepository.get { installerType }.collect {
if (it == InstallerType.SHIZUKU) handleShizukuInstaller()
if (it == InstallerType.ROOT) {
if (!rootPermissionHandler.isGranted) {
settingsRepository.setInstallerType(InstallerType.Default)
}
}
}
}
installer()
}
}
private fun CoroutineScope.handleShizukuInstaller() = launch {
shizukuPermissionHandler.state.collect { (isGranted, isAlive, _) ->
if (isAlive && isGranted) {
settingsRepository.setInstallerType(InstallerType.SHIZUKU)
return@collect
}
if (isAlive) {
settingsRepository.setInstallerType(InstallerType.Default)
shizukuPermissionHandler.requestPermission()
return@collect
}
settingsRepository.setInstallerType(InstallerType.Default)
}
}
private fun listenApplications() {
registerReceiver(
InstalledAppReceiver(packageManager),
IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addDataScheme("package")
}
)
val installedItems =
packageManager.getInstalledPackagesCompat()
?.map { it.toInstalledItem() }
?: return
Database.InstalledAdapter.putAll(installedItems)
}
private fun checkLanguage() {
appScope.launch {
val lastSetLanguage = settingsRepository.getInitial().language
val systemSetLanguage = AppCompatDelegate.getApplicationLocales().toLanguageTags()
if (systemSetLanguage != lastSetLanguage && lastSetLanguage != "system") {
settingsRepository.setLanguage(systemSetLanguage)
}
}
}
private fun updatePreference() {
appScope.launch {
launch {
settingsRepository.get { unstableUpdate }.drop(1).collect {
forceSyncAll()
}
}
launch {
settingsRepository.get { autoSync }.collectIndexed { index, syncMode ->
// Don't update sync job on initial collect
updateSyncJob(index > 0, syncMode)
}
}
launch {
settingsRepository.get { cleanUpInterval }.drop(1).collect {
if (it == INFINITE) {
CleanUpWorker.removeAllSchedules(applicationContext)
} else {
CleanUpWorker.scheduleCleanup(applicationContext, it)
}
}
}
launch {
settingsRepository.get { proxy }.collect(::updateProxy)
}
}
}
private fun updateProxy(proxyPreference: ProxyPreference) {
val type = proxyPreference.type
val host = proxyPreference.host
val port = proxyPreference.port
val socketAddress = when (type) {
ProxyType.DIRECT -> null
ProxyType.HTTP, ProxyType.SOCKS -> {
try {
InetSocketAddress.createUnresolved(host, port)
} catch (e: IllegalArgumentException) {
log(e)
null
}
}
}
val androidProxyType = when (type) {
ProxyType.DIRECT -> Proxy.Type.DIRECT
ProxyType.HTTP -> Proxy.Type.HTTP
ProxyType.SOCKS -> Proxy.Type.SOCKS
}
val determinedProxy = socketAddress?.let { Proxy(androidProxyType, it) } ?: Proxy.NO_PROXY
downloader.setProxy(determinedProxy)
}
private fun updateSyncJob(force: Boolean, autoSync: AutoSync) {
if (autoSync == AutoSync.NEVER) {
jobScheduler?.cancel(Constants.JOB_ID_SYNC)
return
}
val jobScheduler = jobScheduler
val syncConditions = when (autoSync) {
AutoSync.ALWAYS -> SyncPreference(NetworkType.CONNECTED)
AutoSync.WIFI_ONLY -> SyncPreference(NetworkType.UNMETERED)
AutoSync.WIFI_PLUGGED_IN -> SyncPreference(NetworkType.UNMETERED, pluggedIn = true)
else -> null
}
val isCompleted = jobScheduler?.allPendingJobs
?.any { it.id == Constants.JOB_ID_SYNC } == false
if ((force || isCompleted) && syncConditions != null) {
val period = 12.hours.inWholeMilliseconds
val job = SyncService.Job.create(
context = this,
periodMillis = period,
networkType = syncConditions.toJobNetworkType(),
isCharging = syncConditions.pluggedIn,
isBatteryLow = syncConditions.batteryNotLow
)
jobScheduler?.schedule(job)
}
}
private fun forceSyncAll() {
Database.RepositoryAdapter.getAll().forEach {
if (it.lastModified.isNotEmpty() || it.entityTag.isNotEmpty()) {
Database.RepositoryAdapter.put(it.copy(lastModified = "", entityTag = ""))
}
}
Connection(SyncService::class.java, onBind = { connection, binder ->
binder.sync(SyncService.SyncRequest.FORCE)
connection.unbind(this)
}).bind(this)
}
class BootReceiver : BroadcastReceiver() {
@SuppressLint("UnsafeProtectedBroadcastReceiver")
override fun onReceive(context: Context, intent: Intent) = Unit
}
override fun newImageLoader(): ImageLoader {
val memoryCache = MemoryCache.Builder(this)
.maxSizePercent(0.25)
.build()
val diskCache = DiskCache.Builder()
.directory(Cache.getImagesDir(this))
.maxSizePercent(0.05)
.build()
return ImageLoader.Builder(this)
.memoryCache(memoryCache)
.diskCache(diskCache)
.error(CommonR.drawable.ic_cannot_load)
.crossfade(350)
.build()
}
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
}

View File

@@ -1,308 +0,0 @@
package com.looker.droidify
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
import com.looker.core.common.DeeplinkType
import com.looker.core.common.SdkCheck
import com.looker.core.common.deeplinkType
import com.looker.core.common.extension.homeAsUp
import com.looker.core.common.extension.inputManager
import com.looker.core.common.requestNotificationPermission
import com.looker.core.datastore.SettingsRepository
import com.looker.core.datastore.extension.getThemeRes
import com.looker.core.datastore.get
import com.looker.droidify.database.CursorOwner
import com.looker.droidify.ui.appDetail.AppDetailFragment
import com.looker.droidify.ui.favourites.FavouritesFragment
import com.looker.droidify.ui.repository.EditRepositoryFragment
import com.looker.droidify.ui.repository.RepositoriesFragment
import com.looker.droidify.ui.repository.RepositoryFragment
import com.looker.droidify.ui.settings.SettingsFragment
import com.looker.droidify.ui.tabsFragment.TabsFragment
import com.looker.installer.InstallManager
import com.looker.installer.model.installFrom
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
@AndroidEntryPoint
abstract class ScreenActivity : AppCompatActivity() {
companion object {
private const val STATE_FRAGMENT_STACK = "fragmentStack"
}
sealed interface SpecialIntent {
data object Updates : SpecialIntent
class Install(val packageName: String?, val cacheFileName: String?) : SpecialIntent
}
private val notificationPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { }
@Inject
lateinit var installer: InstallManager
@Parcelize
private class FragmentStackItem(
val className: String, val arguments: Bundle?, val savedState: Fragment.SavedState?
) : Parcelable
lateinit var cursorOwner: CursorOwner
private set
private var onBackPressedCallback: OnBackPressedCallback? = null
private val fragmentStack = mutableListOf<FragmentStackItem>()
private val currentFragment: Fragment?
get() {
supportFragmentManager.executePendingTransactions()
return supportFragmentManager.findFragmentById(R.id.main_content)
}
@EntryPoint
@InstallIn(SingletonComponent::class)
interface CustomUserRepositoryInjector {
fun settingsRepository(): SettingsRepository
}
private fun collectChange() {
val hiltEntryPoint = EntryPointAccessors.fromApplication(
this, CustomUserRepositoryInjector::class.java
)
val newSettings = hiltEntryPoint.settingsRepository().get { theme to dynamicTheme }
runBlocking {
val theme = newSettings.first()
setTheme(
resources.configuration.getThemeRes(
theme = theme.first, dynamicTheme = theme.second
)
)
}
lifecycleScope.launch {
newSettings.drop(1).collect { themeAndDynamic ->
setTheme(
resources.configuration.getThemeRes(
theme = themeAndDynamic.first, dynamicTheme = themeAndDynamic.second
)
)
recreate()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
collectChange()
super.onCreate(savedInstanceState)
val rootView = FrameLayout(this).apply { id = R.id.main_content }
addContentView(
rootView, ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
)
requestNotificationPermission(request = notificationPermission::launch)
supportFragmentManager.addFragmentOnAttachListener { _, _ ->
hideKeyboard()
}
if (savedInstanceState == null) {
cursorOwner = CursorOwner()
supportFragmentManager.commit {
add(cursorOwner, CursorOwner::class.java.name)
}
} else {
cursorOwner =
supportFragmentManager.findFragmentByTag(CursorOwner::class.java.name) as CursorOwner
}
savedInstanceState?.getParcelableArrayList<FragmentStackItem>(STATE_FRAGMENT_STACK)
?.let { fragmentStack += it }
if (savedInstanceState == null) {
replaceFragment(TabsFragment(), null)
if ((intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
handleIntent(intent)
}
}
if (SdkCheck.isR) {
window.statusBarColor = resources.getColor(android.R.color.transparent, theme)
window.navigationBarColor = resources.getColor(android.R.color.transparent, theme)
WindowCompat.setDecorFitsSystemWindows(window, false)
}
backHandler()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelableArrayList(STATE_FRAGMENT_STACK, ArrayList(fragmentStack))
}
private fun backHandler() {
if (onBackPressedCallback == null) {
onBackPressedCallback = object : OnBackPressedCallback(enabled = false) {
override fun handleOnBackPressed() {
hideKeyboard()
popFragment()
}
}
onBackPressedDispatcher.addCallback(
this,
onBackPressedCallback!!,
)
}
onBackPressedCallback?.isEnabled = fragmentStack.isNotEmpty()
}
private fun replaceFragment(fragment: Fragment, open: Boolean?) {
if (open != null) {
currentFragment?.view?.translationZ =
(if (open) Int.MIN_VALUE else Int.MAX_VALUE).toFloat()
}
supportFragmentManager.commit {
if (open != null) {
setCustomAnimations(
if (open) R.animator.slide_in else 0,
if (open) R.animator.slide_in_keep else R.animator.slide_out
)
}
setReorderingAllowed(true)
replace(R.id.main_content, fragment)
}
}
private fun pushFragment(fragment: Fragment) {
currentFragment?.let {
fragmentStack.add(
FragmentStackItem(
it::class.java.name,
it.arguments,
supportFragmentManager.saveFragmentInstanceState(it)
)
)
}
replaceFragment(fragment, true)
backHandler()
}
private fun popFragment(): Boolean {
return fragmentStack.isNotEmpty() && run {
val stackItem = fragmentStack.removeAt(fragmentStack.size - 1)
val fragment = Class.forName(stackItem.className).newInstance() as Fragment
stackItem.arguments?.let(fragment::setArguments)
stackItem.savedState?.let(fragment::setInitialSavedState)
replaceFragment(fragment, false)
backHandler()
true
}
}
private fun hideKeyboard() {
inputManager?.hideSoftInputFromWindow((currentFocus ?: window.decorView).windowToken, 0)
}
internal fun onToolbarCreated(toolbar: Toolbar) {
if (fragmentStack.isNotEmpty()) {
toolbar.navigationIcon = toolbar.context.homeAsUp
toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() }
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntent(intent)
}
protected fun handleSpecialIntent(specialIntent: SpecialIntent) {
when (specialIntent) {
is SpecialIntent.Updates -> {
if (currentFragment !is TabsFragment) {
fragmentStack.clear()
replaceFragment(TabsFragment(), true)
}
val tabsFragment = currentFragment as TabsFragment
tabsFragment.selectUpdates()
backHandler()
}
is SpecialIntent.Install -> {
val packageName = specialIntent.packageName
if (!packageName.isNullOrEmpty()) {
navigateProduct(packageName)
specialIntent.cacheFileName?.also { cacheFile ->
val installItem = packageName installFrom cacheFile
lifecycleScope.launch { installer install installItem }
}
}
Unit
}
}::class
}
open fun handleIntent(intent: Intent?) {
when (intent?.action) {
Intent.ACTION_VIEW -> {
when (val deeplink = intent.deeplinkType) {
is DeeplinkType.AppDetail -> {
val fragment = currentFragment
if (fragment !is AppDetailFragment) {
navigateProduct(deeplink.packageName, deeplink.repoAddress)
}
}
is DeeplinkType.AddRepository -> {
navigateAddRepository(repoAddress = deeplink.address)
}
null -> {}
}
}
Intent.ACTION_SHOW_APP_INFO -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)
if (packageName != null && currentFragment !is AppDetailFragment) {
navigateProduct(packageName)
}
}
}
}
}
internal fun navigateFavourites() = pushFragment(FavouritesFragment())
internal fun navigateProduct(packageName: String, repoAddress: String? = null) =
pushFragment(AppDetailFragment(packageName, repoAddress))
internal fun navigateRepositories() = pushFragment(RepositoriesFragment())
internal fun navigatePreferences() = pushFragment(SettingsFragment.newInstance())
internal fun navigateAddRepository(repoAddress: String? = null) =
pushFragment(EditRepositoryFragment(null, repoAddress))
internal fun navigateRepository(repositoryId: Long) =
pushFragment(RepositoryFragment(repositoryId))
internal fun navigateEditRepository(repositoryId: Long) =
pushFragment(EditRepositoryFragment(repositoryId, null))
}

View File

@@ -1,46 +0,0 @@
package com.looker.droidify.utility.extension
import android.view.View
import com.looker.core.common.Singleton
import com.looker.core.common.extension.dpi
import com.looker.droidify.model.Product
import com.looker.droidify.model.ProductItem
import com.looker.droidify.model.Repository
object ImageUtils {
private val SUPPORTED_DPI = listOf(120, 160, 240, 320, 480, 640)
private var DeviceDpi = Singleton<String>()
fun Product.Screenshot.url(
repository: Repository,
packageName: String
): String {
val phoneType = when (type) {
Product.Screenshot.Type.PHONE -> "phoneScreenshots"
Product.Screenshot.Type.SMALL_TABLET -> "sevenInchScreenshots"
Product.Screenshot.Type.LARGE_TABLET -> "tenInchScreenshots"
}
return "${repository.address}/$packageName/$locale/$phoneType/$path"
}
fun ProductItem.icon(
view: View,
repository: Repository
): String? {
if (packageName.isBlank()) return null
if (icon.isBlank() && metadataIcon.isBlank()) return null
if (repository.version < 11 && icon.isNotBlank()) {
return "${repository.address}/icons/$icon"
}
if (icon.isNotBlank()) {
val deviceDpi = DeviceDpi.getOrUpdate {
(SUPPORTED_DPI.find { it >= view.dpi } ?: SUPPORTED_DPI.last()).toString()
}
return "${repository.address}/icons-$deviceDpi/$icon"
}
if (metadataIcon.isNotBlank()) {
return "${repository.address}/$packageName/$metadataIcon"
}
return null
}
}

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/exploreTab"
android:icon="@drawable/ic_public"
android:title="@string/explore" />
<item
android:id="@+id/latestTab"
android:icon="@drawable/ic_new_releases"
android:title="@string/latest" />
<item
android:id="@+id/installedTab"
android:icon="@drawable/ic_launch"
android:title="@string/installed" />
</menu>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,3 +0,0 @@
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true

View File

@@ -1,15 +0,0 @@
dependencyResolutionManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "build-logic"
include(":structure")

View File

@@ -1,62 +0,0 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
`kotlin-dsl`
}
group = "buildlogic"
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_17
}
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
compileOnly(libs.kotlin.ktlint)
compileOnly(libs.ksp.gradlePlugin)
}
gradlePlugin {
plugins {
register("lintPlugin") {
id = "looker.lint"
implementationClass = "AndroidLintPlugin"
}
register("serializationPlugin") {
id = "looker.serialization"
implementationClass = "AndroidSerializationPlugin"
}
register("hiltPlugin") {
id = "looker.hilt"
implementationClass = "AndroidHiltPlugin"
}
register("hiltWorkPlugin") {
id = "looker.hilt.work"
implementationClass = "AndroidHiltWorkerPlugin"
}
register("roomPlugin") {
id = "looker.room"
implementationClass = "AndroidRoomPlugin"
}
register("androidApplicationPlugin") {
id = "looker.android.application"
implementationClass = "AndroidApplicationPlugin"
}
register("androidLibraryPlugin") {
id = "looker.android.library"
implementationClass = "AndroidLibraryPlugin"
}
register("jvmLibraryPlugin") {
id = "looker.jvm.library"
implementationClass = "JvmLibraryPlugin"
}
}
}

View File

@@ -1,34 +0,0 @@
import com.android.build.api.dsl.ApplicationExtension
import com.looker.droidify.configureKotlinAndroid
import com.looker.droidify.kotlin2
import com.looker.droidify.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
class AndroidApplicationPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.android.application")
apply("org.jetbrains.kotlin.android")
}
extensions.configure<ApplicationExtension> {
configureKotlinAndroid(this)
buildToolsVersion = DefaultConfig.buildTools
defaultConfig {
targetSdk = DefaultConfig.compileSdk
applicationId = DefaultConfig.appId
versionCode = DefaultConfig.versionCode
versionName = DefaultConfig.versionName
}
}
dependencies {
add("implementation", kotlin2("stdlib", libs))
add("implementation", kotlin2("reflect", libs))
}
}
}
}

View File

@@ -1,26 +0,0 @@
import com.android.build.gradle.api.AndroidBasePlugin
import com.looker.droidify.getLibrary
import com.looker.droidify.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
class AndroidHiltPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.google.devtools.ksp")
dependencies {
add("ksp", libs.getLibrary("hilt.compiler"))
add("implementation", libs.getLibrary("hilt.core"))
}
/** Add support for Android modules, based on [AndroidBasePlugin] */
pluginManager.withPlugin("com.android.base") {
pluginManager.apply("dagger.hilt.android.plugin")
dependencies {
add("implementation", libs.getLibrary("hilt.android"))
}
}
}
}
}

View File

@@ -1,21 +0,0 @@
import com.looker.droidify.getLibrary
import com.looker.droidify.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
class AndroidHiltWorkerPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("looker.hilt")
}
dependencies {
add("implementation", libs.getLibrary("androidx.work.ktx"))
add("implementation", libs.getLibrary("hilt.ext.work"))
add("ksp", libs.getLibrary("hilt.ext.compiler"))
}
}
}
}

View File

@@ -1,48 +0,0 @@
import com.android.build.api.variant.LibraryAndroidComponentsExtension
import com.android.build.gradle.LibraryExtension
import com.looker.droidify.configureKotlinAndroid
import com.looker.droidify.kotlin2
import com.looker.droidify.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
class AndroidLibraryPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("com.android.library")
apply("org.jetbrains.kotlin.android")
}
extensions.configure<LibraryExtension> {
configureKotlinAndroid(this)
defaultConfig.targetSdk = DefaultConfig.compileSdk
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"${rootDir.path}/app/proguard.pro"
)
}
create("alpha") {
initWith(getByName("debug"))
isMinifyEnabled = false
}
}
}
extensions.configure<LibraryAndroidComponentsExtension> {
beforeVariants {
it.enableAndroidTest = it.enableAndroidTest
&& project.projectDir.resolve("src/androidTest").exists()
}
}
dependencies {
add("implementation", kotlin2("stdlib", libs))
add("implementation", kotlin2("reflect", libs))
}
}
}
}

View File

@@ -1,27 +0,0 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.jlleitschuh.gradle.ktlint.KtlintExtension
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
class AndroidLintPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.jlleitschuh.gradle.ktlint")
}
extensions.configure<KtlintExtension> {
android.set(true)
ignoreFailures.set(true)
debug.set(true)
reporters {
reporter(ReporterType.HTML)
}
filter {
exclude("**/generated/**")
}
}
}
}
}

View File

@@ -1,46 +0,0 @@
import com.google.devtools.ksp.gradle.KspExtension
import com.looker.droidify.getLibrary
import com.looker.droidify.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.gradle.process.CommandLineArgumentProvider
import java.io.File
class AndroidRoomPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.google.devtools.ksp")
extensions.configure<KspExtension> {
// The schemas directory contains a schema file for each version of the Room database.
// This is required to enable Room auto migrations.
// See https://developer.android.com/reference/kotlin/androidx/room/AutoMigration.
arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
}
dependencies {
add("implementation", libs.getLibrary("room.ktx"))
add("implementation", libs.getLibrary("room.runtime"))
add("ksp", libs.getLibrary("room.compiler"))
}
}
}
/**
* https://issuetracker.google.com/issues/132245929
* [Export schemas](https://developer.android.com/training/data-storage/room/migrating-db-versions#export-schemas)
*/
class RoomSchemaArgProvider(
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)
val schemaDir: File,
) : CommandLineArgumentProvider {
override fun asArguments() = listOf("room.schemaLocation=${schemaDir.path}")
}
}

View File

@@ -1,19 +0,0 @@
import com.looker.droidify.getLibrary
import com.looker.droidify.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
class AndroidSerializationPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.jetbrains.kotlin.plugin.serialization")
}
dependencies {
add("implementation", libs.getLibrary("kotlinx.serialization.json"))
}
}
}
}

View File

@@ -1,10 +0,0 @@
object DefaultConfig {
// Update [release_build.yml] along with this

View File

@@ -1,14 +0,0 @@
import com.looker.droidify.configureKotlinJvm
import org.gradle.api.Plugin
import org.gradle.api.Project
class JvmLibraryPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
with(pluginManager) {
apply("org.jetbrains.kotlin.jvm")
}
configureKotlinJvm()
}
}
}

View File

@@ -1,21 +0,0 @@
import org.gradle.kotlin.dsl.DependencyHandlerScope
import org.gradle.kotlin.dsl.project
object Modules {
const val app = ":app"
const val coreCommon = ":core:common"
const val coreData = ":core:data"
const val coreDatabase = ":core:database"
const val coreDatastore = ":core:datastore"
const val coreDI = ":core:di"
const val coreDomain = ":core:domain"
const val coreNetwork = ":core:network"
const val installer = ":installer"
const val sync = ":sync:fdroid"
}
fun DependencyHandlerScope.modules(vararg module: String) {
module.forEach {
add("implementation", project(it))
}
}

View File

@@ -1,79 +0,0 @@
package com.looker.droidify
import DefaultConfig
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.kotlin.dsl.assign
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.dependencies
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
// Taken from NIA sample app by Google
/**
* Configure base Kotlin with Android options
*/
internal fun Project.configureKotlinAndroid(
commonExtension: CommonExtension<*, *, *, *, *, *>,
) {
commonExtension.apply {
compileSdk = DefaultConfig.compileSdk
defaultConfig {
minSdk = DefaultConfig.minSdk
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
// Up to Java 11 APIs are available through desugaring
// https://developer.android.com/studio/write/java11-minimal-support-table
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
isCoreLibraryDesugaringEnabled = true
}
}
configureKotlin<KotlinAndroidProjectExtension>()
dependencies {
add("coreLibraryDesugaring", libs.getLibrary("android.desugarJdkLibs"))
}
}
internal fun Project.configureKotlinJvm() {
extensions.configure<JavaPluginExtension> {
// Up to Java 11 APIs are available through desugaring
// https://developer.android.com/studio/write/java11-minimal-support-table
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
configureKotlin<KotlinJvmProjectExtension>()
}
/**
* Configure base Kotlin options
*/
private inline fun <reified T : KotlinBaseExtension> Project.configureKotlin() = configure<T> {
when (this) {
is KotlinAndroidProjectExtension -> compilerOptions
is KotlinJvmProjectExtension -> compilerOptions
else -> TODO("Unsupported project extension $this ${T::class}")
}.apply {
// Use when hilt supports ksp2
// apiVersion = KotlinVersion.KOTLIN_2_0
jvmTarget = JvmTarget.JVM_11
freeCompilerArgs = listOf(
"-opt-in=kotlin.RequiresOptIn",
// Enable experimental coroutines APIs, including Flow
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-Xcontext-receivers"
)
}
}

View File

@@ -1,19 +0,0 @@
package com.looker.droidify
import org.gradle.api.Project
import org.gradle.api.artifacts.MinimalExternalModuleDependency
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.provider.Provider
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.kotlin
val Project.libs
get(): VersionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
fun VersionCatalog.getLibrary(alias: String): Provider<MinimalExternalModuleDependency> =
findLibrary(alias).get()
fun DependencyHandler.kotlin2(module: String, catalog: VersionCatalog): Any =
kotlin(module, version = catalog.findVersion("kotlin").get().strictVersion)

View File

@@ -1 +0,0 @@
/build

View File

@@ -1,47 +0,0 @@
import com.android.build.gradle.internal.tasks.factory.dependsOn
plugins {
alias(libs.plugins.looker.android.library)
alias(libs.plugins.looker.lint)
}
android {
namespace = "com.looker.core.common"
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
buildFeatures {
buildConfig = true
}
}
dependencies {
implementation(libs.kotlinx.coroutines.android)
implementation(libs.android.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.viewModel)
implementation(libs.androidx.recyclerview)
implementation(libs.coil.kt)
implementation(libs.jackson.core)
}
// using a task as a preBuild dependency instead of a function that takes some time insures that it runs
task("detectAndroidLocals") {
val langsList: MutableSet<String> = HashSet()
// in /res are (almost) all languages that have a translated string is saved. this is safer and saves some time
fileTree("src/main/res").visit {
if (this.file.path.endsWith("strings.xml") &&
this.file.canonicalFile.readText().contains("<string")
) {
var languageCode = this.file.parentFile.name.replace("values-", "")
languageCode = if (languageCode == "values") "en" else languageCode
langsList.add(languageCode)
}
}
val langsListString = "{${langsList.sorted().joinToString(",") { "\"${it}\"" }}}"
android.defaultConfig.buildConfigField("String[]", "DETECTED_LOCALES", langsListString)
}
tasks.preBuild.dependsOn("detectAndroidLocals")

View File

@@ -1,15 +0,0 @@
package com.looker.core.common
object Constants {
const val NOTIFICATION_CHANNEL_SYNCING = "syncing"
const val NOTIFICATION_CHANNEL_UPDATES = "updates"
const val NOTIFICATION_CHANNEL_DOWNLOADING = "downloading"
const val NOTIFICATION_CHANNEL_INSTALL = "install"
const val NOTIFICATION_ID_SYNCING = 1
const val NOTIFICATION_ID_UPDATES = 2
const val NOTIFICATION_ID_DOWNLOADING = 3
const val NOTIFICATION_ID_INSTALL = 4
const val JOB_ID_SYNC = 1
}

View File

@@ -1,80 +0,0 @@
package com.looker.core.common
import android.content.Intent
import com.looker.core.common.extension.get
private const val PERSONAL_HOST = "droidify.eu.org"
private val httpScheme = setOf("http", "https")
private val fdroidRepoScheme = setOf("fdroidrepo", "fdroidrepos")
private val supportedExternalHosts = setOf(
"f-droid.org",
"www.f-droid.org",
"staging.f-droid.org",
"apt.izzysoft.de"
)
val Intent.deeplinkType: DeeplinkType?
get() = when {
data?.scheme == "package" || data?.scheme == "fdroid.app" -> {
val packageName = data?.schemeSpecificPart?.nullIfEmpty()
?: throw InvalidDeeplink("Invalid packageName: $data")
DeeplinkType.AppDetail(packageName)
}
data?.scheme in fdroidRepoScheme -> {
val repoAddress =
if (data?.scheme.equals("fdroidrepos")) {
dataString!!.replaceFirst("fdroidrepos", "https")
} else if (data?.scheme.equals("fdroidrepo")) {
dataString!!.replaceFirst("fdroidrepo", "https")
} else {
throw InvalidDeeplink("No repo address: $data")
}
DeeplinkType.AddRepository(repoAddress)
}
data?.scheme == "market" && data?.host == "details" -> {
val packageName =
data["id"]?.nullIfEmpty() ?: throw InvalidDeeplink("Invalid packageName: $data")
DeeplinkType.AppDetail(packageName)
}
data != null && data?.scheme in httpScheme -> {
when (data?.host) {
PERSONAL_HOST -> {
val repoAddress = data["repo_address"]
if (data?.path == "/app/") {
val packageName =
data["id"] ?: throw InvalidDeeplink("Invalid packageName: $data")
DeeplinkType.AppDetail(packageName, repoAddress)
} else {
throw InvalidDeeplink("Unknown intent path: ${data?.path}, Data: $data")
}
}
in supportedExternalHosts -> {
val packageName = data?.lastPathSegment?.nullIfEmpty()
?: throw InvalidDeeplink("Invalid packageName: $data")
DeeplinkType.AppDetail(packageName)
}
else -> null
}
}
else -> null
}
val Intent.getInstallPackageName: String?
get() = if (data?.scheme == "package") data?.schemeSpecificPart?.nullIfEmpty() else null
class InvalidDeeplink(override val message: String?) : IllegalStateException(message)
sealed interface DeeplinkType {
data class AddRepository(val address: String) : DeeplinkType
data class AppDetail(val packageName: String, val repoAddress: String? = null) : DeeplinkType
}

View File

@@ -1,11 +0,0 @@
package com.looker.core.common
import android.net.Uri
interface Exporter<T> {
suspend fun export(item: T, target: Uri)
suspend fun import(target: Uri): T
}

View File

@@ -1,27 +0,0 @@
package com.looker.core.common
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import com.looker.core.common.extension.notificationManager
fun Context.createNotificationChannel(
id: String,
name: String,
description: String? = null,
showBadge: Boolean = false,
) {
sdkAbove(Build.VERSION_CODES.O) {
val channel = NotificationChannel(
id,
name,
NotificationManager.IMPORTANCE_LOW
).apply {
setDescription(description)
setShowBadge(showBadge)
setSound(null, null)
}
notificationManager?.createNotificationChannel(channel)
}
}

View File

@@ -1,52 +0,0 @@
package com.looker.core.common
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.provider.Settings
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.looker.core.common.extension.intent
import com.looker.core.common.extension.powerManager
fun Context.isIgnoreBatteryEnabled() =
powerManager?.isIgnoringBatteryOptimizations(packageName) == true
fun Context.requestBatteryFreedom() {
if (!isIgnoreBatteryEnabled()) {
val intent = intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) {
data = "package:$packageName".toUri()
}
runCatching {
startActivity(intent)
}
}
}
fun Activity.requestNotificationPermission(
request: (permission: String) -> Unit,
onGranted: () -> Unit = {}
) {
when {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED -> {
onGranted()
}
shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
sdkAbove(Build.VERSION_CODES.TIRAMISU) {
request(Manifest.permission.POST_NOTIFICATIONS)
}
}
else -> {
sdkAbove(Build.VERSION_CODES.TIRAMISU) {
request(Manifest.permission.POST_NOTIFICATIONS)
}
}
}
}

View File

@@ -1,54 +0,0 @@
package com.looker.core.common
import android.content.Context
import android.util.DisplayMetrics
import android.view.View
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs
/**
* A custom LinearSmoothScroller that increases the scrolling speed quadratically
* based on the distance already scrolled.
*
* @param context The context used to access resources.
*/
class Scroller(context: Context) : LinearSmoothScroller(context) {
private var distanceScrolled = 0
/**
* Calculates the speed per pixel based on the display metrics and the distance
* already scrolled. The speed increases quadratically over time.
*
* @param displayMetrics The display metrics used to calculate the speed.
* @return The speed per pixel.
*/
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
return (10f / displayMetrics.densityDpi) / (1 + 0.001f * distanceScrolled * distanceScrolled)
}
/**
* Called when the target view is found. Resets the distance scrolled.
*
* @param targetView The target view.
* @param state The current state of RecyclerView.
* @param action The action to be performed.
*/
override fun onTargetFound(targetView: View, state: RecyclerView.State, action: Action) {
super.onTargetFound(targetView, state, action)
distanceScrolled = 0
}
/**
* Called when seeking the target step. Accumulates the distance scrolled.
*
* @param dx The amount of horizontal scroll.
* @param dy The amount of vertical scroll.
* @param state The current state of RecyclerView.
* @param action The action to be performed.
*/
override fun onSeekTargetStep(dx: Int, dy: Int, state: RecyclerView.State, action: Action) {
super.onSeekTargetStep(dx, dy, state, action)
distanceScrolled += abs(dy)
}
}

View File

@@ -1,36 +0,0 @@
package com.looker.core.common
import android.os.Build
import androidx.annotation.ChecksSdkIntAtLeast
@ChecksSdkIntAtLeast(parameter = 0, lambda = 1)
inline fun sdkAbove(sdk: Int, onSuccessful: () -> Unit) {
if (Build.VERSION.SDK_INT >= sdk) onSuccessful()
}
object SdkCheck {
val sdk: Int
get() = Build.VERSION.SDK_INT
// Allows auto install if target sdk of apk is one less then current sdk
fun canAutoInstall(targetSdk: Int) = targetSdk >= sdk - 1 && isSnowCake
@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
val isTiramisu: Boolean = sdk >= Build.VERSION_CODES.TIRAMISU
@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R)
val isR: Boolean = sdk >= Build.VERSION_CODES.R
@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
val isPie: Boolean = sdk >= Build.VERSION_CODES.P
@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O)
val isOreo: Boolean = sdk >= Build.VERSION_CODES.O
@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
val isSnowCake: Boolean = sdk >= Build.VERSION_CODES.S
@get:ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N)
val isNougat: Boolean = sdk >= Build.VERSION_CODES.N
}

View File

@@ -1,13 +0,0 @@
package com.looker.core.common
class Singleton<T> {
private var value: T? = null
/**
* Updates the [value] if its null else it is returned
*/
fun getOrUpdate(block: () -> T): T = value ?: kotlin.run {
value = block()
value!!
}
}

View File

@@ -1,53 +0,0 @@
package com.looker.core.common
import android.util.Log
import java.util.Locale
fun <T : CharSequence> T.nullIfEmpty(): T? {
return if (isNullOrBlank()) null else this
}
/**
* Removes the string between the first [prefix] and last [suffix]
*
* For example: if "xyz_abc_123" is passed with [prefix] = "_"
*
* @return: "xyz_123"
*/
fun String.stripBetween(prefix: String, suffix: String = prefix): String {
val prefixIndex = indexOf(prefix)
val suffixIndex = lastIndexOf(suffix)
val isRangeValid = prefixIndex != -1 &&
suffixIndex != -1 &&
prefixIndex != suffixIndex
return if (isRangeValid) {
substring(0, prefixIndex + 1) + substring(suffixIndex + 1)
} else {
this
}
}
private val sizeFormats = listOf("%.0f B", "%.0f kB", "%.1f MB", "%.2f GB")
fun Long.formatSize(): String {
val (size, index) = generateSequence(Pair(this.toFloat(), 0)) { (size, index) ->
if (size >= 1024f) {
Pair(size / 1024f, index + 1)
} else {
null
}
}.take(sizeFormats.size).last()
return sizeFormats[index].format(Locale.US, size)
}
fun ByteArray.hex(): String = joinToString(separator = "") { byte ->
"%02x".format(Locale.US, byte.toInt() and 0xff)
}
fun Any.log(
message: Any?,
tag: String = this::class.java.simpleName + ".DEBUG",
type: Int = Log.DEBUG
) {
Log.println(type, tag, message.toString())
}

View File

@@ -1,257 +0,0 @@
package com.looker.core.common.cache
import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
import android.content.pm.PackageManager
import android.database.Cursor
import android.database.MatrixCursor
import android.net.Uri
import android.os.Build
import android.os.ParcelFileDescriptor
import android.os.storage.StorageManager
import android.provider.OpenableColumns
import android.system.Os
import com.looker.core.common.SdkCheck
import com.looker.core.common.sdkAbove
import java.io.File
import java.util.UUID
import kotlin.concurrent.thread
import kotlin.math.min
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.hours
object Cache {
private const val RELEASE_DIR = "releases"
private const val PARTIAL_DIR = "partial"
private const val IMAGES_DIR = "images"
private const val INDEX_DIR = "index"
private const val TEMP_DIR = "temporary"
private fun ensureCacheDir(context: Context, name: String): File {
return File(
context.cacheDir,
name
).apply { isDirectory || mkdirs() || throw RuntimeException() }
}
private fun applyOrMode(file: File, mode: Int) {
val oldMode = Os.stat(file.path).st_mode and 0b111111111111
val newMode = oldMode or mode
if (newMode != oldMode) {
Os.chmod(file.path, newMode)
}
}
private fun subPath(dir: File, file: File): String {
val dirPath = "${dir.path}/"
val filePath = file.path
filePath.startsWith(dirPath) || throw RuntimeException()
return filePath.substring(dirPath.length)
}
fun getEmptySpace(context: Context): Long {
val dir = context.cacheDir
return min(dir.usableSpace, dir.freeSpace)
}
fun getImagesDir(context: Context): File {
return ensureCacheDir(context, IMAGES_DIR)
}
fun getIndexFile(context: Context, indexName: String): File {
return File(ensureCacheDir(context, INDEX_DIR), indexName)
}
fun getPartialReleaseFile(context: Context, cacheFileName: String): File {
return File(ensureCacheDir(context, PARTIAL_DIR), cacheFileName)
}
fun getReleaseFile(context: Context, cacheFileName: String): File {
return File(ensureCacheDir(context, RELEASE_DIR), cacheFileName).apply {
sdkAbove(Build.VERSION_CODES.N) {
// Make readable for package installer
val cacheDir = context.cacheDir.parentFile!!.parentFile!!
generateSequence(this) { it.parentFile!! }.takeWhile { it != cacheDir }.forEach {
when {
it.isDirectory -> applyOrMode(it, 0b001001001)
it.isFile -> applyOrMode(it, 0b100100100)
}
}
}
}
}
fun getReleaseUri(context: Context, cacheFileName: String): Uri {
val file = getReleaseFile(context, cacheFileName)
val packageInfo =
try {
if (SdkCheck.isTiramisu) {
context.packageManager.getPackageInfo(
context.packageName,
PackageManager.PackageInfoFlags.of(PackageManager.GET_PROVIDERS.toLong())
)
} else {
@Suppress("DEPRECATION")
context.packageManager.getPackageInfo(
context.packageName,
PackageManager.GET_PROVIDERS
)
}
} catch (e: Exception) {
null
}
val authority =
packageInfo?.providers?.find { it.name == Provider::class.java.name }!!.authority
return Uri.Builder()
.scheme("content")
.authority(authority)
.encodedPath(file.path.drop(context.cacheDir.path.length))
.build()
}
fun getTemporaryFile(context: Context): File {
return File(ensureCacheDir(context, TEMP_DIR), UUID.randomUUID().toString())
}
fun cleanup(context: Context) {
thread {
cleanup(
context,
Pair(IMAGES_DIR, 7.days),
Pair(INDEX_DIR, Duration.INFINITE),
Pair(PARTIAL_DIR, 1.days),
Pair(RELEASE_DIR, 1.days),
Pair(TEMP_DIR, 1.hours),
)
}
}
private fun cleanup(context: Context, vararg dirHours: Pair<String, Duration>) {
val knownNames = dirHours.asSequence().map { it.first }.toSet()
val files = context.cacheDir.listFiles().orEmpty()
files.asSequence().filter { it.name !in knownNames }.forEach {
if (it.isDirectory) {
cleanupDir(it, Duration.ZERO)
it.delete()
} else {
it.delete()
}
}
dirHours.forEach { (name, duration) ->
val file = File(context.cacheDir, name)
if (file.exists()) {
if (file.isDirectory) {
cleanupDir(file, duration)
} else {
file.delete()
}
}
}
}
private fun cleanupDir(dir: File, duration: Duration) {
dir.listFiles()?.forEach {
val older = duration <= Duration.ZERO || run {
val olderThan = System.currentTimeMillis() / 1000L - duration.inWholeSeconds
try {
val stat = Os.lstat(it.path)
stat.st_atime < olderThan
} catch (e: Exception) {
false
}
}
if (older) {
if (it.isDirectory) {
cleanupDir(it, duration)
if (it.isDirectory) {
it.delete()
}
} else {
it.delete()
}
}
}
}
class Provider : ContentProvider() {
companion object {
private val defaultColumns = arrayOf(OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE)
}
private fun getFileAndTypeForUri(uri: Uri): Pair<File, String> {
return when (uri.pathSegments?.firstOrNull()) {
RELEASE_DIR -> Pair(
File(context!!.cacheDir, uri.encodedPath!!),
"application/vnd.android.package-archive"
)
else -> throw SecurityException()
}
}
override fun onCreate(): Boolean = true
override fun query(
uri: Uri,
projection: Array<String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor {
val file = getFileAndTypeForUri(uri).first
val columns = (projection ?: defaultColumns).mapNotNull {
when (it) {
OpenableColumns.DISPLAY_NAME -> Pair(it, file.name)
OpenableColumns.SIZE -> Pair(it, file.length())
else -> null
}
}.unzip()
return MatrixCursor(columns.first.toTypedArray()).apply {
addRow(
columns.second.toTypedArray()
)
}
}
override fun getType(uri: Uri): String = getFileAndTypeForUri(uri).second
private val unsupported: Nothing
get() = throw UnsupportedOperationException()
override fun insert(uri: Uri, contentValues: ContentValues?): Uri = unsupported
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int =
unsupported
override fun update(
uri: Uri,
contentValues: ContentValues?,
selection: String?,
selectionArgs: Array<out String>?
): Int = unsupported
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
val openMode = when (mode) {
"r" -> ParcelFileDescriptor.MODE_READ_ONLY
"w", "wt" ->
ParcelFileDescriptor.MODE_WRITE_ONLY or ParcelFileDescriptor.MODE_CREATE or
ParcelFileDescriptor.MODE_TRUNCATE
"wa" ->
ParcelFileDescriptor.MODE_WRITE_ONLY or ParcelFileDescriptor.MODE_CREATE or
ParcelFileDescriptor.MODE_APPEND
"rw" -> ParcelFileDescriptor.MODE_READ_WRITE or ParcelFileDescriptor.MODE_CREATE
"rwt" ->
ParcelFileDescriptor.MODE_READ_WRITE or ParcelFileDescriptor.MODE_CREATE or
ParcelFileDescriptor.MODE_TRUNCATE
else -> throw IllegalArgumentException()
}
val file = getFileAndTypeForUri(uri).first
return ParcelFileDescriptor.open(file, openMode)
}
}
}

View File

@@ -1,13 +0,0 @@
package com.looker.core.common.device
object Huawei {
val isHuaweiEmui: Boolean
get() {
return try {
Class.forName("com.huawei.android.os.BuildEx")
true
} catch (e: Exception) {
false
}
}
}

View File

@@ -1,38 +0,0 @@
package com.looker.core.common.device
import android.annotation.SuppressLint
import android.util.Log
object Miui {
val isMiui by lazy {
getSystemProperty("ro.miui.ui.version.name")?.isNotEmpty() ?: false
}
@SuppressLint("PrivateApi")
fun isMiuiOptimizationDisabled(): Boolean {
val sysProp = getSystemProperty("persist.sys.miui_optimization")
if (sysProp == "0" || sysProp == "false") {
return true
}
return try {
Class.forName("android.miui.AppOpsUtils")
.getDeclaredMethod("isXOptMode")
.invoke(null) as Boolean
} catch (e: Exception) {
false
}
}
@SuppressLint("PrivateApi")
private fun getSystemProperty(key: String?): String? {
return try {
Class.forName("android.os.SystemProperties")
.getDeclaredMethod("get", String::class.java)
.invoke(null, key) as String
} catch (e: Exception) {
Log.e("Miui", "Unable to use SystemProperties.get()", e)
null
}
}
}

View File

@@ -1,16 +0,0 @@
package com.looker.core.common.extension
inline fun <K, E> Map<K, E>.updateAsMutable(block: MutableMap<K, E>.() -> Unit): Map<K, E> {
return toMutableMap().apply(block)
}
inline fun <T> Set<T>.updateAsMutable(block: MutableSet<T>.() -> Unit): Set<T> {
return toMutableSet().apply(block)
}
inline fun <T> MutableSet<T>.addAndCompute(item: T, block: (isAdded: Boolean) -> Unit): Boolean =
add(item).apply { block(this) }
inline fun <T> List<T>.updateAsMutable(block: MutableList<T>.() -> Unit): List<T> {
return toMutableList().apply(block)
}

View File

@@ -1,88 +0,0 @@
package com.looker.core.common.extension
import android.app.NotificationManager
import android.app.job.JobScheduler
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.res.ColorStateList
import android.graphics.drawable.Drawable
import android.net.ConnectivityManager
import android.os.PowerManager
import android.view.inputmethod.InputMethodManager
import androidx.annotation.AttrRes
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import com.looker.core.common.R
inline val Context.clipboardManager: ClipboardManager?
get() = getSystemService()
inline val Context.connectivityManager: ConnectivityManager?
get() = getSystemService()
inline val Context.inputManager: InputMethodManager?
get() = getSystemService()
inline val Context.jobScheduler: JobScheduler?
get() = getSystemService()
inline val Context.notificationManager: NotificationManager?
get() = getSystemService()
inline val Context.powerManager: PowerManager?
get() = getSystemService()
fun Context.copyToClipboard(clip: String) {
clipboardManager?.setPrimaryClip(ClipData.newPlainText(null, clip))
}
val Context.corneredBackground: Drawable
get() = getDrawableCompat(R.drawable.background_border)
val Context.divider: Drawable
get() = getDrawableFromAttr(android.R.attr.listDivider)
val Context.homeAsUp: Drawable
get() = getDrawableFromAttr(android.R.attr.homeAsUpIndicator)
val Context.open: Drawable
get() = getDrawableCompat(R.drawable.ic_launch)
val Context.selectableBackground: Drawable
get() = getDrawableFromAttr(android.R.attr.selectableItemBackground)
val Context.camera: Drawable
get() = getDrawableCompat(R.drawable.ic_image)
val Context.aspectRatio: Float
get() = with(resources.displayMetrics) {
(heightPixels / widthPixels).toFloat()
}
fun Context.getMutatedIcon(@DrawableRes id: Int): Drawable = getDrawableCompat(id).mutate()
private fun Context.getDrawableFromAttr(attrResId: Int): Drawable {
val typedArray = obtainStyledAttributes(intArrayOf(attrResId))
val resId = try {
typedArray.getResourceId(0, 0)
} finally {
typedArray.recycle()
}
return getDrawableCompat(resId)
}
fun Context.getDrawableCompat(@DrawableRes resId: Int = R.drawable.background_border): Drawable =
requireNotNull(AppCompatResources.getDrawable(this, resId)) { "Cannot find drawable, ID: $resId" }
fun Context.getColorFromAttr(@AttrRes attrResId: Int): ColorStateList {
val typedArray = obtainStyledAttributes(intArrayOf(attrResId))
val (colorStateList, resId) = try {
Pair(typedArray.getColorStateList(0), typedArray.getResourceId(0, 0))
} finally {
typedArray.recycle()
}
return colorStateList ?: ContextCompat.getColorStateList(this, resId)!!
}

View File

@@ -1,11 +0,0 @@
package com.looker.core.common.extension
import android.database.Cursor
fun Cursor.asSequence(): Sequence<Cursor> {
return generateSequence { if (moveToNext()) this else null }
}
fun Cursor.firstOrNull(): Cursor? {
return if (moveToFirst()) this else null
}

View File

@@ -1,18 +0,0 @@
package com.looker.core.common.extension
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
private object DateTime {
val HTTP_DATE_FORMAT: SimpleDateFormat
get() = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US).apply {
timeZone = TimeZone.getTimeZone("GMT")
}
}
fun Date.toFormattedString(): String = DateTime.HTTP_DATE_FORMAT.format(this)
fun String.toDate(): Date = DateTime.HTTP_DATE_FORMAT.parse(this)
?: throw IllegalStateException("Wrong Date Format")

View File

@@ -1,8 +0,0 @@
package com.looker.core.common.extension
import kotlinx.coroutines.CancellationException
inline fun Exception.exceptCancellation() {
printStackTrace()
if (this is CancellationException) throw this
}

View File

@@ -1,7 +0,0 @@
package com.looker.core.common.extension
import java.io.File
val File.size: Long?
get() = if (exists()) length().takeIf { it > 0L } else null

View File

@@ -1,21 +0,0 @@
package com.looker.core.common.extension
import com.looker.core.common.hex
import java.security.MessageDigest
import java.security.cert.Certificate
fun Certificate.fingerprint(): String {
return runCatching { encoded.fingerprint() }.getOrElse { "" }
}
fun ByteArray.fingerprint(): String = if (size >= 256) {
try {
val fingerprint = MessageDigest.getInstance("sha256").digest(this)
fingerprint.hex()
} catch (e: Exception) {
e.printStackTrace()
""
}
} else {
""
}

View File

@@ -1,29 +0,0 @@
package com.looker.core.common.extension
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.flow.*
context(ViewModel)
fun <T> Flow<T>.asStateFlow(
initialValue: T,
scope: CoroutineScope = viewModelScope,
started: SharingStarted = SharingStarted.WhileSubscribed(5_000)
): StateFlow<T> = stateIn(
scope = scope,
started = started,
initialValue = initialValue
)
context(CoroutineScope)
@OptIn(ExperimentalCoroutinesApi::class)
fun <T> ReceiveChannel<T>.filter(
block: suspend (T) -> Boolean
): ReceiveChannel<T> = produce(capacity = Channel.UNLIMITED) {
consumeEach { item ->
if (block(item)) send(item)
}
}

View File

@@ -1,83 +0,0 @@
package com.looker.core.common.extension
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.marginLeft
import androidx.core.view.marginTop
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.RecyclerView
import com.looker.core.common.SdkCheck
import com.looker.core.common.extension.InsetSides.BOTTOM
import com.looker.core.common.extension.InsetSides.LEFT
import com.looker.core.common.extension.InsetSides.RIGHT
import com.looker.core.common.extension.InsetSides.TOP
fun View.systemBarsMargin(
persistentPadding: Int,
allowedSides: List<InsetSides> = listOf(LEFT, RIGHT, BOTTOM)
) {
if (SdkCheck.isR) {
ViewCompat.setOnApplyWindowInsetsListener(this) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updateLayoutParams<ViewGroup.MarginLayoutParams> {
if (TOP in allowedSides) topMargin = insets.top + marginTop
if (LEFT in allowedSides) leftMargin = insets.left + marginLeft
if (BOTTOM in allowedSides) bottomMargin = insets.bottom + persistentPadding
if (RIGHT in allowedSides) rightMargin = insets.right + persistentPadding
}
WindowInsetsCompat.CONSUMED
}
}
}
fun RecyclerView.systemBarsPadding(
allowedSides: List<InsetSides> = listOf(LEFT, RIGHT, BOTTOM),
includeFab: Boolean = true
) {
if (SdkCheck.isR) {
ViewCompat.setOnApplyWindowInsetsListener(this) { view, windowInsets ->
clipToPadding = false
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(
if (LEFT in allowedSides) insets.left else 0,
if (TOP in allowedSides) insets.top else 0,
if (RIGHT in allowedSides) insets.right else 0,
if (BOTTOM in allowedSides) {
insets.bottom + if (includeFab) 88.dp else 0
} else {
0
}
)
WindowInsetsCompat.CONSUMED
}
}
}
fun NestedScrollView.systemBarsPadding(
allowedSides: List<InsetSides> = listOf(LEFT, RIGHT, BOTTOM)
) {
if (SdkCheck.isR) {
ViewCompat.setOnApplyWindowInsetsListener(this) { view, windowInsets ->
clipToPadding = false
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(
if (LEFT in allowedSides) insets.left else 0,
if (TOP in allowedSides) insets.top else 0,
if (RIGHT in allowedSides) insets.right else 0,
if (BOTTOM in allowedSides) insets.bottom else 0
)
WindowInsetsCompat.CONSUMED
}
}
}
enum class InsetSides {
LEFT,
RIGHT,
TOP,
BOTTOM
}

View File

@@ -1,27 +0,0 @@
package com.looker.core.common.extension
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.core.app.TaskStackBuilder
import com.looker.core.common.SdkCheck
fun intent(action: String, block: Intent.() -> Unit = {}): Intent {
return Intent(action).apply(block)
}
inline val intentFlagCompat
get() = if (SdkCheck.isSnowCake) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
fun Intent.toPendingIntent(context: Context): PendingIntent? =
TaskStackBuilder
.create(context)
.addNextIntentWithParentStack(this)
.getPendingIntent(0, intentFlagCompat)
operator fun Uri?.get(key: String): String? = this?.getQueryParameter(key)

View File

@@ -1,108 +0,0 @@
package com.looker.core.common.extension
import com.fasterxml.jackson.core.JsonFactory
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.JsonToken
object Json {
val factory = JsonFactory()
}
interface KeyToken {
val key: String
val token: JsonToken
fun number(key: String): Boolean = this.key == key && this.token.isNumeric
fun string(key: String): Boolean = this.key == key && this.token == JsonToken.VALUE_STRING
fun boolean(key: String): Boolean = this.key == key && this.token.isBoolean
fun dictionary(key: String): Boolean = this.key == key && this.token == JsonToken.START_OBJECT
fun array(key: String): Boolean = this.key == key && this.token == JsonToken.START_ARRAY
}
fun JsonParser.illegal(): Nothing {
throw JsonParseException(this, "Illegal state")
}
fun JsonParser.forEachKey(callback: JsonParser.(KeyToken) -> Unit) {
var passKey = ""
var passToken = JsonToken.NOT_AVAILABLE
val keyToken = object : KeyToken {
override val key: String
get() = passKey
override val token: JsonToken
get() = passToken
}
while (true) {
val token = nextToken()
if (token == JsonToken.FIELD_NAME) {
passKey = currentName
passToken = nextToken()
callback(keyToken)
} else if (token == JsonToken.END_OBJECT) {
break
} else {
illegal()
}
}
}
fun JsonParser.forEach(requiredToken: JsonToken, callback: JsonParser.() -> Unit) {
while (true) {
val token = nextToken()
if (token == JsonToken.END_ARRAY) {
break
} else if (token == requiredToken) {
callback()
} else if (token.isStructStart) {
skipChildren()
}
}
}
fun <T> JsonParser.collectNotNull(
requiredToken: JsonToken,
callback: JsonParser.() -> T?
): List<T> {
val list = mutableListOf<T>()
forEach(requiredToken) {
val result = callback()
if (result != null) {
list += result
}
}
return list
}
fun JsonParser.collectNotNullStrings(): List<String> {
return collectNotNull(JsonToken.VALUE_STRING) { valueAsString }
}
fun JsonParser.collectDistinctNotEmptyStrings(): List<String> {
return collectNotNullStrings().asSequence().filter { it.isNotEmpty() }.distinct().toList()
}
fun <T> JsonParser.parseDictionary(callback: JsonParser.() -> T): T {
if (nextToken() == JsonToken.START_OBJECT) {
val result = callback()
if (nextToken() != null) {
illegal()
}
return result
} else {
illegal()
}
}
inline fun JsonGenerator.writeDictionary(callback: JsonGenerator.() -> Unit) {
writeStartObject()
callback()
writeEndObject()
}
inline fun JsonGenerator.writeArray(fieldName: String, callback: JsonGenerator.() -> Unit) {
writeArrayFieldStart(fieldName)
callback()
writeEndArray()
}

View File

@@ -1,17 +0,0 @@
package com.looker.core.common.extension
import java.util.Locale
fun String.toLocale(): Locale = when {
contains("-r") -> Locale(
substring(0, 2),
substring(4)
)
contains("_") -> Locale(
substring(0, 2),
substring(3)
)
else -> Locale(this)
}

View File

@@ -1,6 +0,0 @@
package com.looker.core.common.extension
import androidx.core.net.toUri
val String.isOnion: Boolean
get() = toUri().host?.endsWith(".onion") == true

View File

@@ -1,22 +0,0 @@
package com.looker.core.common.extension
import android.content.res.Resources
import android.util.TypedValue
import android.view.View
import kotlin.math.roundToInt
infix fun Long.percentBy(denominator: Long?): Int {
if (denominator == null || denominator < 1) return -1
return (this * 100 / denominator).toInt()
}
val Number.dpToPx
get() = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
Resources.getSystem().displayMetrics
)
context(View)
val Int.dp: Int
get() = (this * resources.displayMetrics.density).roundToInt()

View File

@@ -1,152 +0,0 @@
package com.looker.core.common.extension
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.Signature
import com.looker.core.common.SdkCheck
import com.looker.core.common.hex
import java.security.MessageDigest
val PackageInfo.singleSignature: Signature?
get() = if (SdkCheck.isPie) {
val signingInfo = signingInfo
if (signingInfo?.hasMultipleSigners() == false) {
signingInfo.apkContentsSigners
?.let { if (it.size == 1) it[0] else null }
} else {
null
}
} else {
@Suppress("DEPRECATION")
signatures?.let { if (it.size == 1) it[0] else null }
}
fun Signature.calculateHash() = MessageDigest.getInstance("MD5")
.digest(toCharsString().toByteArray())
.hex()
@Suppress("DEPRECATION")
val PackageInfo.versionCodeCompat: Long
get() = if (SdkCheck.isPie) longVersionCode else versionCode.toLong()
fun PackageManager.isSystemApplication(packageName: String): Boolean = try {
(
(
this.getApplicationInfoCompat(packageName)
.flags
) and ApplicationInfo.FLAG_SYSTEM
) != 0
} catch (e: Exception) {
false
}
fun PackageManager.getLauncherActivities(packageName: String): List<Pair<String, String>> {
return queryIntentActivities(
Intent(Intent.ACTION_MAIN).addCategory(
Intent.CATEGORY_LAUNCHER
),
0
)
.asSequence()
.mapNotNull { resolveInfo -> resolveInfo.activityInfo }
.filter { activityInfo -> activityInfo.packageName == packageName }
.mapNotNull { activityInfo ->
val label = try {
activityInfo.loadLabel(this).toString()
} catch (e: Exception) {
e.printStackTrace()
null
}
label?.let { labelName ->
activityInfo.name to labelName
}
}
.toList()
}
fun PackageManager.getApplicationInfoCompat(
filePath: String
): ApplicationInfo = if (SdkCheck.isTiramisu) {
getApplicationInfo(
filePath,
PackageManager.ApplicationInfoFlags.of(0L)
)
} else {
@Suppress("DEPRECATION")
getApplicationInfo(filePath, 0)
}
@Suppress("DEPRECATION")
private val signaturesFlagCompat: Int
get() = (
if (SdkCheck.isPie) {
PackageManager.GET_SIGNING_CERTIFICATES
} else {
0
}
) or PackageManager.GET_SIGNATURES
fun PackageManager.getPackageInfoCompat(
packageName: String,
signatureFlag: Int = signaturesFlagCompat
): PackageInfo? = try {
if (SdkCheck.isTiramisu) {
getPackageInfo(
packageName,
PackageManager.PackageInfoFlags.of(signatureFlag.toLong())
)
} else {
@Suppress("DEPRECATION")
getPackageInfo(packageName, signatureFlag)
}
} catch (e: Exception) {
null
}
fun PackageManager.getPackageName(
packageName: String?,
): CharSequence? {
if (packageName == null) return null
return try {
getApplicationLabel(
getApplicationInfo(
packageName,
PackageManager.GET_META_DATA
)
)
} catch (e: PackageManager.NameNotFoundException) {
null
}
}
fun PackageManager.getPackageArchiveInfoCompat(
filePath: String,
signatureFlag: Int = signaturesFlagCompat
): PackageInfo? = try {
if (SdkCheck.isTiramisu) {
getPackageArchiveInfo(
filePath,
PackageManager.PackageInfoFlags.of(signatureFlag.toLong())
)
} else {
@Suppress("DEPRECATION")
getPackageArchiveInfo(filePath, signatureFlag)
}
} catch (e: Exception) {
null
}
fun PackageManager.getInstalledPackagesCompat(
signatureFlag: Int = signaturesFlagCompat
): List<PackageInfo>? = try {
if (SdkCheck.isTiramisu) {
getInstalledPackages(PackageManager.PackageInfoFlags.of(signatureFlag.toLong()))
} else {
@Suppress("DEPRECATION")
getInstalledPackages(signatureFlag)
}
} catch (e: Exception) {
null
}

View File

@@ -1,7 +0,0 @@
package com.looker.core.common.extension
import android.database.sqlite.SQLiteDatabase
fun SQLiteDatabase.execWithResult(sql: String) {
rawQuery(sql, null).use { it.count }
}

View File

@@ -1,30 +0,0 @@
package com.looker.core.common.extension
import android.app.Service
import android.content.Intent
import com.looker.core.common.SdkCheck
fun Service.startSelf() {
val intent = Intent(this, this::class.java)
if (SdkCheck.isOreo) {
startForegroundService(intent)
} else {
startService(intent)
}
}
fun Service.stopForegroundCompat(removeNotification: Boolean = true) {
@Suppress("DEPRECATION")
if (SdkCheck.isNougat) {
stopForeground(
if (removeNotification) {
Service.STOP_FOREGROUND_REMOVE
} else {
Service.STOP_FOREGROUND_DETACH
}
)
} else {
stopForeground(removeNotification)
}
stopSelf()
}

View File

@@ -1,54 +0,0 @@
package com.looker.core.common.extension
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil.request.ImageRequest
import kotlin.math.min
import kotlin.math.roundToInt
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.*
fun ImageRequest.Builder.authentication(base64: String) {
addHeader("Authorization", base64)
}
fun TextView.setTextSizeScaled(size: Int) {
val realSize = (size * resources.displayMetrics.scaledDensity).roundToInt()
setTextSize(TypedValue.COMPLEX_UNIT_PX, realSize.toFloat())
}
fun ViewGroup.inflate(layoutResId: Int): View {
return LayoutInflater.from(context).inflate(layoutResId, this, false)
}
val RecyclerView.firstItemPosition: Flow<Int>
get() = callbackFlow {
val listener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val position = (recyclerView.layoutManager as LinearLayoutManager)
.findFirstVisibleItemPosition()
trySend(position)
}
}
addOnScrollListener(listener)
awaitClose { removeOnScrollListener(listener) }
}.distinctUntilChanged().conflate()
val RecyclerView.isFirstItemVisible: Flow<Boolean>
get() = firstItemPosition.map { it == 0 }.distinctUntilChanged()
val View.minDimension: Int
get() = (
min(
layoutParams.width,
layoutParams.height
) / resources.displayMetrics.density
).roundToInt()
val View.dpi: Int
get() = (context.resources.displayMetrics.densityDpi * minDimension) / 48

View File

@@ -1,10 +0,0 @@
package com.looker.core.common.result
sealed interface Result<out T> {
data class Success<T>(val data: T) : Result<T>
data class Error<T>(
val exception: Throwable? = null,
val data: T? = null
) : Result<T>
}

View File

@@ -1,70 +0,0 @@
package com.looker.core.common.signature
import com.looker.core.common.extension.exceptCancellation
import com.looker.core.common.hex
import java.io.File
import java.security.MessageDigest
import kotlinx.coroutines.*
suspend fun File.verifyHash(hash: Hash): Boolean {
return try {
if (!hash.isValid() || !exists()) return false
calculateHash(hash.type)
?.equals(hash.hash, true)
?: false
} catch (e: Exception) {
e.exceptCancellation()
false
}
}
suspend fun File.calculateHash(hashType: String): String? {
return try {
if (hashType.isBlank() || !exists()) return null
MessageDigest
.getInstance(hashType)
.readBytesFrom(this)
?.hex()
} catch (e: Exception) {
e.exceptCancellation()
null
}
}
private suspend fun MessageDigest.readBytesFrom(
file: File
): ByteArray? = withContext(Dispatchers.IO) {
try {
if (file.length() < DIRECT_READ_LIMIT) return@withContext digest(file.readBytes())
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
file.inputStream().use { input ->
var bytesRead = input.read(buffer)
while (bytesRead >= 0) {
ensureActive()
update(buffer, 0, bytesRead)
bytesRead = input.read(buffer)
}
digest()
}
} catch (e: Exception) {
e.exceptCancellation()
null
}
}
// 25 MB
private const val DIRECT_READ_LIMIT = 25 * 1024 * 1024
@Suppress("FunctionName")
data class Hash(
val type: String,
val hash: String
) {
companion object {
fun SHA256(hash: String) = Hash(type = "sha256", hash)
fun MD5(hash: String) = Hash(type = "md5", hash)
}
fun isValid(): Boolean = type.isNotBlank() && hash.isNotBlank()
}

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorError" android:state_checked="true" />
<item android:color="?attr/colorOutline" />
</selector>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorOnSurfaceInverse" android:state_enabled="false" />
<item android:color="?attr/colorPrimary" android:state_checked="true" />
<item android:color="?attr/colorOutline" />
</selector>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="@dimen/material_emphasis_disabled_background" android:color="?attr/colorOnSurface" android:state_enabled="false" />
<item android:color="?attr/colorPrimaryContainer" android:state_checked="true" />
<item android:color="?attr/colorSurfaceVariant" />
</selector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M440,313L244,509Q232,521 216,520.5Q200,520 188,508Q177,496 176.5,480Q176,464 188,452L452,188Q458,182 465,179.5Q472,177 480,177Q488,177 495,179.5Q502,182 508,188L772,452Q783,463 783,479.5Q783,496 772,508Q760,520 743.5,520Q727,520 715,508L520,313L520,760Q520,777 508.5,788.5Q497,800 480,800Q463,800 451.5,788.5Q440,777 440,760L440,313Z" />
</vector>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/shape_large_corner" />
</shape>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18,13h-5v5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-5H6c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h5V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v5h5c0.55,0 1,0.45 1,1s-0.45,1 -1,1z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M175.48,851.92Q147.1,851.92 127.19,832.01Q107.27,812.09 107.27,783.74L107.27,176.26Q107.27,147.91 127.19,127.99Q147.1,108.08 175.54,108.08L490.81,108.08L692.73,310L692.73,501.42L636.77,501.42L636.77,338.38L462.42,338.38L462.42,164.04L175.54,164.04Q170.92,164.04 167.08,167.89Q163.23,171.73 163.23,176.35L163.23,783.65Q163.23,788.27 167.08,792.11Q170.92,795.96 175.54,795.96L577.23,795.96L577.23,851.92L175.48,851.92ZM163.23,795.96L163.23,501.42L163.23,501.42L163.23,338.38L163.23,164.04L163.23,164.04Q163.23,164.04 163.23,167.89Q163.23,171.73 163.23,176.35L163.23,783.65Q163.23,788.27 163.23,792.11Q163.23,795.96 163.23,795.96L163.23,795.96ZM222.46,740.58Q226.08,697 249.02,660.69Q271.96,624.38 309.62,603L275.89,542.66Q275.89,542.54 279.25,528.87Q282.92,527 287.29,527.69Q291.65,528.39 293.65,532.31L327.94,593.77Q345.58,586.54 363.35,583.02Q381.13,579.5 399.88,579.5Q418.64,579.5 436.73,583.02Q454.81,586.54 472.12,593.77L506.54,532.31Q506.73,531.92 519.95,528.69Q523.73,530.63 524.92,534.9Q526.11,539.16 524.11,542.65L490.77,603Q528.42,624.38 551.21,660.68Q574,696.98 577.54,740.58L222.46,740.58ZM320.46,687.15Q327.69,687.15 332.77,681.84Q337.85,676.53 337.85,669.44Q337.85,662.35 332.71,657.08Q327.57,651.81 320.46,651.81Q313.23,651.81 307.81,657.11Q302.39,662.41 302.39,669.48Q302.39,676.55 307.81,681.85Q313.23,687.15 320.46,687.15ZM479.92,687.15Q487.15,687.15 492.58,681.85Q498,676.55 498,669.48Q498,662.41 492.58,657.11Q487.15,651.81 479.92,651.81Q472.69,651.81 467.52,657.11Q462.35,662.41 462.35,669.48Q462.35,676.55 467.62,681.85Q472.89,687.15 479.92,687.15ZM761.08,851.92L618.23,708.5L657.08,668.65L733.19,744.46L733.19,561L789.15,561L789.15,743.96L865.08,669.04L904.11,708.5L761.08,851.92Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M15.88,9.29L12,13.17 8.12,9.29c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.38 -1.03,-0.39 -1.42,0z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480.03,812.73Q422,812.73 372.87,783.98Q323.73,755.23 294.6,705.15L211.23,705.15Q199.77,705.15 191.96,696.9Q184.15,688.65 184.15,677.17Q184.15,665.7 192.37,657.45Q200.58,649.19 212.23,649.19L273.54,649.19Q267.46,624.27 266.56,598.64Q265.65,573.01 265.65,547.58L211.23,547.58Q199.77,547.58 191.96,539.32Q184.15,531.07 184.15,519.6Q184.15,508.12 192.37,499.87Q200.58,491.62 212.23,491.62L265.67,491.62Q265.67,465.42 266.02,439.67Q266.39,413.92 273.54,389.19L211.23,389.19Q199.77,389.19 191.96,380.94Q184.15,372.68 184.15,361.21Q184.15,349.74 192.37,341.48Q200.58,333.23 212.23,333.23L294.5,333.23Q308.84,308.69 328.9,288.75Q348.96,268.81 374.27,255.27L325,205.69Q317,197.58 317.35,186.5Q317.69,175.42 325.5,167.42Q333.31,159.31 344.58,159.31Q355.85,159.31 364.15,167.42L429,232.46Q453.83,224.62 479.79,224.62Q505.74,224.62 530.58,232.46L597.5,166.42Q605.63,158.62 616.54,159.12Q627.46,159.62 635.27,167.42Q643.08,175.73 643.08,187Q643.08,198.27 634.96,206.38L586.08,255.27Q611.38,268.81 631.23,288.6Q651.08,308.39 665.46,333.23L748.96,333.23Q760.23,333.23 768.04,341.48Q775.84,349.74 775.84,361.21Q775.84,372.68 767.63,380.94Q759.42,389.19 747.96,389.19L686.46,389.19Q693.31,413.92 693.83,439.67Q694.34,465.42 694.34,491.62L748.96,491.62Q760.23,491.62 768.04,499.87Q775.84,508.12 775.84,519.6Q775.84,531.07 767.63,539.32Q759.42,547.58 747.96,547.58L694.34,547.58Q694.34,573.08 693.44,598.67Q692.54,624.27 686.46,649.19L748.96,649.19Q760.23,649.19 768.04,657.45Q775.84,665.7 775.84,677.17Q775.84,688.65 767.63,696.9Q759.42,705.15 747.96,705.15L665.46,705.15Q636.27,755.23 587.16,783.98Q538.06,812.73 480.03,812.73ZM480.02,756.77Q545.69,756.77 592.04,710.38Q638.39,663.99 638.39,598.29L638.39,440.81Q638.39,375.11 592.02,328.77Q545.65,282.42 479.98,282.42Q414.31,282.42 367.96,328.81Q321.61,375.2 321.61,440.9L321.61,598.38Q321.61,664.08 367.98,710.42Q414.36,756.77 480.02,756.77ZM435.85,626.77L525.35,626.77Q536.61,626.77 544.42,618.75Q552.23,610.73 552.23,598.73Q552.23,587.23 544.01,579.02Q535.78,570.81 524.35,570.81L434.85,570.81Q423.39,570.81 415.58,578.87Q407.77,586.92 407.77,598.69Q407.77,610.35 415.98,618.56Q424.19,626.77 435.85,626.77ZM435.85,468.38L525.35,468.38Q536.61,468.38 544.42,460.36Q552.23,452.34 552.23,440.34Q552.23,428.85 544.01,420.64Q535.78,412.42 524.35,412.42L434.85,412.42Q423.39,412.42 415.58,420.48Q407.77,428.54 407.77,440.31Q407.77,451.96 415.98,460.17Q424.19,468.38 435.85,468.38ZM480,519.5Q480,519.5 480,519.5Q480,519.5 480,519.5L480,519.5Q480,519.5 480,519.5Q480,519.5 480,519.5Q480,519.5 480,519.5Q480,519.5 480,519.5L480,519.5Q480,519.5 480,519.5Q480,519.5 480,519.5Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z" />
</vector>

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#FFB4AB"
android:pathData="M0,0 108,0 108,108 L0,108 z" />
<path
android:fillColor="#690005"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorOnPrimaryContainer">
<path
android:fillColor="@android:color/white"
android:pathData="M9,16.2l-3.5,-3.5c-0.39,-0.39 -1.01,-0.39 -1.4,0 -0.39,0.39 -0.39,1.01 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7c0.39,-0.39 0.39,-1.01 0,-1.4 -0.39,-0.39 -1.01,-0.39 -1.4,0L9,16.2z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M180.38,480.61L341.87,642.1Q349.69,649.92 350.04,661.39Q350.38,672.85 341.88,681.44Q333.38,690.04 322.27,690.04Q311.15,690.04 302.65,681.35L124.81,503.69Q119.69,498.52 117.14,492.46Q114.58,486.41 114.58,479.6Q114.58,472.78 117.14,466.73Q119.69,460.68 124.81,455.5L301.8,278.51Q310.27,270.04 321.83,269.94Q333.38,269.85 342.19,278.46Q350.81,287.27 350.81,298.73Q350.81,310.19 342.19,318.81L180.38,480.61ZM779.62,479.39L618.13,317.9Q610.31,310.08 609.96,298.61Q609.62,287.15 618.12,278.56Q626.62,269.96 637.73,269.96Q648.85,269.96 657.54,278.46L835.18,456.29Q840.31,461.42 842.86,467.48Q845.42,473.55 845.42,480.37Q845.42,487.19 842.86,493.25Q840.31,499.32 835.19,504.5L658.35,681.35Q649.73,689.96 638.48,689.75Q627.23,689.54 618.62,680.73Q609.81,672.11 609.81,660.65Q609.81,649.19 618.63,640.37L779.62,479.39Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480.09,851.92Q402.94,851.92 335.03,822.6Q267.11,793.27 216.87,743Q166.64,692.73 137.36,624.95Q108.08,557.16 108.08,480.09Q108.08,402.94 137.4,335.03Q166.73,267.11 217,216.87Q267.27,166.64 335.05,137.36Q402.84,108.08 479.91,108.08Q557.06,108.08 624.97,137.4Q692.89,166.73 743.13,217Q793.36,267.27 822.64,335.05Q851.92,402.84 851.92,479.91Q851.92,557.06 822.6,624.97Q793.27,692.89 743,743.13Q692.73,793.36 624.95,822.64Q557.16,851.92 480.09,851.92ZM479.99,795.96Q611.89,795.96 703.92,703.94Q795.96,611.91 795.96,480.01Q795.96,348.11 703.94,256.08Q611.91,164.04 480.01,164.04Q348.11,164.04 256.08,256.06Q164.04,348.09 164.04,479.99Q164.04,611.89 256.06,703.92Q348.09,795.96 479.99,795.96ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM400.81,626.77L559.19,626.77Q571.19,626.77 578.98,618.63Q586.77,610.49 586.77,598.45L586.77,558.64Q586.77,547.25 578.53,539.03Q570.29,530.81 558.87,530.81Q547.23,530.81 539.02,539.04Q530.81,547.28 530.81,558.69L530.81,570.81L429.19,570.81L429.19,389.19L530.81,389.19L530.81,401.11Q530.81,412.75 539.03,420.97Q547.26,429.19 558.8,429.19Q570.35,429.19 578.56,420.97Q586.77,412.75 586.77,401.11L586.77,361.61Q586.77,349.55 578.98,341.39Q571.19,333.23 559.19,333.23L400.81,333.23Q388.81,333.23 381.02,341.39Q373.23,349.55 373.23,361.61L373.23,598.39Q373.23,610.45 381.02,618.61Q388.81,626.77 400.81,626.77Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M283,830Q252.06,830 230.03,807.97Q208,785.94 208,755L208,243L206.5,243Q191,243 180,232Q169,221 169,205.5Q169,190 180,179Q191,168 206.5,168L362,168L362,167.5Q362,152 373,141Q384,130 399.5,130L561.5,130Q577,130 588,141Q599,152 599,167.5L599,168L754.5,168Q770,168 781,179Q792,190 792,205.5Q792,221 781,232Q770,243 754.5,243L753,243L753,755Q753,785.94 730.97,807.97Q708.94,830 678,830L283,830ZM678,243L283,243L283,755Q283,755 283,755Q283,755 283,755L678,755Q678,755 678,755Q678,755 678,755L678,243ZM365,676.5L440,676.5L440,321.5L365,321.5L365,676.5ZM521,676.5L596,676.5L596,321.5L521,321.5L521,676.5ZM283,243L283,243L283,755Q283,755 283,755Q283,755 283,755L283,755Q283,755 283,755Q283,755 283,755L283,243Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M471.92,638.08L497.08,638.08L497.08,606.46Q525.08,602.54 544.58,583.93Q564.08,565.31 564.08,535.92Q564.08,510.45 544.08,493.3Q524.08,476.15 498.08,465.15L498.08,387.69Q508.85,390.31 516.31,397.5Q523.77,404.69 527.15,414.31L559.31,400.85Q551.92,381.39 535.28,369.38Q518.64,357.38 498.08,353.54L498.08,321.92L471.92,321.92L471.92,352.92Q443.92,355.84 424.42,372.84Q404.92,389.84 404.92,418Q404.92,444.23 425.42,462.08Q445.92,479.94 471.92,490.85L471.92,572.54Q454.39,568.31 442.81,556.5Q431.23,544.69 426.85,528.69L395.31,542.15Q403.31,568.81 423.31,585.94Q443.31,603.08 471.92,607.08L471.92,638.08ZM498.08,571.92L498.08,500.92Q510.59,506.63 520.26,514.62Q529.92,522.61 529.92,537.15Q529.92,553.77 520.96,561.04Q512,568.31 498.08,571.92ZM471.92,454.08Q459.77,448.31 449.42,440.35Q439.08,432.39 439.08,418Q439.08,403 449.23,396.04Q459.39,389.08 471.92,387.08L471.92,454.08ZM320,737.88Q212.24,737.88 137.18,662.83Q62.12,587.77 62.12,480.02Q62.12,372.27 137.18,297.1Q212.24,221.92 320,221.92L640,221.92Q747.84,221.92 822.96,297.02Q898.08,372.12 898.08,479.92Q898.08,587.73 822.96,662.81Q747.84,737.88 640,737.88L320,737.88ZM320,681.92L640,681.92Q723.88,681.92 783,622.86Q842.11,563.79 842.11,479.99Q842.11,396.19 783,337.04Q723.88,277.89 640,277.89L320,277.89Q236.2,277.89 177.14,336.99Q118.08,396.09 118.08,479.95Q118.08,563.81 177.14,622.86Q236.2,681.92 320,681.92ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M378.27,812.73L378.27,737.88L263.42,737.88L263.42,681.92L338.27,681.92L338.27,277.89L263.42,277.89L263.42,221.83L378.27,221.83L378.27,147.27L434.23,147.27L434.23,221.92L516.77,221.92L516.77,147.27L572.73,147.27L572.73,224.83L572.73,224.83Q625.11,232.5 658.92,271.59Q692.73,310.67 692.73,364.97Q692.73,395.54 681.33,421.87Q669.92,448.19 650.54,466.39Q688.96,483.54 710.84,517.96Q732.73,552.38 732.73,595.24Q732.73,655.5 691.46,696.69Q650.2,737.88 589.85,737.88L572.73,737.88L572.73,812.73L516.77,812.73L516.77,737.88L434.23,737.88L434.23,812.73L378.27,812.73ZM394.23,451.92L549.85,451.92Q586.57,451.92 611.67,426.89Q636.77,401.86 636.77,364.99Q636.77,328.12 611.67,303Q586.57,277.89 549.85,277.89L394.23,277.89L394.23,451.92ZM394.23,681.92L589.85,681.92Q626.57,681.92 651.67,656.89Q676.77,631.86 676.77,594.99Q676.77,558.11 651.67,533Q626.57,507.88 589.85,507.88L394.23,507.88L394.23,681.92Z" />
</vector>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M9.461 3C5.183 3 3 5.464 3 10.064v3.213 6.438L7.19 15.52v-4.902c0-1.906 .505-3.118 2.199-3.391
.592-.116 1.824-.075 2.607-.075v2.911c0 .027 .004 .074 .01 .098 .033 .118 .139 .204 .266 .204 .071 0 .138-.037
.207-.105l7.262-7.259-4.875-.001zM21 4.285L16.81 8.48v4.902c0 1.906-.505 3.118-2.199 3.391-.592 .116-1.824 .075
-2.607 .075v-2.911c0-.026-.004-.074-.01-.098-.033-.118-.139-.204-.266-.204-.071 0-.138 .037-.207 .105L4.258 20.999
9.133 21H14.539C18.817 21 21 18.536 21 13.936v-3.214z" />
</vector>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M11.393 1.347L8.018 1.869 5.253 13.43c-.16 .682-.244 1.325-.251 1.927-.007 .604 .116 1.136 .37 1.6
.254 .465 .675 .831 1.262 1.1 .588 .268 1.397 .402 2.428 .402v-.002L9.716 15.781C9.339 15.752 9.045 15.687 8.834
15.585 8.624 15.484 8.475 15.35 8.388 15.183 8.301 15.016 8.261 14.823 8.269 14.605c.007-.217 .04-.457 .098-.718zm
5.201 5.184c-.871 0-1.68 .069-2.428 .207-.747 .138-1.412 .294-1.992 .468L8.559 22.27H11.782l.98-3.941c.493 .087
.987 .13 1.48 .13 1.015 0 1.956-.178 2.82-.534 .864-.355 1.603-.851 2.22-1.491 .617-.639 1.099-1.397 1.448-2.276
.348-.878 .522-1.846 .523-2.905 0 0 0-.001 0-.001 0 0 0-.001 0-.001C21.252 10.601 21.162 9.987 20.98 9.415 20.799
8.842 20.519 8.342 20.142 7.913 19.765 7.485 19.283 7.147 18.695 6.901 18.107 6.654 17.407 6.53 16.594 6.53Zm-.414
2.722c.682 0 1.161 .218 1.437 .653 .275 .436 .413 .966 .413 1.59 0 .639-.091 1.223-.272 1.752-.182 .53-.436 .984
-.762 1.361-.327 .378-.723 .671-1.187 .881-.465 .211-.98 .316-1.546 .316-.363 0-.667-.029-.914-.087l1.523-6.335c
.406-.087 .842-.131 1.307-.131z" />
</vector>

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="m11.065 16.274l1.039-3.913 2.46-.899 .612-2.3-.021-.057-2.422 .885 1.745-6.571H9.53L7.248 11.994
5.342 12.69 4.713 15.061 6.617 14.366 5.272 19.419H18.443l.844-3.145h-8.222" />
</vector>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12 2A10 10 0 0 0 2 12A10 10 0 0 0 12 22A10 10 0 0 0 18.043 19.951L15.469 17.377A6.4 6.4 0 0 1 12
18.4A6.4 6.4 0 0 1 5.6 12A6.4 6.4 0 0 1 12 5.6A6.4 6.4 0 0 1 15.465 6.627L18.047 4.045A10 10 0 0 0 12 2zM19.951
5.957L17.377 8.531A6.4 6.4 0 0 1 18.4 12A6.4 6.4 0 0 1 17.373 15.465L19.955 18.047A10 10 0 0 0 22 12A10 10 0 0 0
19.951 5.957z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,614.48Q471.54,614.48 463.6,611.13Q455.65,607.78 449.43,601.57L306.85,458.98Q294.41,446.54 294.54,429.15Q294.67,411.76 306.85,399.33Q319.52,386.65 336.92,386.52Q354.33,386.39 367,399.07L437,469.07L437,204.87Q437,187.22 449.67,174.54Q462.35,161.87 480,161.87Q497.65,161.87 510.33,174.54Q523,187.22 523,204.87L523,469.07L593,399.07Q605.43,386.39 622.84,386.4Q640.24,386.41 652.91,399.09Q665.33,411.76 665.46,429.03Q665.59,446.3 652.91,458.98L510.57,601.57Q504.35,607.78 496.4,611.13Q488.46,614.48 480,614.48ZM247.87,798.13Q212.09,798.13 186.98,773.02Q161.87,747.91 161.87,712.13L161.87,637.63Q161.87,619.98 174.54,607.3Q187.22,594.63 204.87,594.63Q222.52,594.63 235.2,607.3Q247.87,619.98 247.87,637.63L247.87,712.13Q247.87,712.13 247.87,712.13Q247.87,712.13 247.87,712.13L712.13,712.13Q712.13,712.13 712.13,712.13Q712.13,712.13 712.13,712.13L712.13,637.63Q712.13,619.98 724.8,607.3Q737.48,594.63 755.13,594.63Q772.78,594.63 785.46,607.3Q798.13,619.98 798.13,637.63L798.13,712.13Q798.13,747.91 773.02,773.02Q747.91,798.13 712.13,798.13L247.87,798.13Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M176.26,772.73Q147.91,772.73 127.99,752.81Q108.08,732.9 108.08,704.54L108.08,255.46Q108.08,227.1 127.99,207.19Q147.91,187.27 176.26,187.27L783.74,187.27Q812.09,187.27 832.01,207.19Q851.92,227.1 851.92,255.46L851.92,704.54Q851.92,732.9 832.01,752.81Q812.09,772.73 783.74,772.73L176.26,772.73ZM795.96,296.88L498.35,487.96Q493.73,490.27 489.27,491.77Q484.81,493.27 480,493.27Q475.19,493.27 470.73,491.77Q466.27,490.27 461.85,487.96L164.04,296.88L164.04,704.46Q164.04,709.85 167.5,713.31Q170.96,716.77 176.35,716.77L783.65,716.77Q789.04,716.77 792.5,713.31Q795.96,709.85 795.96,704.46L795.96,296.88ZM480,440.81L789,243.23L171,243.23L480,440.81ZM164.04,296.88L164.04,305.61Q164.04,301.33 164.04,295.14Q164.04,288.96 164.04,282.15Q164.04,269.59 164.04,263Q164.04,256.42 164.04,263.96L164.04,243.23L164.04,243.23L164.04,264Q164.04,257.19 164.04,262.73Q164.04,268.27 164.04,281.69Q164.04,289.17 164.04,295.58Q164.04,302 164.04,305.61L164.04,296.88L164.04,704.46Q164.04,709.85 164.04,713.31Q164.04,716.77 164.04,716.77L164.04,716.77Q164.04,716.77 164.04,713.31Q164.04,709.85 164.04,704.46L164.04,296.88Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorError"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19.66,3.99c-2.64,-1.8 -5.9,-0.96 -7.66,1.1 -1.76,-2.06 -5.02,-2.91 -7.66,-1.1 -1.4,0.96 -2.28,2.58 -2.34,4.29 -0.14,3.88 3.3,6.99 8.55,11.76l0.1,0.09c0.76,0.69 1.93,0.69 2.69,-0.01l0.11,-0.1c5.25,-4.76 8.68,-7.87 8.55,-11.75 -0.06,-1.7 -0.94,-3.32 -2.34,-4.28zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorError"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M13.35,20.13c-0.76,0.69 -1.93,0.69 -2.69,-0.01l-0.11,-0.1C5.3,15.27 1.87,12.16 2,8.28c0.06,-1.7 0.93,-3.33 2.34,-4.29 2.64,-1.8 5.9,-0.96 7.66,1.1 1.76,-2.06 5.02,-2.91 7.66,-1.1 1.41,0.96 2.28,2.59 2.34,4.29 0.14,3.88 -3.3,6.99 -8.55,11.76l-0.1,0.09z" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="?android:textColor"
android:pathData="M494.07,281.6l-25.18,-78.08a11,11 0,0 0,-0.61 -2.1L417.78,44.48a20.08,20.08 0,0 0,-19.17 -13.82A19.77,19.77 0,0 0,379.66 44.6L331.52,194.15h-152L131.34,44.59a19.76,19.76 0,0 0,-18.86 -13.94h-0.11a20.15,20.15 0,0 0,-19.12 14L42.7,201.73c0,0.14 -0.11,0.26 -0.16,0.4L16.91,281.61a29.15,29.15 0,0 0,10.44 32.46L248.79,476.48a11.25,11.25 0,0 0,13.38 -0.07L483.65,314.07a29.13,29.13 0,0 0,10.42 -32.47m-331,-64.51L224.8,408.85 76.63,217.09m209.64,191.8 l59.19,-183.84 2.55,-8h86.52L300.47,390.44M398.8,59.31l43.37,134.83H355.35M324.16,217l-43,133.58L255.5,430.14 186.94,217M112.27,59.31l43.46,134.83H69M40.68,295.58a6.19,6.19 0,0 1,-2.21 -6.9l19,-59L197.08,410.27M470.34,295.58 L313.92,410.22l0.52,-0.69L453.5,229.64l19,59a6.2,6.2 0,0 1,-2.19 6.92" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M478.92,812.73Q361.13,812.73 271.1,740.48Q181.08,668.23 155.15,555.95Q151.92,544.46 158.64,534.62Q165.36,524.78 177.58,523.15Q189.04,521.73 198.21,527.79Q207.38,533.85 210.73,545.41Q233.08,637.77 307.69,697.27Q382.31,756.77 478.97,756.77Q594.27,756.77 674.98,676.07Q755.69,595.37 755.69,480.09Q755.69,364.31 674.77,283.77Q593.86,203.23 478.11,203.23Q414.16,203.23 357.98,231.69Q301.81,260.15 261.42,309.23L335.54,309.23Q347.17,309.23 355.39,317.47Q363.62,325.71 363.62,337.13Q363.62,348.77 355.39,356.98Q347.17,365.19 335.54,365.19L203.46,365.19Q189.21,365.19 179.32,355.2Q169.43,345.21 169.43,330.96L169.43,198.81Q169.43,187.43 177.55,179.21Q185.68,171 197.32,171Q208.96,171 217.18,179.24Q225.39,187.47 225.39,198.88L225.39,264.96Q273.27,209.12 338.91,178.19Q404.55,147.27 478.03,147.27Q547.3,147.27 608.07,173.48Q668.84,199.69 713.94,244.79Q759.04,289.89 785.34,350.32Q811.65,410.75 811.65,479.95Q811.65,549.15 785.34,609.63Q759.04,670.11 713.94,715.21Q668.84,760.31 608.38,786.52Q547.91,812.73 478.92,812.73ZM509.27,468.61L617.96,577.35Q626.08,585.66 626.27,597.12Q626.46,608.58 617.96,617.17Q609.46,625.77 598.1,625.77Q586.73,625.77 578.23,617.08L463.37,501.39Q458.23,496.27 455.77,490.21Q453.31,484.15 453.31,477.38L453.31,311.92Q453.31,300.51 461.44,292.27Q469.57,284.04 481.21,284.04Q492.85,284.04 501.06,292.27Q509.27,300.51 509.27,311.92L509.27,468.61Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M204,831Q173.06,831 151.03,808.97Q129,786.94 129,756L129,204Q129,173.06 151.03,151.03Q173.06,129 204,129L756,129Q786.94,129 808.97,151.03Q831,173.06 831,204L831,756Q831,786.94 808.97,808.97Q786.94,831 756,831L204,831ZM204,756L756,756Q756,756 756,756Q756,756 756,756L756,204Q756,204 756,204Q756,204 756,204L204,204Q204,204 204,204Q204,204 204,204L204,756Q204,756 204,756Q204,756 204,756ZM204,756Q204,756 204,756Q204,756 204,756L204,204Q204,204 204,204Q204,204 204,204L204,204Q204,204 204,204Q204,204 204,204L204,756Q204,756 204,756Q204,756 204,756L204,756ZM285.5,677L675.31,677Q687,677 692.5,666.75Q698,656.5 690.5,647L583,504Q577.35,496.5 567.92,496.5Q558.5,496.5 553,504L450,641L377,544.5Q371.35,537 361.92,537Q352.5,537 347,544.5L270.64,646.93Q263,656.5 268.63,666.75Q274.25,677 285.5,677Z" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:textColor"
android:pathData="M13.8521,0.7714C12.3162,0.2228 11.0572,0.3718 9.89,0.7524L9.9406,16.1462c0.8343,0.7743 3.0648,0.8543 3.8984,0.0768V9.216l5.2569,7.0811c0.9244,0.5188 4.1768,0.2319 4.162,-1.317L17.873,8.196 23.352,1.146C22.8842,0.3544 19.6824,0.1619 18.7887,1.003L13.84,7.22ZM4.834,4.005C4.7874,4.0099 4.744,4.0307 4.711,4.064L3.145,5.63C3.0793,5.696 3.0669,5.7982 3.115,5.878L4.949,8.9C4.6205,9.4525 4.3613,10.0432 4.177,10.659l-3.367,0.7c-0.0944,0.0195 -0.1621,0.1026 -0.162,0.199v2.215c0,0.093 0.064,0.174 0.155,0.196l3.268,0.8c0.1709,0.7107 0.4405,1.394 0.801,2.03L2.98,19.683c-0.0521,0.0804 -0.0408,0.1863 0.027,0.254l1.566,1.567c0.0663,0.0659 0.1689,0.0782 0.249,0.03l2.964,-1.8c0.582,0.336 1.21,0.6 1.874,0.78l0.692,3.325C10.372,23.933 10.454,24 10.55,24h2.215c0.0937,0.0003 0.1752,-0.0639 0.197,-0.155l0.815,-3.332c0.6758,-0.1827 1.3239,-0.4555 1.927,-0.811l2.922,1.915c0.08,0.053 0.186,0.042 0.254,-0.026l1.567,-1.566c0.0661,-0.0658 0.0784,-0.1683 0.03,-0.248L19.41,18.019C18.9297,17.2055 18.038,15.026 17.371,15.8 15.3819,19.6985 10.1369,20.4613 7.1197,17.291 4.1025,14.1206 5.1238,8.9198 9.116,7.126 9.5319,6.8182 7.957,5.999 7.957,5.999L7.956,5.997 4.966,4.037C4.9271,4.0111 4.8805,3.9995 4.834,4.004Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M479.76,851.92Q403.15,851.92 335.38,822.71Q267.6,793.49 217.05,742.95Q166.51,692.4 137.29,624.63Q108.08,556.85 108.08,480.24Q108.08,402.85 137.29,335.35Q166.51,267.85 217.05,217.23Q267.6,166.6 335.38,137.34Q403.15,108.08 479.76,108.08Q557.15,108.08 624.65,137.35Q692.15,166.62 742.77,217.26Q793.4,267.89 822.66,335.41Q851.92,402.92 851.92,480Q851.92,556.85 822.66,624.63Q793.4,692.4 742.77,742.95Q692.15,793.49 624.65,822.71Q557.15,851.92 479.76,851.92ZM480,797.54Q511.23,756.52 532.4,714.35Q553.58,672.19 566.92,622.88L393.27,622.88Q407,673.92 427.98,715.89Q448.97,757.86 480,797.54ZM407.39,785.73Q383.58,751.42 364.71,709.23Q345.85,667.04 335.6,622.88L199.19,622.88Q230.88,686.5 284.9,728.64Q338.92,770.77 407.39,785.73ZM552.61,785.73Q620.88,770.96 675,728.73Q729.12,686.5 761,622.88L624.59,622.88Q612.23,667.42 593.36,709.61Q574.5,751.81 552.61,785.73ZM176.46,566.92L323.85,566.92Q320.08,544.31 318.39,522.79Q316.69,501.27 316.69,480Q316.69,458.73 318.39,437.21Q320.08,415.69 323.85,393.08L176.46,393.08Q170.19,413.96 167.12,435.8Q164.04,457.64 164.04,480Q164.04,502.36 167.12,524.2Q170.19,546.04 176.46,566.92ZM380.31,566.92L579.89,566.92Q583.77,544.31 585.56,523.34Q587.35,502.36 587.35,480Q587.35,457.64 585.56,436.66Q583.77,415.69 579.89,393.08L380.31,393.08Q376.23,415.69 374.44,436.66Q372.65,457.64 372.65,480Q372.65,502.36 374.44,523.34Q376.23,544.31 380.31,566.92ZM636.15,566.92L783.73,566.92Q789.81,546.04 792.89,524.2Q795.96,502.36 795.96,480Q795.96,457.64 792.89,435.8Q789.81,413.96 783.73,393.08L636.15,393.08Q639.92,415.69 641.61,437.21Q643.31,458.73 643.31,480Q643.31,501.27 641.61,522.79Q639.92,544.31 636.15,566.92ZM624.59,337.12L761,337.12Q728.92,272.92 675.77,231.36Q622.61,189.81 552.61,173.88Q576.42,210.11 595,251.73Q613.58,293.35 624.59,337.12ZM393.27,337.12L566.92,337.12Q553,286.65 531.44,243.63Q509.88,200.6 480,162.46Q450.12,200.6 428.56,243.63Q407,286.65 393.27,337.12ZM199.19,337.12L335.6,337.12Q346.42,293.35 365,251.73Q383.58,210.11 407.39,173.88Q337.19,190 284.14,231.56Q231.08,273.11 199.19,337.12Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M204,831Q173.06,831 151.03,808.97Q129,786.94 129,756L129,204Q129,173.06 151.03,151.03Q173.06,129 204,129L439.5,129Q455,129 466,140Q477,151 477,166.5Q477,182 466,193Q455,204 439.5,204L204,204Q204,204 204,204Q204,204 204,204L204,756Q204,756 204,756Q204,756 204,756L756,756Q756,756 756,756Q756,756 756,756L756,520.5Q756,505 767,494Q778,483 793.5,483Q809,483 820,494Q831,505 831,520.5L831,756Q831,786.94 808.97,808.97Q786.94,831 756,831L204,831ZM756,256.5L415.5,597Q405,607.5 389.75,607.5Q374.5,607.5 363.5,596.5Q352.5,585.5 352.5,570.25Q352.5,555 363.38,544.12L703.5,204L589.5,204Q574,204 563,193Q552,182 552,166.5Q552,151 563,140Q574,129 589.5,129L831,129L831,370.5Q831,386 820,397Q809,408 793.5,408Q778,408 767,397Q756,386 756,370.5L756,256.5Z" />
</vector>

View File

@@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M22.42,11.34l-1.86,-2.12 0.26,-2.81c0.05,-0.5 -0.29,-0.96 -0.77,-1.07l-2.76,-0.63 -1.44,-2.43c-0.26,-0.43 -0.79,-0.61 -1.25,-0.41L12,3 9.41,1.89c-0.46,-0.2 -1,-0.02 -1.25,0.41L6.71,4.72l-2.75,0.62c-0.49,0.11 -0.83,0.56 -0.78,1.07l0.26,2.8 -1.86,2.13c-0.33,0.38 -0.33,0.94 0,1.32l1.86,2.12 -0.26,2.82c-0.05,0.5 0.29,0.96 0.77,1.07l2.76,0.63 1.44,2.42c0.26,0.43 0.79,0.61 1.26,0.41L12,21l2.59,1.11c0.46,0.2 1,0.02 1.25,-0.41l1.44,-2.43 2.76,-0.63c0.49,-0.11 0.82,-0.57 0.77,-1.07l-0.26,-2.81 1.86,-2.12c0.34,-0.36 0.34,-0.92 0.01,-1.3zM13,17h-2v-2h2v2zM12,13c-0.55,0 -1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v4c0,0.55 -0.45,1 -1,1z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M452.12,643.58L452.12,435.19L508.08,435.19L508.08,643.58L452.12,643.58ZM480.11,365.5Q467.08,365.5 458.19,356.72Q449.31,347.94 449.31,334.91Q449.31,321.89 458.09,313Q466.87,304.12 479.89,304.12Q492.92,304.12 501.81,312.9Q510.69,321.67 510.69,334.7Q510.69,347.73 501.91,356.62Q493.13,365.5 480.11,365.5ZM294.65,891.92Q266.29,891.92 246.38,872.01Q226.46,852.09 226.46,823.75L226.46,136.25Q226.46,107.91 246.38,87.99Q266.29,68.08 294.65,68.08L665.35,68.08Q693.71,68.08 713.62,87.99Q733.54,107.91 733.54,136.25L733.54,823.75Q733.54,852.09 713.62,872.01Q693.71,891.92 665.35,891.92L294.65,891.92ZM282.42,784.35L282.42,823.65Q282.42,828.27 286.27,832.11Q290.12,835.96 294.73,835.96L665.27,835.96Q669.88,835.96 673.73,832.11Q677.58,828.27 677.58,823.65L677.58,784.35L282.42,784.35ZM282.42,728.39L677.58,728.39L677.58,231.61L282.42,231.61L282.42,728.39ZM282.42,175.65L677.58,175.65L677.58,136.35Q677.58,131.73 673.73,127.89Q669.88,124.04 665.27,124.04L294.73,124.04Q290.12,124.04 286.27,127.89Q282.42,131.73 282.42,136.35L282.42,175.65ZM282.42,175.65L282.42,136.35Q282.42,131.73 282.42,127.89Q282.42,124.04 282.42,124.04L282.42,124.04Q282.42,124.04 282.42,127.89Q282.42,131.73 282.42,136.35L282.42,175.65L282.42,175.65ZM282.42,784.35L282.42,784.35L282.42,823.65Q282.42,828.27 282.42,832.11Q282.42,835.96 282.42,835.96L282.42,835.96Q282.42,835.96 282.42,832.11Q282.42,828.27 282.42,823.65L282.42,784.35Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,468.5Q423.56,468.5 383.8,428.74Q344.04,388.98 344.04,332.54Q344.04,276.1 383.8,236.34Q423.56,196.58 480,196.58Q536.44,196.58 576.2,236.34Q615.96,276.1 615.96,332.54Q615.96,388.98 576.2,428.74Q536.44,468.5 480,468.5ZM187.27,705.08L187.27,677.68Q187.27,649.09 202.57,625.11Q217.88,601.13 244.25,588.06Q302.86,559.79 361.8,545.39Q420.73,531 480.01,531Q539.28,531 598.26,545.39Q657.23,559.77 715.8,588.05Q742.15,601.12 757.44,625.1Q772.73,649.09 772.73,677.67L772.73,705.08Q772.73,728.72 756.18,745.26Q739.64,761.81 716,761.81L244,761.81Q220.36,761.81 203.82,745.26Q187.27,728.72 187.27,705.08ZM243.23,705.85L716.77,705.85L716.77,677.78Q716.77,665.39 709.73,654.98Q702.69,644.58 690.31,637.85Q638.87,612.69 586.23,599.83Q533.58,586.96 479.98,586.96Q426.02,586.96 373.55,599.83Q321.08,612.69 269.89,637.85Q257.31,644.58 250.27,655.02Q243.23,665.46 243.23,677.73L243.23,705.85ZM480,412.54Q513,412.54 536.5,389.04Q560,365.54 560,332.54Q560,299.54 536.5,276.04Q513,252.54 480,252.54Q447,252.54 423.5,276.04Q400,299.54 400,332.54Q400,365.54 423.5,389.04Q447,412.54 480,412.54ZM480,332.54Q480,332.54 480,332.54Q480,332.54 480,332.54Q480,332.54 480,332.54Q480,332.54 480,332.54Q480,332.54 480,332.54Q480,332.54 480,332.54Q480,332.54 480,332.54Q480,332.54 480,332.54ZM480,705.85L480,705.85Q480,705.85 480,705.85Q480,705.85 480,705.85Q480,705.85 480,705.85Q480,705.85 480,705.85Q480,705.85 480,705.85Q480,705.85 480,705.85Q480,705.85 480,705.85Q480,705.85 480,705.85L480,705.85L480,705.85Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M282.33,694.34Q193.1,694.34 130.59,631.87Q68.08,569.39 68.08,480.14Q68.08,390.89 130.6,328.27Q193.11,265.66 282.42,265.66Q343.55,265.66 395.78,298.41Q448,331.16 474.08,384.85L823.65,384.85Q851.81,384.85 871.87,404.9Q891.92,424.96 891.92,453.12L891.92,506.88Q891.92,535.05 871.87,555.1Q851.81,575.15 823.65,575.15L812.73,575.15L812.73,626.08Q812.73,654.24 792.67,674.29Q772.62,694.34 744.46,694.34L689.89,694.34Q661.72,694.34 641.67,674.29Q621.62,654.24 621.62,626.08L621.62,575.15L474.08,575.15Q448,628.84 395.75,661.59Q343.5,694.34 282.33,694.34ZM282.48,638.39Q348.16,638.39 387.59,598.14Q427.02,557.89 434.9,519.19L677.8,519.19L677.8,626.08Q677.8,631.46 681.27,634.92Q684.73,638.39 690.11,638.39L744.46,638.39Q749.85,638.39 753.31,634.92Q756.77,631.46 756.77,626.08L756.77,519.19L823.65,519.19Q829.04,519.19 832.5,515.73Q835.96,512.27 835.96,506.88L835.96,453.12Q835.96,447.73 832.5,444.27Q829.04,440.81 823.65,440.81L434.81,440.81Q426.92,402.07 387.5,361.84Q348.08,321.61 282.4,321.61Q216.73,321.61 170.38,367.98Q124.04,414.35 124.04,480.02Q124.04,545.69 170.42,592.04Q216.8,638.39 282.48,638.39ZM282.53,541.38Q307.77,541.38 325.79,523.26Q343.81,505.13 343.81,479.89Q343.81,454.65 325.68,436.64Q307.56,418.62 282.32,418.62Q257.08,418.62 239.06,436.74Q221.04,454.87 221.04,480.11Q221.04,505.35 239.16,523.36Q257.29,541.38 282.53,541.38ZM282.42,480Q282.42,480 282.42,480Q282.42,480 282.42,480Q282.42,480 282.42,480Q282.42,480 282.42,480Q282.42,480 282.42,480Q282.42,480 282.42,480L282.42,480L282.42,480L282.42,480L282.42,480L282.42,480L282.42,480L282.42,480Q282.42,480 282.42,480Q282.42,480 282.42,480Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480.09,851.92Q402.94,851.92 335.03,822.6Q267.11,793.27 216.87,743Q166.64,692.73 137.36,624.95Q108.08,557.16 108.08,480.09Q108.08,402.94 137.4,335.03Q166.73,267.11 217,216.87Q267.27,166.64 335.05,137.36Q402.84,108.08 479.91,108.08Q557.06,108.08 624.97,137.4Q692.89,166.73 743.13,217Q793.36,267.27 822.64,335.05Q851.92,402.84 851.92,479.91Q851.92,557.06 822.6,624.97Q793.27,692.89 743,743.13Q692.73,793.36 624.95,822.64Q557.16,851.92 480.09,851.92ZM480,795.96Q611.9,795.96 703.93,703.94Q795.96,611.92 795.96,479.9Q795.96,473 795.81,466.25Q795.65,459.5 794.96,452.92Q791.24,479.86 771.41,497.33Q751.58,514.81 723.72,514.81L634.55,514.81Q604.54,514.81 583.29,493.77Q562.04,472.73 562.04,442.75L562.04,406.41L417.58,406.41L417.58,333.85Q417.58,303.92 438.63,282.78Q459.69,261.63 489.63,261.63L525.92,261.63L525.92,246.24Q525.92,220.54 541.69,203.67Q557.46,186.81 579.19,180.35Q555.73,172.35 530.91,168.19Q506.1,164.04 480,164.04Q348.1,164.04 256.07,256.07Q164.04,348.1 164.04,480Q164.04,483.08 164.04,485.77Q164.04,488.46 164.42,491.54L335.96,491.54Q396.14,491.54 438.43,533.82Q480.73,576.09 480.73,636.07L480.73,672.42L372.38,672.42L372.38,776.38Q397.61,785.73 424.54,790.85Q451.47,795.96 480,795.96Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M202.87,848.13Q165.09,848.13 138.48,821.52Q111.87,794.91 111.87,757.13L111.87,202.87Q111.87,165.09 138.48,138.48Q165.09,111.87 202.87,111.87L645.8,111.87Q664.02,111.87 680.52,118.71Q697.02,125.54 709.7,138.22L821.78,250.3Q834.46,262.98 841.29,279.48Q848.13,295.98 848.13,314.2L848.13,757.13Q848.13,794.91 821.52,821.52Q794.91,848.13 757.13,848.13L202.87,848.13ZM757.13,315.2L644.8,202.87L202.87,202.87Q202.87,202.87 202.87,202.87Q202.87,202.87 202.87,202.87L202.87,757.13Q202.87,757.13 202.87,757.13Q202.87,757.13 202.87,757.13L757.13,757.13Q757.13,757.13 757.13,757.13Q757.13,757.13 757.13,757.13L757.13,315.2ZM480,717.13Q530,717.13 565,682.13Q600,647.13 600,597.13Q600,547.13 565,512.13Q530,477.13 480,477.13Q430,477.13 395,512.13Q360,547.13 360,597.13Q360,647.13 395,682.13Q430,717.13 480,717.13ZM288.37,402.87L557.37,402.87Q576.52,402.87 589.7,389.7Q602.87,376.52 602.87,357.37L602.87,288.37Q602.87,269.22 589.7,256.04Q576.52,242.87 557.37,242.87L288.37,242.87Q269.22,242.87 256.04,256.04Q242.87,269.22 242.87,288.37L242.87,357.37Q242.87,376.52 256.04,389.7Q269.22,402.87 288.37,402.87ZM202.87,315.2L202.87,757.13Q202.87,757.13 202.87,757.13Q202.87,757.13 202.87,757.13L202.87,757.13Q202.87,757.13 202.87,757.13Q202.87,757.13 202.87,757.13L202.87,202.87Q202.87,202.87 202.87,202.87Q202.87,202.87 202.87,202.87L202.87,202.87L202.87,315.2Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M379.74,639.5Q271.46,639.5 196.27,564.37Q121.09,489.24 121.09,381.05Q121.09,272.85 196.21,197.67Q271.34,122.5 379.54,122.5Q487.74,122.5 562.91,197.69Q638.09,272.87 638.09,381.16Q638.09,424.48 625.07,462.87Q612.04,501.26 589.5,530.28L809.2,749.75Q821.76,762.52 821.76,780.05Q821.76,797.59 808.85,810.26Q796.17,822.93 778.52,822.93Q760.87,822.93 748.32,810.39L529.01,590.91Q499.59,613.96 461.21,626.73Q422.83,639.5 379.74,639.5ZM379.59,553.5Q451.93,553.5 502.01,503.42Q552.09,453.35 552.09,381Q552.09,308.65 502.01,258.58Q451.93,208.5 379.59,208.5Q307.24,208.5 257.16,258.58Q207.09,308.65 207.09,381Q207.09,453.35 257.16,503.42Q307.24,553.5 379.59,553.5Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M716.88,871Q668.5,871 634.75,837.17Q601,803.33 601,755Q601,748.04 602,740.58Q603,733.11 605,727.15L324,564Q307.5,579.5 287.05,587.75Q266.6,596 244.2,596Q195.5,596 161.75,562.02Q128,528.04 128,479.5Q128,431.38 161.83,397.69Q195.67,364 244,364Q266.65,364 287.32,372Q308,380 324,395L605,231.85Q603,225.89 602,218.42Q601,210.96 601,204Q601,155.67 634.87,121.83Q668.73,88 717.12,88Q765.5,88 799.25,121.69Q833,155.38 833,203.5Q833,252.04 799.17,286.02Q765.33,320 717,320Q694.53,320 674.02,311.75Q653.5,303.5 637,288L356,451Q358,457.29 359,465.14Q360,473 360,479.96Q360,486.93 359,494.39Q358,501.85 356,507.82L637,671Q653.5,655.5 673.95,647.25Q694.4,639 716.8,639Q765.5,639 799.25,672.98Q833,706.96 833,755.5Q833,803.63 799.13,837.31Q765.27,871 716.88,871ZM717,245Q734,245 746,233Q758,221 758,204Q758,187 746,175Q734,163 717,163Q700,163 688,175Q676,187 676,204Q676,221 688,233Q700,245 717,245ZM244,521Q261,521 273,509Q285,497 285,480Q285,463 273,451Q261,439 244,439Q227,439 215,451Q203,463 203,480Q203,497 215,509Q227,521 244,521ZM717,796Q734,796 746,784Q758,772 758,755Q758,738 746,726Q734,714 717,714Q700,714 688,726Q676,738 676,755Q676,772 688,784Q700,796 717,796ZM717,204Q717,204 717,204Q717,204 717,204Q717,204 717,204Q717,204 717,204Q717,204 717,204Q717,204 717,204Q717,204 717,204Q717,204 717,204ZM244,480Q244,480 244,480Q244,480 244,480Q244,480 244,480Q244,480 244,480Q244,480 244,480Q244,480 244,480Q244,480 244,480Q244,480 244,480ZM717,755Q717,755 717,755Q717,755 717,755Q717,755 717,755Q717,755 717,755Q717,755 717,755Q717,755 717,755Q717,755 717,755Q717,755 717,755Z" />
</vector>

View File

@@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M164.63,726.26Q146.89,726.26 134.38,713.59Q121.87,700.91 121.87,683.2Q121.87,665.49 134.38,653Q146.89,640.5 164.63,640.5L322.8,640.5Q340.54,640.5 353.05,653.17Q365.57,665.85 365.57,683.56Q365.57,701.27 353.05,713.77Q340.54,726.26 322.8,726.26L164.63,726.26ZM164.63,528Q146.89,528 134.38,515.33Q121.87,502.65 121.87,484.94Q121.87,467.23 134.38,454.73Q146.89,442.24 164.63,442.24L559.22,442.24Q576.95,442.24 589.47,454.91Q601.98,467.59 601.98,485.3Q601.98,503.01 589.47,515.5Q576.95,528 559.22,528L164.63,528ZM164.63,329.74Q146.89,329.74 134.38,317.07Q121.87,304.39 121.87,286.68Q121.87,268.97 134.54,256.47Q147.22,243.98 164.87,243.98L795.37,243.98Q813.11,243.98 825.62,256.65Q838.13,269.33 838.13,287.04Q838.13,304.75 825.46,317.24Q812.78,329.74 795.13,329.74L164.63,329.74Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorOnSurface"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M8.0855,18.6109L14.0817,4.6064C14.2991,4.0987 14.8868,3.8633 15.3946,4.0807C15.866,4.2826 16.1026,4.8038 15.96,5.2837L15.9202,5.3936L9.9241,19.3981C9.7067,19.9058 9.1189,20.1412 8.6112,19.9238C8.1398,19.722 7.9032,19.2007 8.0458,18.7208L8.0855,18.6109L14.0817,4.6064L8.0855,18.6109ZM2.2929,11.2929L6.2929,7.2929C6.6834,6.9024 7.3166,6.9024 7.7071,7.2929C8.0676,7.6534 8.0953,8.2206 7.7903,8.6129L7.7071,8.7071L4.4142,12L7.7071,15.2929C8.0976,15.6834 8.0976,16.3166 7.7071,16.7071C7.3466,17.0676 6.7794,17.0953 6.3871,16.7903L6.2929,16.7071L2.2929,12.7071C1.9324,12.3466 1.9047,11.7794 2.2097,11.3871L2.2929,11.2929L6.2929,7.2929L2.2929,11.2929ZM16.2921,7.2917C16.6526,6.9312 17.2198,6.9035 17.6121,7.2085L17.7063,7.2917L21.7071,11.2929C22.0678,11.6536 22.0953,12.2211 21.7899,12.6134L21.7066,12.7076L17.7058,16.7031C17.315,17.0934 16.6819,17.0929 16.2916,16.7022C15.9313,16.3414 15.904,15.7742 16.2093,15.3821L16.2925,15.288L19.5854,11.9995L16.292,8.7059C15.9015,8.3153 15.9015,7.6822 16.2921,7.2917Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M246.52,481.5Q246.52,524.57 262.91,565.99Q279.3,607.41 314.35,642.93L325.43,654.02L325.43,600.17Q325.43,583.96 337.03,572.48Q348.63,561 364.85,561Q381.07,561 392.54,572.48Q404.02,583.96 404.02,600.17L404.02,754.78Q404.02,772.43 391.35,785.11Q378.67,797.78 361.02,797.78L206.65,797.78Q190.43,797.78 178.96,786.18Q167.48,774.59 167.48,758.37Q167.48,742.15 179.08,730.67Q190.67,719.2 206.89,719.2L269.59,719.2L254.7,704.59Q204.96,656.65 182.74,598.68Q160.52,540.72 160.52,481.5Q160.52,387.61 209.55,310.08Q258.59,232.54 340.96,192.8Q356.13,185.33 371.21,193.38Q386.28,201.43 391.76,218.59Q397,235.24 390.67,250.78Q384.35,266.33 368.93,274.78Q312.61,305.57 279.57,360.62Q246.52,415.67 246.52,481.5ZM713.48,478.5Q713.48,435.43 697.09,394.01Q680.7,352.59 645.65,317.07L634.57,305.98L634.57,359.83Q634.57,376.04 623.09,387.52Q611.61,399 595.39,399Q579.17,399 567.58,387.4Q555.98,375.8 555.98,359.59L555.98,205.22Q555.98,187.57 568.65,174.89Q581.33,162.22 598.98,162.22L753.35,162.22Q769.57,162.22 781.04,173.7Q792.52,185.17 792.52,201.39Q792.52,217.61 781.04,229.21Q769.57,240.8 753.35,240.8L690.41,240.8L705.3,255.41Q754.02,304.37 776.75,361.83Q799.48,419.28 799.48,478.5Q799.48,572.39 750.45,649.42Q701.41,726.46 619.54,766.7Q604.37,774.17 589.04,766.37Q573.72,758.57 568.24,741.41Q563,724.76 569.33,709.22Q575.65,693.67 591.07,685.22Q647.39,654.43 680.43,599.38Q713.48,544.33 713.48,478.5Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M231.31,482.27Q231.31,528.84 248.8,573.11Q266.3,617.38 303.88,654.89L331.69,682.69L331.69,600.23Q331.69,588.79 339.92,580.57Q348.14,572.35 359.78,572.35Q371.23,572.35 379.44,580.57Q387.65,588.79 387.65,600.23L387.65,747.04Q387.65,761.29 377.66,771.28Q367.67,781.27 353.61,781.27L206.81,781.27Q195.17,781.27 186.95,773.04Q178.73,764.82 178.73,753.18Q178.73,741.73 186.95,733.52Q195.17,725.31 206.81,725.31L295.65,725.31L264.96,695.04Q217.77,649.11 196.56,594Q175.35,538.88 175.35,482.27Q175.35,393.85 221,320.37Q266.65,246.89 343.65,207.58Q354.08,202.31 364.9,206.69Q375.73,211.08 379.77,222.11Q383.42,233.08 379.36,243.53Q375.29,253.98 364.81,259.81Q303.15,292.46 267.23,351.81Q231.31,411.16 231.31,482.27ZM728.89,477.54Q728.89,431.16 711.29,386.89Q693.7,342.62 656.12,305.11L628.31,277.31L628.31,359.58Q628.31,371.21 620.08,379.43Q611.86,387.65 600.41,387.65Q588.77,387.65 580.56,379.43Q572.35,371.21 572.35,359.58L572.35,212.77Q572.35,198.71 582.34,188.72Q592.33,178.73 606.58,178.73L753.38,178.73Q764.83,178.73 773.05,186.96Q781.27,195.18 781.27,206.63Q781.27,218.27 773.05,226.48Q764.83,234.69 753.38,234.69L664.34,234.69L695.04,264.96Q741.43,311.35 763.14,366.16Q784.85,420.96 784.85,477.6Q784.85,566.15 739.38,639.13Q693.92,712.11 617.23,751.54Q606.61,756.81 595.64,752.86Q584.65,748.92 580.81,737.7Q576.77,726.92 580.96,716.44Q585.15,705.96 595.39,700.19Q656.85,667.54 692.87,608.19Q728.89,548.84 728.89,477.54Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M479.23,851.92Q402.77,851.92 335.09,822.71Q267.4,793.49 216.96,742.95Q166.51,692.4 137.29,624.63Q108.08,556.85 108.08,479.99Q108.08,402.15 138.06,334.42Q168.04,266.69 219.71,216.34Q271.39,166 340.81,137.04Q410.23,108.08 488.57,108.08Q562.06,108.08 627.64,133.25Q693.23,158.42 743.02,202.57Q792.81,246.71 822.37,307.49Q851.92,368.27 851.92,438.96Q851.92,540.44 791.96,597.39Q732,654.34 637.61,654.34L566.73,654.34Q548.35,654.34 537.15,666.08Q525.96,677.81 525.96,694.33Q525.96,713.41 540.96,734.9Q555.96,756.39 555.96,782.81Q555.96,816.27 536.46,834.09Q516.96,851.92 479.23,851.92ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM262.38,507.58Q282.7,507.58 296.35,493.97Q310,480.36 310,460.04Q310,439.72 296.39,426.07Q282.78,412.42 262.46,412.42Q242.15,412.42 228.5,426.03Q214.85,439.64 214.85,459.96Q214.85,480.28 228.46,493.93Q242.07,507.58 262.38,507.58ZM381.58,349.19Q401.89,349.19 415.54,335.58Q429.19,321.97 429.19,301.66Q429.19,281.34 415.58,267.69Q401.97,254.04 381.66,254.04Q361.34,254.04 347.69,267.65Q334.04,281.26 334.04,301.58Q334.04,321.89 347.65,335.54Q361.26,349.19 381.58,349.19ZM579.15,349.19Q599.47,349.19 613.12,335.58Q626.77,321.97 626.77,301.66Q626.77,281.34 613.16,267.69Q599.55,254.04 579.23,254.04Q558.92,254.04 545.27,267.65Q531.62,281.26 531.62,301.58Q531.62,321.89 545.23,335.54Q558.84,349.19 579.15,349.19ZM697.54,507.58Q717.85,507.58 731.5,493.97Q745.15,480.36 745.15,460.04Q745.15,439.72 731.54,426.07Q717.93,412.42 697.62,412.42Q677.3,412.42 663.65,426.03Q650,439.64 650,459.96Q650,480.28 663.61,493.93Q677.22,507.58 697.54,507.58ZM479.31,795.96Q488.96,795.96 494.48,791.15Q500,786.35 500,777.96Q500,763.96 485.4,746.1Q470.81,728.23 470.81,691.81Q470.81,649.54 499.19,623.96Q527.57,598.39 569.26,598.39L637.58,598.39Q708.19,598.39 752.08,557.56Q795.96,516.73 795.96,438.92Q795.96,319.46 703.94,241.75Q611.92,164.04 488.7,164.04Q353.54,164.04 258.79,255.86Q164.04,347.69 164.04,480Q164.04,611.08 256.48,703.52Q348.92,795.96 479.31,795.96Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M508.38,468.65L508.38,310.31Q508.38,298.89 500.14,290.66Q491.9,282.42 480.49,282.42Q468.85,282.42 460.64,290.66Q452.42,298.89 452.42,310.31L452.42,477.38Q452.42,483.96 454.89,490.12Q457.35,496.29 462.48,501.38L598.46,637.92Q606.46,646.19 617.92,646.38Q629.39,646.58 638.08,637.89Q646.58,629.39 646.58,618.12Q646.58,606.85 638.12,598.2L508.38,468.65ZM480.09,851.92Q402.94,851.92 335.03,822.6Q267.11,793.27 216.87,743Q166.64,692.73 137.36,624.95Q108.08,557.16 108.08,480.09Q108.08,402.94 137.4,335.03Q166.73,267.11 217,216.87Q267.27,166.64 335.05,137.36Q402.84,108.08 479.91,108.08Q557.06,108.08 624.97,137.4Q692.89,166.73 743.13,217Q793.36,267.27 822.64,335.05Q851.92,402.84 851.92,479.91Q851.92,557.06 822.6,624.97Q793.27,692.89 743,743.13Q692.73,793.36 624.95,822.64Q557.16,851.92 480.09,851.92ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM480,795.96Q611.08,795.96 703.52,703.52Q795.96,611.08 795.96,480Q795.96,348.92 703.52,256.48Q611.08,164.04 480,164.04Q348.92,164.04 256.48,256.48Q164.04,348.92 164.04,480Q164.04,611.08 256.48,703.52Q348.92,795.96 480,795.96Z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M703.5,806Q642,806 599,763Q556,720 556,658.5Q556,597 599,554Q642,511 703.5,511Q765,511 808,554Q851,597 851,658.5Q851,720 808,763Q765,806 703.5,806ZM703.47,731Q733.5,731 754.75,709.78Q776,688.55 776,658.53Q776,628.5 754.78,607.25Q733.55,586 703.53,586Q673.5,586 652.25,607.22Q631,628.45 631,658.47Q631,688.5 652.22,709.75Q673.45,731 703.47,731ZM443.5,696L186.5,696Q171,696 160,685Q149,674 149,658.5Q149,643 160,632Q171,621 186.5,621L443.5,621Q459,621 470,632Q481,643 481,658.5Q481,674 470,685Q459,696 443.5,696ZM256.5,449Q195,449 152,406Q109,363 109,301.5Q109,240 152,197Q195,154 256.5,154Q318,154 361,197Q404,240 404,301.5Q404,363 361,406Q318,449 256.5,449ZM256.48,374Q286.5,374 307.75,352.78Q329,331.55 329,301.53Q329,271.5 307.77,250.25Q286.55,229 256.52,229Q226.5,229 205.25,250.22Q184,271.45 184,301.47Q184,331.5 205.23,352.75Q226.45,374 256.48,374ZM773.5,339L516.5,339Q501,339 490,328Q479,317 479,301.5Q479,286 490,275Q501,264 516.5,264L773.5,264Q789,264 800,275Q811,286 811,301.5Q811,317 800,328Q789,339 773.5,339ZM703.5,658.5Q703.5,658.5 703.5,658.5Q703.5,658.5 703.5,658.5Q703.5,658.5 703.5,658.5Q703.5,658.5 703.5,658.5Q703.5,658.5 703.5,658.5Q703.5,658.5 703.5,658.5Q703.5,658.5 703.5,658.5Q703.5,658.5 703.5,658.5ZM256.5,301.5Q256.5,301.5 256.5,301.5Q256.5,301.5 256.5,301.5Q256.5,301.5 256.5,301.5Q256.5,301.5 256.5,301.5Q256.5,301.5 256.5,301.5Q256.5,301.5 256.5,301.5Q256.5,301.5 256.5,301.5Q256.5,301.5 256.5,301.5Z" />
</vector>

Some files were not shown because too many files have changed in this diff Show More