Add UI
This commit is contained in:
parent
9a96cc4583
commit
3d37a285d4
83
ui/build.gradle
Normal file
83
ui/build.gradle
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2019, microG Project Team
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion androidCompileSdk
|
||||||
|
buildToolsVersion "$androidBuildVersionTools"
|
||||||
|
dataBinding {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
versionName version
|
||||||
|
minSdkVersion Math.max(androidMinSdk, 14)
|
||||||
|
targetSdkVersion androidTargetSdk
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':api')
|
||||||
|
implementation project(':client')
|
||||||
|
|
||||||
|
implementation "androidx.appcompat:appcompat:$appcompatVersion"
|
||||||
|
implementation "androidx.fragment:fragment:$fragmentVersion"
|
||||||
|
implementation "androidx.recyclerview:recyclerview:$recyclerviewVersion"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
release(MavenPublication) {
|
||||||
|
pom {
|
||||||
|
name = 'UnifiedNlp UI'
|
||||||
|
description = 'UnifiedNlp UI library for common configuration fragments'
|
||||||
|
url = 'https://github.com/microg/UnifiedNlp'
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = 'The Apache Software License, Version 2.0'
|
||||||
|
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = 'microg'
|
||||||
|
name = 'microG Team'
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id = 'mar-v-in'
|
||||||
|
name = 'Marvin W.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
url = 'https://github.com/microg/UnifiedNlp'
|
||||||
|
connection = 'scm:git:https://github.com/microg/UnifiedNlp.git'
|
||||||
|
developerConnection = 'scm:git:ssh://github.com/microg/UnifiedNlp.git'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from components.release
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
ui/src/main/AndroidManifest.xml
Normal file
10
ui/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest package="org.microg.nlp.ui">
|
||||||
|
|
||||||
|
<application />
|
||||||
|
</manifest>
|
150
ui/src/main/kotlin/org/microg/nlp/ui/BackendDetailsFragment.kt
Normal file
150
ui/src/main/kotlin/org/microg/nlp/ui/BackendDetailsFragment.kt
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
package org.microg.nlp.ui
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.Intent.ACTION_VIEW
|
||||||
|
import android.content.pm.PackageManager.GET_META_DATA
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.databinding.Observable
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.microg.nlp.client.UnifiedLocationClient
|
||||||
|
import org.microg.nlp.ui.BackendType.GEOCODER
|
||||||
|
import org.microg.nlp.ui.BackendType.LOCATION
|
||||||
|
import org.microg.nlp.ui.databinding.BackendDetailsBinding
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class BackendDetailsFragment : Fragment(R.layout.backend_details) {
|
||||||
|
|
||||||
|
fun Double.toStringWithDigits(digits: Int): String {
|
||||||
|
val s = this.toString()
|
||||||
|
val i = s.indexOf('.')
|
||||||
|
if (i <= 0 || s.length - i - 1 < digits) return s
|
||||||
|
if (digits == 0) return s.substring(0, i)
|
||||||
|
return s.substring(0, s.indexOf('.') + digits + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Float.toStringWithDigits(digits: Int): String {
|
||||||
|
val s = this.toString()
|
||||||
|
val i = s.indexOf('.')
|
||||||
|
if (i <= 0 || s.length - i - 1 < digits) return s
|
||||||
|
if (digits == 0) return s.substring(0, i)
|
||||||
|
return s.substring(0, s.indexOf('.') + digits + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
fun Context.resolveColor(@AttrRes resid: Int): Int? {
|
||||||
|
val typedValue = TypedValue()
|
||||||
|
if (!theme.resolveAttribute(resid, typedValue, true)) return null
|
||||||
|
val colorRes = if (typedValue.resourceId != 0) typedValue.resourceId else typedValue.data
|
||||||
|
return ContextCompat.getColor(this, colorRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
val switchBarEnabledColor: Int
|
||||||
|
get() = context?.resolveColor(androidx.appcompat.R.attr.colorControlActivated) ?: Color.RED
|
||||||
|
|
||||||
|
val switchBarDisabledColor: Int
|
||||||
|
get() {
|
||||||
|
val color = context?.resolveColor(android.R.attr.textColorSecondary) ?: Color.RED
|
||||||
|
return Color.argb(100, Color.red(color), Color.green(color), Color.blue(color))
|
||||||
|
}
|
||||||
|
|
||||||
|
val switchBarTrackTintColor: ColorStateList
|
||||||
|
get() {
|
||||||
|
val color = context?.resolveColor(android.R.attr.textColorPrimaryInverse)
|
||||||
|
?: Color.RED
|
||||||
|
val withAlpha = Color.argb(50, Color.red(color), Color.green(color), Color.blue(color))
|
||||||
|
return ColorStateList(arrayOf(emptyArray<Int>().toIntArray()), arrayOf(withAlpha).toIntArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
val binding = BackendDetailsBinding.inflate(inflater, container, false)
|
||||||
|
binding.fragment = this
|
||||||
|
binding.switchWidget.trackTintList = switchBarTrackTintColor
|
||||||
|
lifecycleScope.launchWhenStarted {
|
||||||
|
val entry = createBackendInfo()
|
||||||
|
binding.entry = entry
|
||||||
|
binding.executePendingBindings()
|
||||||
|
if (entry?.type == LOCATION) {
|
||||||
|
val client = UnifiedLocationClient[entry.context]
|
||||||
|
|
||||||
|
val location = client.getLastLocationForBackend(entry.serviceInfo.packageName, entry.serviceInfo.name, entry.firstSignatureDigest)
|
||||||
|
?: return@launchWhenStarted
|
||||||
|
var locationString = "${location.latitude.toStringWithDigits(6)}, ${location.longitude.toStringWithDigits(6)}"
|
||||||
|
|
||||||
|
val address = client.getFromLocation(location.latitude, location.longitude, 1, Locale.getDefault().toString()).singleOrNull()
|
||||||
|
if (address != null) {
|
||||||
|
val addressLine = StringBuilder()
|
||||||
|
var i = 0
|
||||||
|
addressLine.append(address.getAddressLine(i))
|
||||||
|
while (addressLine.length < 10 && address.maxAddressLineIndex > i) {
|
||||||
|
i++
|
||||||
|
addressLine.append(", ")
|
||||||
|
addressLine.append(address.getAddressLine(i))
|
||||||
|
}
|
||||||
|
locationString = addressLine.toString()
|
||||||
|
}
|
||||||
|
binding.lastLocationString = locationString
|
||||||
|
binding.executePendingBindings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onBackendEnabledChanged(entry: BackendInfo) {
|
||||||
|
entry.enabled = !entry.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createExternalIntent(packageName: String, activityName: String): Intent {
|
||||||
|
val intent = Intent(ACTION_VIEW);
|
||||||
|
intent.setPackage(packageName);
|
||||||
|
intent.setClassName(packageName, activityName);
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startExternalActivity(packageName: String, activityName: String) {
|
||||||
|
requireContext().startActivity(createExternalIntent(packageName, activityName))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAboutClicked(entry: BackendInfo) {
|
||||||
|
entry.aboutActivity?.let { activityName -> startExternalActivity(entry.serviceInfo.packageName, activityName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onConfigureClicked(entry: BackendInfo) {
|
||||||
|
entry.settingsActivity?.let { activityName -> startExternalActivity(entry.serviceInfo.packageName, activityName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun createBackendInfo(): BackendInfo? {
|
||||||
|
val activity = activity ?: return null
|
||||||
|
val intent = activity.intent ?: return null
|
||||||
|
val type = BackendType.values().find { it.name == intent.getStringExtra(EXTRA_TYPE) }
|
||||||
|
?: return null
|
||||||
|
val packageName = intent.getStringExtra(EXTRA_PACKAGE) ?: return null
|
||||||
|
val name = intent.getStringExtra(EXTRA_NAME) ?: return null
|
||||||
|
val serviceInfo = activity.packageManager.getServiceInfo(ComponentName(packageName, name), GET_META_DATA)
|
||||||
|
?: return null
|
||||||
|
val enabledBackends = when (type) {
|
||||||
|
GEOCODER -> UnifiedLocationClient[activity].getGeocoderBackends()
|
||||||
|
LOCATION -> UnifiedLocationClient[activity].getLocationBackends()
|
||||||
|
}
|
||||||
|
return BackendInfo(activity, serviceInfo, type, lifecycleScope, enabledBackends)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ACTION = "org.microg.nlp.ui.BACKEND_DETAILS"
|
||||||
|
val EXTRA_TYPE = "org.microg.nlp.ui.BackendDetailsFragment.type"
|
||||||
|
val EXTRA_PACKAGE = "org.microg.nlp.ui.BackendDetailsFragment.package"
|
||||||
|
val EXTRA_NAME = "org.microg.nlp.ui.BackendDetailsFragment.name"
|
||||||
|
}
|
||||||
|
}
|
95
ui/src/main/kotlin/org/microg/nlp/ui/BackendInfo.kt
Normal file
95
ui/src/main/kotlin/org/microg/nlp/ui/BackendInfo.kt
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package org.microg.nlp.ui
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.databinding.BaseObservable
|
||||||
|
import androidx.databinding.Bindable
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.microg.nlp.api.Constants
|
||||||
|
import org.microg.nlp.client.UnifiedLocationClient
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.security.NoSuchAlgorithmException
|
||||||
|
|
||||||
|
private val TAG: String = "ULocUI"
|
||||||
|
|
||||||
|
class BackendInfo(val context: Context, val serviceInfo: ServiceInfo, val type: BackendType, val coroutineScope: CoroutineScope, enabledBackends: Array<String>) : BaseObservable() {
|
||||||
|
val firstSignatureDigest = firstSignatureDigest(context, serviceInfo.packageName)
|
||||||
|
val unsignedComponent: String = "${serviceInfo.packageName}/${serviceInfo.name}"
|
||||||
|
val signedComponent: String = "${serviceInfo.packageName}/${serviceInfo.name}/$firstSignatureDigest"
|
||||||
|
|
||||||
|
var enabled: Boolean = enabledBackends.contains(signedComponent) || enabledBackends.contains(unsignedComponent)
|
||||||
|
@Bindable get
|
||||||
|
set(value) {
|
||||||
|
if (field == value) return
|
||||||
|
field = value
|
||||||
|
notifyPropertyChanged(BR.enabled)
|
||||||
|
coroutineScope.launch {
|
||||||
|
val client = UnifiedLocationClient[context]
|
||||||
|
val withoutSelf = when (type) {
|
||||||
|
BackendType.LOCATION -> client.getLocationBackends()
|
||||||
|
BackendType.GEOCODER -> client.getGeocoderBackends()
|
||||||
|
}.filterNot { it == unsignedComponent || it.startsWith("$unsignedComponent/") }.toTypedArray()
|
||||||
|
val new = if (value) withoutSelf + signedComponent else withoutSelf
|
||||||
|
try {
|
||||||
|
when (type) {
|
||||||
|
BackendType.LOCATION -> client.setLocationBackends(new)
|
||||||
|
BackendType.GEOCODER -> client.setGeocoderBackends(new)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Failed to change backend state", e)
|
||||||
|
field = !value
|
||||||
|
notifyPropertyChanged(BR.enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val appIcon: Drawable by lazy { serviceInfo.loadIcon(context.packageManager) }
|
||||||
|
val name: CharSequence by lazy { serviceInfo.loadLabel(context.packageManager) }
|
||||||
|
val appName: CharSequence by lazy { serviceInfo.applicationInfo.loadLabel(context.packageManager) }
|
||||||
|
|
||||||
|
val backendSummary: String? by lazy { serviceInfo.metaData?.getString(Constants.METADATA_BACKEND_SUMMARY) }
|
||||||
|
val settingsActivity: String? by lazy { serviceInfo.metaData?.getString(Constants.METADATA_BACKEND_SETTINGS_ACTIVITY) }
|
||||||
|
val aboutActivity: String? by lazy { serviceInfo.metaData?.getString(Constants.METADATA_BACKEND_ABOUT_ACTIVITY) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class BackendType { LOCATION, GEOCODER }
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
@SuppressLint("PackageManagerGetSignatures")
|
||||||
|
fun firstSignatureDigest(context: Context, packageName: String?): String? {
|
||||||
|
val packageManager = context.packageManager
|
||||||
|
val info: PackageInfo?
|
||||||
|
try {
|
||||||
|
info = packageManager.getPackageInfo(packageName!!, PackageManager.GET_SIGNATURES)
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info?.signatures?.isNotEmpty() == true) {
|
||||||
|
for (sig in info.signatures) {
|
||||||
|
sha256sum(sig.toByteArray())?.let { return it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sha256sum(bytes: ByteArray): String? {
|
||||||
|
try {
|
||||||
|
val md = MessageDigest.getInstance("SHA-256")
|
||||||
|
val digest = md.digest(bytes)
|
||||||
|
val sb = StringBuilder(2 * digest.size)
|
||||||
|
for (b in digest) {
|
||||||
|
sb.append(String.format("%02x", b))
|
||||||
|
}
|
||||||
|
return sb.toString()
|
||||||
|
} catch (e: NoSuchAlgorithmException) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
86
ui/src/main/kotlin/org/microg/nlp/ui/BackendListFragment.kt
Normal file
86
ui/src/main/kotlin/org/microg/nlp/ui/BackendListFragment.kt
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package org.microg.nlp.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.PackageManager.GET_META_DATA
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.microg.nlp.api.Constants.*
|
||||||
|
import org.microg.nlp.client.UnifiedLocationClient
|
||||||
|
import org.microg.nlp.ui.BackendDetailsFragment.Companion.EXTRA_NAME
|
||||||
|
import org.microg.nlp.ui.BackendDetailsFragment.Companion.EXTRA_PACKAGE
|
||||||
|
import org.microg.nlp.ui.BackendDetailsFragment.Companion.EXTRA_TYPE
|
||||||
|
import org.microg.nlp.ui.databinding.BackendListBinding
|
||||||
|
import org.microg.nlp.ui.databinding.BackendListEntryBinding
|
||||||
|
|
||||||
|
class BackendListFragment : Fragment(R.layout.backend_list) {
|
||||||
|
val locationAdapter: BackendSettingsLineAdapter = BackendSettingsLineAdapter(this)
|
||||||
|
val geocoderAdapter: BackendSettingsLineAdapter = BackendSettingsLineAdapter(this)
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
val binding = BackendListBinding.inflate(inflater, container, false)
|
||||||
|
binding.fragment = this
|
||||||
|
lifecycleScope.launchWhenStarted { updateAdapters() }
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onBackendSelected(entry: BackendInfo) {
|
||||||
|
val intent = Intent(BackendDetailsFragment.ACTION)
|
||||||
|
//intent.`package` = requireContext().packageName
|
||||||
|
intent.putExtra(EXTRA_TYPE, entry.type.name)
|
||||||
|
intent.putExtra(EXTRA_PACKAGE, entry.serviceInfo.packageName)
|
||||||
|
intent.putExtra(EXTRA_NAME, entry.serviceInfo.name)
|
||||||
|
context?.packageManager?.queryIntentActivities(intent, 0)?.forEach {
|
||||||
|
Log.d("USettings", it.activityInfo.name)
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun updateAdapters() {
|
||||||
|
val context = requireContext()
|
||||||
|
locationAdapter.entries = createBackendInfoList(context, Intent(ACTION_LOCATION_BACKEND), UnifiedLocationClient[context].getLocationBackends(), BackendType.LOCATION)
|
||||||
|
geocoderAdapter.entries = createBackendInfoList(context, Intent(ACTION_GEOCODER_BACKEND), UnifiedLocationClient[context].getGeocoderBackends(), BackendType.GEOCODER)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createBackendInfoList(context: Context, intent: Intent, enabledBackends: Array<String>, type: BackendType): Array<BackendInfo> {
|
||||||
|
val backends = context.packageManager.queryIntentServices(intent, GET_META_DATA).map { BackendInfo(context, it.serviceInfo, type, lifecycleScope, enabledBackends) }
|
||||||
|
return backends.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackendSettingsLineViewHolder(val binding: BackendListEntryBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(fragment: BackendListFragment, entry: BackendInfo) {
|
||||||
|
binding.fragment = fragment
|
||||||
|
binding.entry = entry
|
||||||
|
binding.executePendingBindings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BackendSettingsLineAdapter(val fragment: BackendListFragment) : RecyclerView.Adapter<BackendSettingsLineViewHolder>() {
|
||||||
|
var entries: Array<BackendInfo> = emptyArray()
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackendSettingsLineViewHolder {
|
||||||
|
return BackendSettingsLineViewHolder(BackendListEntryBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: BackendSettingsLineViewHolder, position: Int) {
|
||||||
|
holder.bind(fragment, entries[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int {
|
||||||
|
return entries.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
301
ui/src/main/res/layout/backend_details.xml
Normal file
301
ui/src/main/res/layout/backend_details.xml
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="android.view.View" />
|
||||||
|
|
||||||
|
<import type="org.microg.nlp.ui.BackendType" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="fragment"
|
||||||
|
type="org.microg.nlp.ui.BackendDetailsFragment" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="entry"
|
||||||
|
type="org.microg.nlp.ui.BackendInfo" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="lastLocationString"
|
||||||
|
type="String" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingTop="24dp"
|
||||||
|
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?attr/listPreferredItemPaddingRight"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:antialias="true"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@{entry.appIcon}"
|
||||||
|
tools:src="@android:mipmap/sym_def_app_icon" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:gravity="center"
|
||||||
|
android:singleLine="false"
|
||||||
|
android:text='@{entry.name}'
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:textSize="20sp"
|
||||||
|
tools:text="Mozilla Location Service" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_name"
|
||||||
|
style="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:text='@{entry.appName ?? ""}'
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:visibility='@{entry != null && entry.appName == entry.name ? View.GONE : View.VISIBLE}'
|
||||||
|
tools:text="Mozilla UnifiedNlp Backend" />
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="center"
|
||||||
|
android:onClick="@{() -> fragment.onBackendEnabledChanged(entry)}"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?attr/listPreferredItemPaddingRight"
|
||||||
|
app:backgroundColor="@{entry.enabled ? fragment.switchBarEnabledColor : fragment.switchBarDisabledColor}"
|
||||||
|
tools:background="?attr/colorAccent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/switch_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:paddingStart="56dp"
|
||||||
|
android:paddingLeft="56dp"
|
||||||
|
android:text="Use backend"
|
||||||
|
android:textAppearance="?attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorPrimaryInverse" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:id="@+id/switch_widget"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:background="@null"
|
||||||
|
android:checked="@={entry.enabled}"
|
||||||
|
app:thumbTint="?android:attr/textColorPrimaryInverse"
|
||||||
|
tools:checked="true" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/settingsLauncher"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:minHeight="?attr/listPreferredItemHeightSmall"
|
||||||
|
android:onClick="@{() -> fragment.onConfigureClicked(entry)}"
|
||||||
|
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?attr/listPreferredItemPaddingRight"
|
||||||
|
android:visibility='@{entry == null || entry.settingsActivity == null ? View.GONE : View.VISIBLE}'>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="56dp"
|
||||||
|
android:paddingLeft="56dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="Configure"
|
||||||
|
android:textAppearance="?attr/textAppearanceListItem" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/aboutLauncher"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:minHeight="?attr/listPreferredItemHeightSmall"
|
||||||
|
android:onClick="@{() -> fragment.onAboutClicked(entry)}"
|
||||||
|
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?attr/listPreferredItemPaddingRight"
|
||||||
|
android:visibility='@{entry == null || entry.aboutActivity == null ? View.GONE : View.VISIBLE}'>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="56dp"
|
||||||
|
android:paddingLeft="56dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/about_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text='About'
|
||||||
|
android:textAppearance="?attr/textAppearanceListItem" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?attr/dividerHorizontal"
|
||||||
|
android:visibility='@{entry == null || (entry.backendSummary == null || entry.type != BackendType.LOCATION) || (entry.settingsActivity == null && entry.aboutActivity == null) ? View.GONE : View.VISIBLE}' />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:minHeight="?attr/listPreferredItemHeightSmall"
|
||||||
|
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?attr/listPreferredItemPaddingRight"
|
||||||
|
android:visibility='@{entry == null || entry.backendSummary == null ? View.GONE : View.VISIBLE}'>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="56dp"
|
||||||
|
android:paddingLeft="56dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="Description"
|
||||||
|
android:textAppearance="?attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/summary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/description_title"
|
||||||
|
android:layout_alignStart="@id/description_title"
|
||||||
|
android:layout_alignLeft="@id/description_title"
|
||||||
|
android:maxLines="10"
|
||||||
|
android:text='@{entry.backendSummary ?? ""}'
|
||||||
|
android:textAppearance="?attr/textAppearanceListItemSecondary"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
tools:text="Locate using Mozilla\'s online database" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:minHeight="?attr/listPreferredItemHeightSmall"
|
||||||
|
android:paddingStart="?attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?attr/listPreferredItemPaddingRight"
|
||||||
|
android:visibility='@{lastLocationString == null ? View.GONE : View.VISIBLE}'>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="56dp"
|
||||||
|
android:paddingLeft="56dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/last_location_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="Last location"
|
||||||
|
android:textAppearance="?attr/textAppearanceListItem"
|
||||||
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/last_location"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/last_location_title"
|
||||||
|
android:layout_alignStart="@id/last_location_title"
|
||||||
|
android:layout_alignLeft="@id/last_location_title"
|
||||||
|
android:maxLines="10"
|
||||||
|
android:text='@{lastLocationString ?? ""}'
|
||||||
|
android:textAppearance="?attr/textAppearanceListItemSecondary"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
tools:text="Main St 23" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
101
ui/src/main/res/layout/backend_list.xml
Normal file
101
ui/src/main/res/layout/backend_list.xml
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="fragment"
|
||||||
|
type="org.microg.nlp.ui.BackendListFragment" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?android:attr/listPreferredItemPaddingRight">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:letterSpacing="0.073"
|
||||||
|
android:paddingStart="56dp"
|
||||||
|
android:paddingLeft="56dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/network_location"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
|
||||||
|
android:textColor="?attr/colorAccent"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/network_location_backend_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:adapter="@{fragment.locationAdapter}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="2"
|
||||||
|
tools:listitem="@layout/backend_list_entry" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/dividerHorizontal" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?android:attr/listPreferredItemPaddingRight">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:paddingStart="56dp"
|
||||||
|
android:paddingLeft="56dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/geocoding"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
|
||||||
|
android:textColor="?attr/colorAccent"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/geocoding_backend_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:adapter="@{fragment.geocoderAdapter}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="1"
|
||||||
|
tools:listitem="@layout/backend_list_entry" />
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
113
ui/src/main/res/layout/backend_list_entry.xml
Normal file
113
ui/src/main/res/layout/backend_list_entry.xml
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2020, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<import type="android.view.View" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="fragment"
|
||||||
|
type="org.microg.nlp.ui.BackendListFragment" />
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="entry"
|
||||||
|
type="org.microg.nlp.ui.BackendInfo" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:focusable="true"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:onClick="@{() -> fragment.onBackendSelected(entry)}"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:paddingRight="?android:attr/listPreferredItemPaddingRight">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/icon_frame"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:minWidth="56dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:src="@{entry.appIcon}"
|
||||||
|
tools:src="@android:mipmap/sym_def_app_icon" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text='@{entry.name}'
|
||||||
|
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||||
|
tools:text="Mozilla Location Service" />
|
||||||
|
</RelativeLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/two_target_divider"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="64dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.SwitchCompat
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:checked="@={entry.enabled}"
|
||||||
|
android:minWidth="80dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
10
ui/src/main/res/values-de/strings.xml
Normal file
10
ui/src/main/res/values-de/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Funknetz-basierte Ortung</string>
|
||||||
|
<string name="geocoding">Adressauflösung</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-eo/strings.xml
Normal file
10
ui/src/main/res/values-eo/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Ret-bazita pozici-trovado</string>
|
||||||
|
<string name="geocoding">Adres-elserĉado</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-fr/strings.xml
Normal file
10
ui/src/main/res/values-fr/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Géolocalisation réseau</string>
|
||||||
|
<string name="geocoding">Géocodage</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-pl/strings.xml
Normal file
10
ui/src/main/res/values-pl/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Geolokalizacja oparta o sieć</string>
|
||||||
|
<string name="geocoding">Wyszukiwanie adresów</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-ro/strings.xml
Normal file
10
ui/src/main/res/values-ro/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Localizare geografică bazată pe rețea</string>
|
||||||
|
<string name="geocoding">Căutare adrese</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-ru/strings.xml
Normal file
10
ui/src/main/res/values-ru/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Местоположение по сети</string>
|
||||||
|
<string name="geocoding">Поиск адреса</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-sr/strings.xml
Normal file
10
ui/src/main/res/values-sr/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Мрежна геолокација</string>
|
||||||
|
<string name="geocoding">Потрага адресе</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-uk/strings.xml
Normal file
10
ui/src/main/res/values-uk/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Географічне позиціювання на основі мереж</string>
|
||||||
|
<string name="geocoding">Пошук адрес</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values-zh-rTW/strings.xml
Normal file
10
ui/src/main/res/values-zh-rTW/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">基於網路的地理位置定位</string>
|
||||||
|
<string name="geocoding">地址查閱</string>
|
||||||
|
</resources>
|
10
ui/src/main/res/values/strings.xml
Normal file
10
ui/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ SPDX-FileCopyrightText: 2014, microG Project Team
|
||||||
|
~ SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="network_location">Network-based Geolocation</string>
|
||||||
|
<string name="geocoding">Address lookup</string>
|
||||||
|
</resources>
|
Loading…
Reference in a new issue