Compare commits

...

28 Commits

Author SHA1 Message Date
johan12345
23387ae371 Release 1.0.0 2021-10-02 14:08:44 +02:00
johan12345
25f466b6d7 Merge branch 'place-search-recents' 2021-10-02 13:49:25 +02:00
johan12345
6692b21bf9 add non-dark Mapbox logo 2021-10-02 13:48:50 +02:00
johan12345
5959fe8be4 limit number of autocomplete results 2021-10-02 13:40:22 +02:00
johan12345
00f4c13fcc add button to delete search history 2021-10-02 13:33:51 +02:00
johan12345
47054d470b replace deprecated method getAdapterPosition 2021-10-02 13:23:30 +02:00
Johan von Forstner
d10192cae1 save recent place search results
fixes #128
2021-10-02 13:19:33 +02:00
johan12345
e1b90955c3 handle back button correctly
fixes #115
2021-10-02 13:18:27 +02:00
johan12345
d249bf47c7 improve title of filter profiles editing 2021-10-02 13:15:58 +02:00
johan12345
738dcd5f8d do not allow blank names for filter profiles 2021-10-02 13:11:05 +02:00
johan12345
ad4f32ec32 fix missing filter name in title of FilterFragment 2021-10-02 12:47:22 +02:00
Johan von Forstner
4d03107ae7 add links to translated FAQ and privacy policy
#110
2021-09-26 16:17:44 +02:00
Johan von Forstner
0e93e310bf MultiSelectDialog: move selected entries to the top
fixes #126
2021-09-26 16:17:44 +02:00
Johan von Forstner
6cb8940696 Catch IllegalArgumentException in navigation library 2021-09-26 14:47:55 +02:00
johan12345
dad30eb51e Release 1.0.0-beta04 2021-09-19 19:37:52 +02:00
johan12345
abf6a2b933 upgrade some dependencies 2021-09-19 19:28:26 +02:00
johan12345
2c5685d918 Android Auto: use smartphone location even with car API level 3
if car hardware location is not available
2021-09-19 19:25:59 +02:00
johan12345
b61e57b022 Android Auto: fix crash when filter profile has no name 2021-09-19 19:25:59 +02:00
Johan von Forstner
e6428cc8db Merge pull request #125 from johan12345/android-12
Update to Android 12 targetSdkVersion and implement corresponding changes
2021-09-12 21:39:39 +02:00
johan12345
6302006a35 Android 12 compat: implement new SplashScreen API
with animated icon
update onboarding to avoid showing animation twice
2021-09-12 21:21:17 +02:00
johan12345
ab93577a98 Android 12 compat: support for approximate location permission (#123) 2021-09-12 21:21:17 +02:00
johan12345
98b695ed4b Android 12 compat: set exported attribute explicitly (#123)
for services and activities in Manifest
2021-09-12 18:48:15 +02:00
johan12345
ed8cb50b08 increase targetSdk to Android 12 (API 31) (#123) 2021-09-12 18:48:14 +02:00
johan12345
88d89c2760 fix crash in FavoritesFragment.onDestroy
apparently it can be called before onCreate?
2021-09-12 18:00:07 +02:00
johan12345
80c25cb416 build.gradle: add possibility to pass encrypted Mapbox API Key 2021-09-12 12:23:25 +02:00
johan12345
81c8e54dd2 Release 1.0.0-beta03 2021-09-12 11:49:09 +02:00
johan12345
8c01ee1581 shorten error message on Android Auto 2021-09-12 11:48:28 +02:00
johan12345
e8db5acfbf Check if Android Auto Version >= 6.7 before using Car API Level 3 2021-09-12 11:46:15 +02:00
51 changed files with 998 additions and 204 deletions

View File

@@ -12,9 +12,9 @@ android {
defaultConfig {
applicationId "net.vonforst.evmap"
minSdkVersion 21
targetSdkVersion 30
versionCode 60
versionName "1.0.0-beta02"
targetSdkVersion 31
versionCode 63
versionName "1.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -89,6 +89,9 @@ android {
variant.resValue "string", "google_maps_key", googleMapsKey
}
def mapboxKey = env.MAPBOX_API_KEY ?: project.findProperty("MAPBOX_API_KEY")
if (mapboxKey == null && project.hasProperty("MAPBOX_API_KEY_ENCRYPTED")) {
mapboxKey = decode(project.findProperty("MAPBOX_API_KEY_ENCRYPTED"), "FmK.d,-f*p+rD+WK!eds")
}
if (mapboxKey != null) {
variant.resValue "string", "mapbox_key", mapboxKey
}
@@ -105,15 +108,16 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.core:core-ktx:1.5.0'
implementation "androidx.activity:activity-ktx:1.2.3"
implementation "androidx.fragment:fragment-ktx:1.3.4"
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.core:core-splashscreen:1.0.0-alpha01'
implementation "androidx.activity:activity-ktx:1.3.1"
implementation "androidx.fragment:fragment-ktx:1.3.6"
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'com.google.android.material:material:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.recyclerview:recyclerview:1.2.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.browser:browser:1.3.0'
implementation 'com.github.johan12345:CustomBottomSheetBehavior:f69f532660'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
@@ -196,12 +200,12 @@ dependencies {
// debug tools
implementation 'com.facebook.stetho:stetho:1.5.1'
implementation 'com.facebook.stetho:stetho-okhttp3:1.5.1'
testImplementation 'junit:junit:4.13'
testImplementation 'junit:junit:4.13.1'
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.0"
//noinspection GradleDependency
testImplementation 'org.json:json:20080701'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.12.0"

View File

@@ -10,6 +10,10 @@
<uses-sdk tools:overrideLibrary="androidx.car.app,androidx.car.app.projected" />
<queries>
<package android:name="com.google.android.projection.gearhead" />
</queries>
<application>
<meta-data
android:name="com.google.android.geo.API_KEY"
@@ -42,6 +46,7 @@
<service
android:name=".auto.CarLocationService"
android:foregroundServiceType="location"
android:enabled="true" />
android:enabled="true"
android:exported="false" />
</application>
</manifest>

View File

@@ -1,9 +1,7 @@
package net.vonforst.evmap.auto
import android.Manifest
import android.content.*
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.location.Location
import android.os.IBinder
import androidx.car.app.CarContext
@@ -13,12 +11,12 @@ import androidx.car.app.hardware.CarHardwareManager
import androidx.car.app.hardware.info.CarHardwareLocation
import androidx.car.app.hardware.info.CarSensors
import androidx.car.app.validation.HostValidator
import androidx.car.app.versioning.CarAppApiLevels
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import net.vonforst.evmap.utils.checkAnyLocationPermission
interface LocationAwareScreen {
@@ -73,11 +71,7 @@ class EVMapSession(val cas: CarAppService) : Session(), LifecycleObserver {
return WelcomeScreen(carContext, this)
}
fun locationPermissionGranted() =
ContextCompat.checkSelfPermission(
carContext,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
fun locationPermissionGranted() = carContext.checkAnyLocationPermission()
private val locationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -96,37 +90,43 @@ class EVMapSession(val cas: CarAppService) : Session(), LifecycleObserver {
private fun onCarHardwareLocationReceived(loc: CarHardwareLocation) {
updateLocation(loc.location.value)
locationService?.let { service ->
// we successfully received a location from the car hardware,
// so we don't need the smartphone location anymore.
service.removeLocationUpdates()
cas.unbindService(serviceConnection)
locationService = null
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun bindLocationService() {
if (!locationPermissionGranted()) return
if (carContext.carAppApiLevel >= CarAppApiLevels.LEVEL_3) {
if (supportsCarApiLevel3(carContext)) {
val exec = ContextCompat.getMainExecutor(carContext)
hardwareMan.carSensors.addCarHardwareLocationListener(
CarSensors.UPDATE_RATE_NORMAL,
exec,
::onCarHardwareLocationReceived
)
} else {
cas.bindService(
Intent(cas, CarLocationService::class.java),
serviceConnection,
Context.BIND_AUTO_CREATE
)
}
cas.bindService(
Intent(cas, CarLocationService::class.java),
serviceConnection,
Context.BIND_AUTO_CREATE
)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private fun unbindLocationService() {
if (carContext.carAppApiLevel >= CarAppApiLevels.LEVEL_3) {
locationService?.let { service ->
service.removeLocationUpdates()
cas.unbindService(serviceConnection)
}
} else {
if (supportsCarApiLevel3(carContext)) {
hardwareMan.carSensors.removeCarHardwareLocationListener(::onCarHardwareLocationReceived)
}
locationService?.let { service ->
service.removeLocationUpdates()
cas.unbindService(serviceConnection)
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)

View File

@@ -11,7 +11,6 @@ import androidx.car.app.Screen
import androidx.car.app.hardware.CarHardwareManager
import androidx.car.app.hardware.info.Model
import androidx.car.app.model.*
import androidx.car.app.versioning.CarAppApiLevels
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.lifecycle.lifecycleScope
@@ -148,7 +147,7 @@ class ChargepriceScreen(ctx: CarContext, val charger: ChargeLocation) : Screen(c
}
private fun loadData() {
if (carContext.carAppApiLevel >= CarAppApiLevels.LEVEL_3) {
if (supportsCarApiLevel3(carContext)) {
val exec = ContextCompat.getMainExecutor(carContext)
val hardwareMan =
carContext.getCarService(CarContext.HARDWARE_SERVICE) as CarHardwareManager

View File

@@ -68,7 +68,9 @@ class FilterScreen(ctx: CarContext) : Screen(ctx) {
}.build())
profiles.forEach {
addItem(Row.Builder().apply {
setTitle(it.name)
val name =
it.name.ifEmpty { carContext.getString(R.string.unnamed_filter_profile) }
setTitle(name)
if (it.id == filterStatus) {
setImage(checkIcon)
} else {

View File

@@ -1,11 +1,13 @@
package net.vonforst.evmap.auto
import android.content.Context
import android.graphics.Bitmap
import androidx.car.app.CarContext
import androidx.car.app.constraints.ConstraintManager
import androidx.car.app.hardware.common.CarUnit
import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.versioning.CarAppApiLevels
import androidx.core.graphics.drawable.IconCompat
import net.vonforst.evmap.api.availability.ChargepointStatus
import java.util.*
@@ -68,4 +70,24 @@ fun formatCarUnitSpeed(value: Float?, unit: Int?): String {
CarUnit.MILES_PER_HOUR -> "%.0f mph".format(value * 3.6 / kmPerMile)
else -> ""
}
}
fun getAndroidAutoVersion(ctx: Context): List<String> {
val info = ctx.packageManager.getPackageInfo("com.google.android.projection.gearhead", 0)
return info.versionName.split(".")
}
fun supportsCarApiLevel3(ctx: CarContext): Boolean {
if (ctx.carAppApiLevel < CarAppApiLevels.LEVEL_3) return false
ctx.hostInfo?.let { hostInfo ->
if (hostInfo.packageName == "com.google.android.projection.gearhead") {
val version = getAndroidAutoVersion(ctx)
// Android Auto 6.7 is required. 6.6 reports supporting API Level 3,
// but crashes when using it. See: https://issuetracker.google.com/issues/199509584
if (version[0] < "6" || version[0] == "6" && version[1] < "7") {
return false
}
}
}
return true
}

View File

@@ -7,7 +7,6 @@ import android.os.Looper
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.*
import androidx.car.app.versioning.CarAppApiLevels
import androidx.core.graphics.drawable.IconCompat
import net.vonforst.evmap.R
@@ -24,7 +23,10 @@ class WelcomeScreen(ctx: CarContext, val session: EVMapSession) : Screen(ctx), L
PermissionScreen(
carContext,
R.string.auto_location_permission_needed,
listOf(Manifest.permission.ACCESS_FINE_LOCATION)
listOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
) {
session.bindLocationService()
@@ -82,7 +84,7 @@ class WelcomeScreen(ctx: CarContext, val session: EVMapSession) : Screen(ctx), L
screenManager.push(MapScreen(carContext, session, favorites = true))
}
.build())
if (carContext.carAppApiLevel >= CarAppApiLevels.LEVEL_3) {
if (supportsCarApiLevel3(carContext)) {
addItem(
Row.Builder()
.setTitle(carContext.getString(R.string.auto_vehicle_data))

View File

@@ -28,6 +28,8 @@ class GooglePlacesAutocompleteProvider(val context: Context) : AutocompleteProvi
private val client = Places.createClient(context)
private val bold: CharacterStyle = StyleSpan(Typeface.BOLD)
override val id = "google"
override fun autocomplete(
query: String,
location: com.car2go.maps.model.LatLng?
@@ -48,7 +50,7 @@ class GooglePlacesAutocompleteProvider(val context: Context) : AutocompleteProvi
it.getPrimaryText(bold),
it.getSecondaryText(bold),
it.placeId,
it.distanceMeters,
it.distanceMeters?.toDouble(),
it.placeTypes.map { AutocompletePlaceType.valueOf(it.name) })
}
} catch (e: ExecutionException) {

View File

@@ -31,6 +31,6 @@
<string name="welcome_android_auto_detail">Auf unterstützen Autos kannst du EVMap auch mit Android Auto nutzen. Öffne dazu einfach die EVMap-App aus dem Menü von Android Auto.</string>
<string name="sounds_cool">klingt cool</string>
<string name="auto_chargeprice_vehicle_unavailable">EVMap konnte das Fahrzeugmodell nicht erkennen.</string>
<string name="auto_chargeprice_vehicle_unknown">Keins der in der App ausgewählten Fahrzeuge passt zu diesem Fahrzeug (%s %s). Bitte wähle in der App ein passendes Fahrzeug aus.</string>
<string name="auto_chargeprice_vehicle_ambiguous">Mehrere der in der App ausgewählten Fahrzeuge passen zu diesem Fahrzeug (%s %s). Bitte wähle nur ein passendes Fahrzeug in der App aus.</string>
<string name="auto_chargeprice_vehicle_unknown">Keins der in der App ausgewählten Fahrzeuge passt zu diesem Fahrzeug (%s %s).</string>
<string name="auto_chargeprice_vehicle_ambiguous">Mehrere der in der App ausgewählten Fahrzeuge passen zu diesem Fahrzeug (%s %s).</string>
</resources>

View File

@@ -41,6 +41,6 @@
<string name="welcome_android_auto_detail">You can also use EVMap from within Android Auto on supported cars. Simply select the EVMap app in the Android Auto menu.</string>
<string name="sounds_cool">sounds cool</string>
<string name="auto_chargeprice_vehicle_unavailable">EVMap could not determine your vehicle model.</string>
<string name="auto_chargeprice_vehicle_unknown">None of the vehicles selected in the app matches this vehicle (%s %s). Please select a matching vehicle from the app.</string>
<string name="auto_chargeprice_vehicle_ambiguous">Mehrere der in der App ausgewählten Fahrzeuge passen zu diesem Fahrzeug (%s %s). Bitte wähle nur ein passendes Fahrzeug in der App aus.</string>
<string name="auto_chargeprice_vehicle_unknown">None of the vehicles selected in the app matches this vehicle (%s %s).</string>
<string name="auto_chargeprice_vehicle_ambiguous">Mehrere der in der App ausgewählten Fahrzeuge passen zu diesem Fahrzeug (%s %s).</string>
</resources>

View File

@@ -3,6 +3,7 @@
package="net.vonforst.evmap">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<queries>
@@ -32,7 +33,8 @@
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps"
android:theme="@style/AppTheme.LaunchScreen">
android:theme="@style/AppTheme.LaunchScreen"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -256,6 +258,16 @@
</intent-filter>
</activity>
<!-- Override services of the com.mapzen.android.lost library with exported:false
until https://github.com/lostzen/lost/pull/270 is merged -->
<service
android:name="com.mapzen.android.lost.internal.GeofencingIntentService"
android:exported="false">
<intent-filter>
<action android:name="com.mapzen.lost.action.ACTION_GEOFENCING_SERVICE" />
</intent-filter>
</service>
</application>
</manifest>

View File

@@ -4,12 +4,16 @@ import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.SystemClock
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import androidx.core.splashscreen.SplashScreen
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.drawerlayout.widget.DrawerLayout
@@ -51,9 +55,8 @@ class MapsActivity : AppCompatActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
// set theme to AppTheme to end launch screen
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
val splashScreen = installSplashScreen()
setContentView(R.layout.activity_maps)
@@ -82,8 +85,23 @@ class MapsActivity : AppCompatActivity() {
checkPlayServices(this)
if (!prefs.welcomeDialogShown || !prefs.dataSourceSet) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// wait for splash screen animation to finish on first start
splashScreen.setKeepVisibleCondition(object : SplashScreen.KeepOnScreenCondition {
var startTime: Long? = null
override fun shouldKeepOnScreen(): Boolean {
val st = startTime
if (st == null) {
startTime = SystemClock.uptimeMillis()
return true
} else {
return (SystemClock.uptimeMillis() - st) < 1000
}
}
})
}
navGraph.startDestination = R.id.onboarding
navController.graph = navGraph
return

View File

@@ -1,6 +1,8 @@
package net.vonforst.evmap.adapter
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -13,7 +15,10 @@ import net.vonforst.evmap.autocomplete.*
import net.vonforst.evmap.containsAny
import net.vonforst.evmap.databinding.ItemAutocompleteResultBinding
import net.vonforst.evmap.isDarkMode
import net.vonforst.evmap.storage.AppDatabase
import net.vonforst.evmap.storage.PreferenceDataSource
import net.vonforst.evmap.storage.RecentAutocompletePlace
import java.time.Instant
class PlaceAutocompleteAdapter(val context: Context, val location: LiveData<LatLng>) :
BaseAdapter(), Filterable {
@@ -21,7 +26,10 @@ class PlaceAutocompleteAdapter(val context: Context, val location: LiveData<LatL
private val providers = getAutocompleteProviders(context)
private val typeItem = 0
private val typeAttribution = 1
var currentProvider: AutocompleteProvider? = null
private val maxItems = 6
private var currentProvider: AutocompleteProvider? = null
private val recents = AppDatabase.getInstance(context).recentAutocompletePlaceDao()
private var recentResults = mutableListOf<RecentAutocompletePlace>()
data class ViewHolder(val binding: ItemAutocompleteResultBinding)
@@ -103,20 +111,40 @@ class PlaceAutocompleteAdapter(val context: Context, val location: LiveData<LatL
}
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filterResults = FilterResults()
val query = constraint.toString()
if (constraint != null) {
for (provider in providers) {
try {
resultList =
provider.autocomplete(constraint.toString(), location.value)
recentResults.clear()
currentProvider = provider
// first search in recent places
val recentPlaces = if (query.isEmpty()) {
recents.getAll(provider.id, limit = maxItems)
} else {
recents.search(query, provider.id, limit = maxItems)
}
recentResults.addAll(recentPlaces)
resultList = recentPlaces.map { it.asAutocompletePlace(location.value) }
Handler(Looper.getMainLooper()).post {
// publish intermediate results on main thread
publishResults(constraint, resultList.asFilterResults())
}
// if we already have enough results or the query is short, stop here
if (query.length < 3 || recentResults.size >= maxItems) break
// then search online
val recentIds = recentPlaces.map { it.id }
resultList =
(recentPlaces.map { it.asAutocompletePlace(location.value) } +
provider.autocomplete(query, location.value)
.filter { !recentIds.contains(it.id) }).take(maxItems)
break
} catch (e: ApiUnavailableException) {
e.printStackTrace()
}
}
filterResults.values = resultList
filterResults.count = resultList!!.size
}
@@ -125,16 +153,42 @@ class PlaceAutocompleteAdapter(val context: Context, val location: LiveData<LatL
this.setDelayer { 500L }
}
return filterResults
return resultList.asFilterResults()
}
private fun List<AutocompletePlace>?.asFilterResults(): FilterResults {
val result = FilterResults()
if (this != null) {
result.values = this
result.count = this.size
}
return result
}
}
}
suspend fun getDetails(id: String): PlaceWithBounds {
val provider = currentProvider!!
val result = resultList!!.find { it.id == id }!!
val recentPlace = recentResults.find { it.id == id }
if (recentPlace != null) return recentPlace.asPlaceWithBounds()
val details = provider.getDetails(id)
recents.insert(RecentAutocompletePlace(result, details, provider.id, Instant.now()))
return details
}
}
fun iconForPlaceType(types: List<AutocompletePlaceType>): Int =
when {
types.contains(
AutocompletePlaceType.RECENT
) -> R.drawable.ic_history
types.containsAny(
AutocompletePlaceType.LIGHT_RAIL_STATION,
AutocompletePlaceType.BUS_STATION,
@@ -153,4 +207,7 @@ fun iconForPlaceType(types: List<AutocompletePlaceType>): Int =
}
fun isSpecialPlace(types: List<AutocompletePlaceType>): Boolean =
iconForPlaceType(types) != R.drawable.ic_place_type_default
!setOf(
R.drawable.ic_place_type_default,
R.drawable.ic_history
).contains(iconForPlaceType(types))

View File

@@ -6,6 +6,8 @@ import com.car2go.maps.model.LatLng
import com.car2go.maps.model.LatLngBounds
interface AutocompleteProvider {
val id: String
fun autocomplete(query: String, location: LatLng?): List<AutocompletePlace>
suspend fun getDetails(id: String): PlaceWithBounds
@@ -20,7 +22,7 @@ data class AutocompletePlace(
val primaryText: CharSequence,
val secondaryText: CharSequence,
val id: String,
val distanceMeters: Int?,
val distanceMeters: Double?,
val types: List<AutocompletePlaceType>
)
@@ -167,7 +169,8 @@ enum class AutocompletePlaceType {
TRAVEL_AGENCY,
UNIVERSITY,
VETERINARY_CARE,
ZOO;
ZOO,
RECENT;
companion object {
fun valueOfOrNull(value: String): AutocompletePlaceType? {

View File

@@ -17,12 +17,13 @@ import com.mapbox.geojson.BoundingBox
import com.mapbox.geojson.Point
import net.vonforst.evmap.R
import java.io.IOException
import kotlin.math.roundToInt
class MapboxAutocompleteProvider(val context: Context) : AutocompleteProvider {
private val bold: CharacterStyle = StyleSpan(Typeface.BOLD)
private val results = HashMap<String, CarmenFeature>()
override val id = "mapbox"
override fun autocomplete(query: String, location: LatLng?): List<AutocompletePlace> {
val result = MapboxGeocoding.builder().apply {
location?.let {
@@ -58,7 +59,7 @@ class MapboxAutocompleteProvider(val context: Context) : AutocompleteProvider {
location?.let { location ->
SphericalUtil.computeDistanceBetween(
feature.center()!!.toLatLng(), location
).roundToInt()
)
},
getPlaceTypes(feature)
)
@@ -112,7 +113,8 @@ class MapboxAutocompleteProvider(val context: Context) : AutocompleteProvider {
override fun getAttributionString(): Int = R.string.powered_by_mapbox
override fun getAttributionImage(dark: Boolean): Int = R.drawable.mapbox_logo_icon
override fun getAttributionImage(dark: Boolean): Int =
if (dark) R.drawable.mapbox_logo_icon else R.drawable.mapbox_logo
}
private fun BoundingBox.toLatLngBounds(): LatLngBounds {

View File

@@ -1,7 +1,5 @@
package net.vonforst.evmap.fragment
import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Canvas
import android.os.Bundle
import android.view.Gravity
@@ -9,7 +7,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
@@ -30,12 +27,13 @@ import net.vonforst.evmap.adapter.FavoritesAdapter
import net.vonforst.evmap.databinding.FragmentFavoritesBinding
import net.vonforst.evmap.databinding.ItemFavoriteBinding
import net.vonforst.evmap.model.ChargeLocation
import net.vonforst.evmap.utils.checkAnyLocationPermission
import net.vonforst.evmap.viewmodel.FavoritesViewModel
import net.vonforst.evmap.viewmodel.viewModelFactory
class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
private lateinit var binding: FragmentFavoritesBinding
private lateinit var locationClient: LostApiClient
private var locationClient: LostApiClient? = null
private var toDelete: ChargeLocation? = null
private var deleteSnackbar: Snackbar? = null
private lateinit var adapter: FavoritesAdapter
@@ -59,7 +57,7 @@ class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_favorites, container, false
@@ -95,17 +93,13 @@ class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
}
createTouchHelper().attachToRecyclerView(binding.favsList)
locationClient.connect()
locationClient!!.connect()
}
override fun onConnected() {
val context = this.context ?: return
if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
val location = LocationServices.FusedLocationApi.getLastLocation(locationClient)
if (context.checkAnyLocationPermission()) {
val location = LocationServices.FusedLocationApi.getLastLocation(locationClient!!)
if (location != null) {
vm.location.value = LatLng(location.latitude, location.longitude)
}
@@ -118,8 +112,8 @@ class FavoritesFragment : Fragment(), LostApiClient.ConnectionCallbacks {
override fun onDestroy() {
super.onDestroy()
if (locationClient.isConnected) {
locationClient.disconnect()
locationClient?.let {
if (it.isConnected) it.disconnect()
}
}

View File

@@ -43,12 +43,6 @@ class FilterFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
(requireActivity() as AppCompatActivity).setSupportActionBar(binding.toolbar)
vm.filterProfile.observe(viewLifecycleOwner) {
if (it != null) {
binding.toolbar.title = "${getString(R.string.menu_filter)}: ${it.name}"
}
}
binding.filtersList.apply {
adapter = FiltersAdapter()
layoutManager =
@@ -80,34 +74,52 @@ class FilterFragment : Fragment() {
true
}
R.id.menu_save_profile -> {
showEditTextDialog(requireContext()) { dialog, input ->
vm.filterProfile.value?.let { profile ->
input.setText(profile.name)
}
dialog.setTitle(R.string.save_as_profile)
.setMessage(R.string.save_profile_enter_name)
.setPositiveButton(R.string.ok) { di, button ->
lifecycleScope.launch {
vm.saveAsProfile(input.text.toString())
findNavController().popBackStack()
}
}
.setNegativeButton(R.string.cancel) { di, button ->
}
}
saveProfile()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun saveProfile(error: Boolean = false) {
showEditTextDialog(requireContext()) { dialog, input ->
vm.filterProfile.value?.let { profile ->
input.setText(profile.name)
}
if (error) {
input.error = getString(R.string.required)
}
dialog.setTitle(R.string.save_as_profile)
.setMessage(R.string.save_profile_enter_name)
.setPositiveButton(R.string.ok) { di, button ->
if (input.text.isBlank()) {
saveProfile(true)
} else {
lifecycleScope.launch {
vm.saveAsProfile(input.text.toString())
findNavController().popBackStack()
}
}
}
.setNegativeButton(R.string.cancel) { di, button ->
}
}
}
override fun onResume() {
super.onResume()
binding.toolbar.setupWithNavController(
findNavController(),
(requireActivity() as MapsActivity).appBarConfiguration
)
vm.filterProfile.observe(viewLifecycleOwner) {
if (it != null) {
binding.toolbar.title = getString(R.string.edit_filter_profile, it.name)
}
}
}
}

View File

@@ -67,8 +67,8 @@ class FilterProfilesFragment : Fragment() {
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val fromPos = viewHolder.adapterPosition;
val toPos = target.adapterPosition;
val fromPos = viewHolder.bindingAdapterPosition;
val toPos = target.bindingAdapterPosition;
val list = vm.filterProfiles.value?.toMutableList()
if (list != null) {

View File

@@ -1,5 +1,6 @@
package net.vonforst.evmap.fragment
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.annotation.SuppressLint
import android.content.Context
@@ -81,6 +82,8 @@ import net.vonforst.evmap.ui.ClusterIconGenerator
import net.vonforst.evmap.ui.MarkerAnimator
import net.vonforst.evmap.ui.getMarkerTint
import net.vonforst.evmap.utils.boundingBox
import net.vonforst.evmap.utils.checkAnyLocationPermission
import net.vonforst.evmap.utils.checkFineLocationPermission
import net.vonforst.evmap.utils.distanceBetween
import net.vonforst.evmap.viewmodel.*
import java.io.IOException
@@ -239,6 +242,8 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
findNavController().navigate(R.id.action_map_to_opensource_donations)
} catch (ignored: IllegalArgumentException) {
// when there is already another navigation going on
} catch (ignored: IllegalStateException) {
// "no current navigation node"
}
}
/*if (!prefs.update060AndroidAutoDialogShown) {
@@ -262,10 +267,8 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
)
vm.reloadPrefs()
if (requestingLocationUpdates && ContextCompat.checkSelfPermission(
requireContext(),
ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED && locationClient.isConnected
if (requestingLocationUpdates && requireContext().checkAnyLocationPermission()
&& locationClient.isConnected
) {
requestLocationUpdates()
}
@@ -273,16 +276,14 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
private fun setupClickListeners() {
binding.fabLocate.setOnClickListener {
if (ContextCompat.checkSelfPermission(
requireContext(),
ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
requestPermissions(
arrayOf(ACCESS_FINE_LOCATION),
if (!requireContext().checkFineLocationPermission()) {
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
} else {
}
if (requireContext().checkAnyLocationPermission()) {
enableLocation(moveTo = true, animate = true)
}
}
@@ -369,7 +370,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
val place = adapter.getItem(position) ?: return@OnItemClickListener
lifecycleScope.launch {
try {
vm.searchResult.value = adapter.currentProvider!!.getDetails(place.id)
vm.searchResult.value = adapter.getDetails(place.id)
} catch (e: ApiUnavailableException) {
e.printStackTrace()
} catch (e: IOException) {
@@ -389,9 +390,6 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
binding.search.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus ->
if (hasFocus) {
binding.search.keyListener = searchKeyListener
if (binding.search.text.isNotEmpty() && isVisible) {
binding.search.showDropDown()
}
} else {
binding.search.keyListener = null
}
@@ -883,11 +881,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
}
}
}
if (ContextCompat.checkSelfPermission(
requireContext(),
ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
if (context?.checkAnyLocationPermission() ?: false) {
enableLocation(!positionSet, false)
positionSet = true
}
@@ -903,7 +897,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
)
}
@RequiresPermission(ACCESS_FINE_LOCATION)
@RequiresPermission(anyOf = [ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION])
private fun enableLocation(moveTo: Boolean, animate: Boolean) {
val map = this.map ?: return
map.setMyLocationEnabled(true)
@@ -917,7 +911,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
}
}
@RequiresPermission(ACCESS_FINE_LOCATION)
@RequiresPermission(anyOf = [ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION])
private fun moveToLastLocation(map: AnyMap, animate: Boolean) {
val location = LocationServices.FusedLocationApi.getLastLocation(locationClient)
if (location != null) {
@@ -1027,7 +1021,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
) {
when (requestCode) {
REQUEST_LOCATION_PERMISSION -> {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
if ((grantResults.isNotEmpty() && grantResults.any { it == PackageManager.PERMISSION_GRANTED })) {
enableLocation(moveTo = true, animate = true)
}
}
@@ -1200,11 +1194,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac
val map = this.map ?: return
val context = this.context ?: return
if (vm.myLocationEnabled.value == true) {
if (ActivityCompat.checkSelfPermission(
context,
ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
if (context.checkAnyLocationPermission()) {
moveToLastLocation(map, false)
requestLocationUpdates()
}

View File

@@ -79,7 +79,13 @@ class MultiSelectDialog : AppCompatDialogFragment() {
items = data.entries.toList()
.sortedBy { it.value.toLowerCase(Locale.getDefault()) }
.sortedByDescending { commonChoices?.contains(it.key) == true }
.sortedBy {
when {
selected.contains(it.key) -> 0
commonChoices?.contains(it.key) == true -> 1
else -> 2
}
}
.map { MultiSelectItem(it.key, it.value, it.key in selected) }
adapter.submitList(items)

View File

@@ -4,11 +4,13 @@ import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.AnimatedVectorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.DecelerateInterpolator
import android.widget.ImageView
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.viewpager2.widget.ViewPager2
@@ -93,12 +95,18 @@ class WelcomeFragment : OnboardingPageFragment() {
override fun onResume() {
super.onResume()
binding.animationView.playAnimation()
val drawable = (binding.animationView as ImageView).drawable
if (drawable is AnimatedVectorDrawable) {
drawable.start()
}
}
override fun onPause() {
super.onPause()
binding.animationView.progress = 0f
val drawable = (binding.animationView as ImageView).drawable
if (drawable is AnimatedVectorDrawable) {
drawable.stop()
}
}
}

View File

@@ -102,6 +102,12 @@ class SettingsFragment : PreferenceFragmentCompat(),
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
return when (preference?.key) {
"search_delete_recent" -> {
Toast.makeText(context, R.string.deleted_recent_search_results, Toast.LENGTH_LONG)
.show()
vm.deleteRecentSearchResults()
true
}
else -> super.onPreferenceTreeClick(preference)
}
}

View File

@@ -24,19 +24,21 @@ import net.vonforst.evmap.model.*
MultipleChoiceFilterValue::class,
SliderFilterValue::class,
FilterProfile::class,
RecentAutocompletePlace::class,
GEPlug::class,
GENetwork::class,
GEChargeCard::class,
OCMConnectionType::class,
OCMCountry::class,
OCMOperator::class
], version = 13
], version = 14
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun chargeLocationsDao(): ChargeLocationsDao
abstract fun filterValueDao(): FilterValueDao
abstract fun filterProfileDao(): FilterProfileDao
abstract fun recentAutocompletePlaceDao(): RecentAutocompletePlaceDao
// GoingElectric API specific
abstract fun geReferenceDataDao(): GEReferenceDataDao
@@ -51,7 +53,7 @@ abstract class AppDatabase : RoomDatabase() {
.addMigrations(
MIGRATION_2, MIGRATION_3, MIGRATION_4, MIGRATION_5, MIGRATION_6,
MIGRATION_7, MIGRATION_8, MIGRATION_9, MIGRATION_10, MIGRATION_11,
MIGRATION_12, MIGRATION_13
MIGRATION_12, MIGRATION_13, MIGRATION_14
)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
@@ -303,5 +305,12 @@ abstract class AppDatabase : RoomDatabase() {
}
}
}
private val MIGRATION_14 = object : Migration(13, 14) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("CREATE TABLE IF NOT EXISTS `RecentAutocompletePlace` (`id` TEXT NOT NULL, `dataSource` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `primaryText` TEXT NOT NULL, `secondaryText` TEXT NOT NULL, `latLng` TEXT NOT NULL, `viewport` TEXT, `types` TEXT NOT NULL, PRIMARY KEY(`id`, `dataSource`))");
}
}
}
}

View File

@@ -0,0 +1,70 @@
package net.vonforst.evmap.storage
import androidx.room.*
import com.car2go.maps.model.LatLng
import com.car2go.maps.model.LatLngBounds
import net.vonforst.evmap.autocomplete.AutocompletePlace
import net.vonforst.evmap.autocomplete.AutocompletePlaceType
import net.vonforst.evmap.autocomplete.PlaceWithBounds
import net.vonforst.evmap.utils.distanceBetween
import java.time.Instant
@Entity(primaryKeys = ["id", "dataSource"])
data class RecentAutocompletePlace(
val id: String,
val dataSource: String,
var timestamp: Instant,
val primaryText: String,
val secondaryText: String,
val latLng: LatLng,
val viewport: LatLngBounds?,
val types: List<AutocompletePlaceType>
) {
constructor(
place: AutocompletePlace,
details: PlaceWithBounds,
dataSource: String,
timestamp: Instant
) : this(
place.id, dataSource, timestamp, place.primaryText.toString(),
place.secondaryText.toString(), details.latLng, details.viewport, place.types
)
fun asAutocompletePlace(currentLocation: LatLng?): AutocompletePlace {
return AutocompletePlace(
primaryText,
secondaryText,
id,
currentLocation?.let {
distanceBetween(
latLng.latitude, latLng.longitude,
it.latitude, it.longitude
)
},
types + AutocompletePlaceType.RECENT
)
}
fun asPlaceWithBounds(): PlaceWithBounds {
return PlaceWithBounds(latLng, viewport)
}
}
@Dao
abstract class RecentAutocompletePlaceDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract suspend fun insert(vararg places: RecentAutocompletePlace)
@Query("DELETE FROM recentautocompleteplace")
abstract suspend fun deleteAll()
@Query("SELECT * FROM recentautocompleteplace WHERE dataSource = :dataSource AND primaryText LIKE '%' || :query || '%' ORDER BY timestamp DESC LIMIT :limit")
abstract fun search(
query: String,
dataSource: String,
limit: Int? = null
): List<RecentAutocompletePlace>
@Query("SELECT * FROM recentautocompleteplace WHERE dataSource = :dataSource ORDER BY timestamp DESC LIMIT :limit")
abstract fun getAll(dataSource: String, limit: Int? = null): List<RecentAutocompletePlace>
}

View File

@@ -1,11 +1,14 @@
package net.vonforst.evmap.storage
import androidx.room.TypeConverter
import com.car2go.maps.model.LatLng
import com.car2go.maps.model.LatLngBounds
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
import net.vonforst.evmap.api.goingelectric.GEChargerPhotoAdapter
import net.vonforst.evmap.api.openchargemap.OCMChargerPhotoAdapter
import net.vonforst.evmap.autocomplete.AutocompletePlaceType
import net.vonforst.evmap.model.ChargeCardId
import net.vonforst.evmap.model.Chargepoint
import net.vonforst.evmap.model.ChargerPhoto
@@ -41,6 +44,12 @@ class Converters {
val type = Types.newParameterizedType(List::class.java, String::class.java)
moshi.adapter<List<String>>(type)
}
private val latLngAdapter by lazy {
moshi.adapter<LatLng>(LatLng::class.java)
}
private val latLngBoundsAdapter by lazy {
moshi.adapter<LatLngBounds>(LatLngBounds::class.java)
}
@TypeConverter
fun fromChargepointList(value: List<Chargepoint>?): String {
@@ -115,4 +124,34 @@ class Converters {
fun toStringList(value: String): List<String>? {
return stringListAdapter.fromJson(value)
}
@TypeConverter
fun fromLatLng(value: LatLng?): String {
return latLngAdapter.toJson(value)
}
@TypeConverter
fun toLatLng(value: String): LatLng? {
return latLngAdapter.fromJson(value)
}
@TypeConverter
fun fromLatLngBounds(value: LatLngBounds?): String {
return latLngBoundsAdapter.toJson(value)
}
@TypeConverter
fun toLatLngBounds(value: String): LatLngBounds? {
return latLngBoundsAdapter.fromJson(value)
}
@TypeConverter
fun fromAutocompletePlaceTypeList(value: List<AutocompletePlaceType>): String {
return value.joinToString(",") { it.name }
}
@TypeConverter
fun toAutocompletePlaceTypeList(value: String): List<AutocompletePlaceType> {
return value.split(",").map { AutocompletePlaceType.valueOf(it) }
}
}

View File

@@ -0,0 +1,20 @@
package net.vonforst.evmap.ui
import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
class AutocompleteTextViewWithSuggestions(ctx: Context, args: AttributeSet) :
androidx.appcompat.widget.AppCompatAutoCompleteTextView(ctx, args) {
override fun enoughToFilter(): Boolean = true
override fun onFocusChanged(
focused: Boolean, direction: Int,
previouslyFocusedRect: Rect?
) {
super.onFocusChanged(focused, direction, previouslyFocusedRect)
if (focused && adapter != null) {
performFiltering(text, 0)
}
}
}

View File

@@ -1,7 +1,11 @@
package net.vonforst.evmap.utils
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Location
import androidx.core.content.ContextCompat
import com.car2go.maps.model.LatLng
import com.car2go.maps.model.LatLngBounds
import kotlin.math.*
@@ -75,3 +79,17 @@ fun boundingBox(pos: LatLng, sizeMeters: Double): LatLngBounds {
pos.plusMeters(sizeMeters, sizeMeters)
)
}
fun Context.checkAnyLocationPermission() = ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
fun Context.checkFineLocationPermission() = ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED

View File

@@ -8,11 +8,13 @@ import kotlinx.coroutines.launch
import net.vonforst.evmap.api.chargeprice.ChargepriceApi
import net.vonforst.evmap.api.chargeprice.ChargepriceCar
import net.vonforst.evmap.api.chargeprice.ChargepriceTariff
import net.vonforst.evmap.storage.AppDatabase
import java.io.IOException
class SettingsViewModel(application: Application, chargepriceApiKey: String) :
AndroidViewModel(application) {
private var api = ChargepriceApi.create(chargepriceApiKey)
private var db = AppDatabase.getInstance(application)
val vehicles: MutableLiveData<Resource<List<ChargepriceCar>>> by lazy {
MutableLiveData<Resource<List<ChargepriceCar>>>().apply {
@@ -49,4 +51,10 @@ class SettingsViewModel(application: Application, chargepriceApiKey: String) :
}
}
}
fun deleteRecentSearchResults() {
viewModelScope.launch {
db.recentAutocompletePlaceDao().deleteAll()
}
}
}

View File

@@ -1,49 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="144.3dp"
android:height="270.5dp"
android:viewportWidth="144.3"
android:viewportHeight="270.5">
<path
android:pathData="M33.9,100l-2.5,-21.7l-3.8,0.4l2.5,21.7L33.9,100zM47.4,98.5l-2.5,-21.7l-3.8,0.4l2.5,21.7L47.4,98.5z"
android:fillColor="#FFB300" />
<path
android:pathData="M54.5,128c-1.2,1.4 -2.1,2.4 -2.2,2.5c-3.4,2.7 -6.1,3.5 -8.4,2.5c-3.9,-2 -3.7,-9.3 -3.5,-10.1l2.7,0.1c-0.1,2.1 0.3,6.5 2.1,7.5c1,0.5 2.9,-0.1 5.2,-2.1l0,0c0,0 7.6,-7.6 6,-13.6c-1.8,-7.2 6.5,-17.5 9.3,-21.1l0.4,-0.4l2.2,1.7l-0.4,0.5c-8.5,10.5 -9.4,15.8 -8.8,18.6C60.5,119.4 57,125 54.5,128z"
android:fillColor="#90A4AE" />
<path
android:pathData="M25.6,99.8l1,8.9l8.2,5.5L46,113l6.8,-7.2l-1,-8.9L25.6,99.8z"
android:fillColor="#90A4AE" />
<path
android:pathData="M45.8,113l-11.1,1.2l2.4,9.8l8.8,-1V113L45.8,113zM53.8,89.4l0.9,8.1l-31.9,3.7l-0.9,-8.1L53.8,89.4z"
android:fillColor="#546E7A" />
<path
android:pathData="M78.8,0C55.9,0 37.3,18.6 37.3,41.5c0,31.3 34.9,47.6 39.1,92.2c0.1,1.3 1.2,2.2 2.5,2.2s2.4,-0.9 2.5,-2.2c4.2,-44.6 39.1,-60.9 39.1,-92.2C120.3,18.4 101.7,0 78.8,0z"
android:fillColor="#00E676" />
<path
android:pathData="M78.8,0.9c22.8,0 41.2,18.3 41.5,40.9c0,-0.1 0,-0.3 0,-0.4C120.3,18.6 101.7,0 78.8,0S37.3,18.4 37.3,41.5c0,0.1 0,0.3 0,0.4C37.6,19.2 56,0.9 78.8,0.9L78.8,0.9z"
android:fillColor="#FFFFFF"
android:fillAlpha="0.2" />
<path
android:pathData="M81.3,132.6c-0.1,1.3 -1.2,2.2 -2.5,2.2c-1.3,0 -2.4,-0.9 -2.5,-2.2c-4.1,-44.5 -38.7,-60.8 -39,-91.7c0,0.3 0,0.4 0,0.7c0,31.3 34.9,47.6 39.1,92.2c0.1,1.3 1.2,2.2 2.5,2.2c1.3,0 2.4,-0.9 2.5,-2.2c4.2,-44.6 39.1,-60.9 39.1,-92.2c0,-0.3 0,-0.4 0,-0.7C120,71.8 85.3,88.1 81.3,132.6L81.3,132.6z"
android:fillColor="#3E2723"
android:fillAlpha="0.2" />
<path
android:fillColor="#FF000000"
android:pathData="M69.3,21.2v25.1h6.8v20.5l16,-27.5h-9.2L92,21.1C92.1,21.2 69.3,21.2 69.3,21.2z"
android:strokeAlpha="0.45"
android:fillAlpha="0.45" />
<path
android:fillColor="?android:textColorSecondary"
android:pathData="M19.2,244.2H2.8v14.1h18.8v2.4H0v-34.1h21.5v2.4H2.8v12.8h16.4V244.2z" />
<path
android:fillColor="?android:textColorSecondary"
android:pathData="M37.2,254.9l0.7,2.3h0.1l0.7,-2.3L49,226.6h3l-12.7,34.1h-2.6l-12.7,-34.1h3L37.2,254.9z" />
<path
android:fillColor="?android:textColorSecondary"
android:pathData="M60.9,226.6l12.5,30h0.1l12.6,-30h3.7v34.1h-2.8v-15.1l0.2,-14.9l-0.1,0l-12.7,30h-1.9l-12.7,-29.9l-0.1,0l0.3,14.8v15.1h-2.8v-34.1H60.9z" />
<path
android:fillColor="?android:textColorSecondary"
android:pathData="M114.1,260.7c-0.2,-0.9 -0.3,-1.6 -0.4,-2.2s-0.1,-1.3 -0.1,-1.9c-0.9,1.3 -2.2,2.4 -3.8,3.3s-3.3,1.3 -5.3,1.3c-2.5,0 -4.4,-0.7 -5.8,-2s-2.1,-3.1 -2.1,-5.3c0,-2.3 1,-4.2 3,-5.6s4.8,-2.1 8.2,-2.1h5.6v-3.1c0,-1.8 -0.6,-3.2 -1.7,-4.3s-2.8,-1.5 -4.9,-1.5c-2,0 -3.6,0.5 -4.9,1.5s-1.9,2.2 -1.9,3.6l-2.6,0l0,-0.1c-0.1,-1.9 0.8,-3.6 2.6,-5.1s4.1,-2.2 6.9,-2.2c2.8,0 5,0.7 6.8,2.1s2.6,3.5 2.6,6.1v12.5c0,0.9 0.1,1.8 0.2,2.6s0.3,1.7 0.5,2.5H114.1zM104.9,258.7c2,0 3.8,-0.5 5.3,-1.4s2.7,-2.2 3.4,-3.6v-5.3H108c-2.5,0 -4.6,0.5 -6.1,1.6s-2.3,2.4 -2.3,4c0,1.4 0.5,2.5 1.4,3.4S103.3,258.7 104.9,258.7z" />
<path
android:fillColor="?android:textColorSecondary"
android:pathData="M144.3,248.7c0,3.8 -0.9,6.8 -2.6,9.1s-4.1,3.4 -7.1,3.4c-1.8,0 -3.3,-0.3 -4.7,-1s-2.4,-1.6 -3.3,-2.9v13.1h-2.8v-35.1h2.4l0.4,3.9c0.8,-1.4 1.9,-2.5 3.3,-3.3s2.9,-1.1 4.7,-1.1c3,0 5.4,1.2 7.1,3.6s2.6,5.7 2.6,9.7V248.7zM141.5,248.2c0,-3.2 -0.6,-5.8 -1.9,-7.9c-1.3,-2 -3.2,-3 -5.6,-3c-1.9,0 -3.4,0.4 -4.6,1.3c-1.2,0.9 -2.1,2.1 -2.7,3.5v12.2c0.6,1.4 1.6,2.5 2.8,3.3s2.7,1.2 4.5,1.2c2.5,0 4.3,-0.9 5.6,-2.8c1.3,-1.8 1.9,-4.3 1.9,-7.3V248.2z" />
</vector>

View File

@@ -0,0 +1,10 @@
<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/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z" />
</vector>

View File

@@ -0,0 +1,217 @@
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:width="192dp"
android:height="192dp"
android:viewportWidth="192"
android:viewportHeight="192">
<group android:name="_R_G">
<group
android:name="_R_G_L_2_G_N_1_T_0"
android:translateX="94"
android:translateY="96">
<group
android:name="_R_G_L_2_G"
android:pivotX="53.625"
android:pivotY="43.025"
android:rotation="73"
android:translateX="-37.85"
android:translateY="6.550000000000004">
<path
android:name="_R_G_L_2_G_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#ffb300"
android:fillType="nonZero"
android:pathData=" M9.45 18.05 C9.45,18.05 7.55,1.45 7.55,1.45 C7.55,1.45 4.65,1.75 4.65,1.75 C4.65,1.75 6.55,18.35 6.55,18.35 C6.55,18.35 9.45,18.05 9.45,18.05c M19.75 16.85 C19.75,16.85 17.85,0.25 17.85,0.25 C17.85,0.25 14.95,0.55 14.95,0.55 C14.95,0.55 16.85,17.15 16.85,17.15 C16.85,17.15 19.75,16.85 19.75,16.85c " />
<path
android:name="_R_G_L_2_G_D_1_P_0"
android:fillAlpha="1"
android:fillColor="#90a4ae"
android:fillType="nonZero"
android:pathData=" M25.15 39.45 C24.25,40.55 23.55,41.25 23.45,41.35 C20.85,43.45 18.75,44.05 17.05,43.25 C14.05,41.75 14.25,36.15 14.35,35.55 C14.35,35.55 16.45,35.65 16.45,35.65 C16.35,37.25 16.65,40.65 18.05,41.35 C18.85,41.75 20.25,41.25 22.05,39.75 C22.05,39.75 27.85,33.95 26.65,29.35 C25.25,23.85 31.65,15.95 33.75,13.25 C33.75,13.25 34.05,12.95 34.05,12.95 C34.05,12.95 35.75,14.25 35.75,14.25 C35.75,14.25 35.45,14.65 35.45,14.65 C28.95,22.65 28.25,26.75 28.75,28.85 C29.75,32.85 27.05,37.15 25.15,39.45c " />
<path
android:name="_R_G_L_2_G_D_2_P_0"
android:fillAlpha="1"
android:fillColor="#90a4ae"
android:fillType="nonZero"
android:pathData=" M3.05 17.85 C3.05,17.85 3.85,24.65 3.85,24.65 C3.85,24.65 10.15,28.85 10.15,28.85 C10.15,28.85 18.65,27.95 18.65,27.95 C18.65,27.95 23.85,22.45 23.85,22.45 C23.85,22.45 23.05,15.65 23.05,15.65 C23.05,15.65 3.05,17.85 3.05,17.85c " />
<path
android:name="_R_G_L_2_G_D_3_P_0"
android:fillAlpha="1"
android:fillColor="#546e7a"
android:fillType="nonZero"
android:pathData=" M18.55 27.95 C18.55,27.95 10.05,28.85 10.05,28.85 C10.05,28.85 11.85,36.35 11.85,36.35 C11.85,36.35 18.55,35.55 18.55,35.55 C18.55,35.55 18.55,27.95 18.55,27.95c M24.65 9.95 C24.65,9.95 25.35,16.15 25.35,16.15 C25.35,16.15 0.95,18.95 0.95,18.95 C0.95,18.95 0.25,12.75 0.25,12.75 C0.25,12.75 24.65,9.95 24.65,9.95c " />
</group>
</group>
<group
android:name="_R_G_L_1_G_N_1_T_0"
android:translateX="94"
android:translateY="96">
<group
android:name="_R_G_L_1_G"
android:translateX="-26.049"
android:translateY="-52.150000000000006">
<path
android:name="_R_G_L_1_G_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#00e676"
android:fillType="nonZero"
android:pathData=" M31.95 0.25 C14.45,0.25 0.25,14.45 0.25,31.95 C0.25,55.85 26.95,68.35 30.15,102.45 C30.25,103.45 31.05,104.15 32.05,104.15 C33.05,104.15 33.85,103.45 33.95,102.45 C37.15,68.35 63.85,55.85 63.85,31.95 C63.65,14.35 49.45,0.25 31.95,0.25c " />
<path
android:name="_R_G_L_1_G_D_1_P_0"
android:fillAlpha="0.2"
android:fillColor="#ffffff"
android:fillType="nonZero"
android:pathData=" M31.95 0.95 C49.35,0.95 63.45,14.95 63.65,32.25 C63.65,32.25 63.65,31.95 63.65,31.95 C63.65,14.45 49.45,0.25 31.95,0.25 C14.45,0.25 0.25,14.35 0.25,31.95 C0.25,31.95 0.25,32.25 0.25,32.25 C0.45,14.95 14.55,0.95 31.95,0.95c " />
<path
android:name="_R_G_L_1_G_D_2_P_0"
android:fillAlpha="0.2"
android:fillColor="#3e2723"
android:fillType="nonZero"
android:pathData=" M33.85 101.65 C33.75,102.65 32.95,103.35 31.95,103.35 C30.95,103.35 30.15,102.65 30.05,101.65 C26.95,67.65 0.45,55.15 0.25,31.55 C0.25,31.55 0.25,32.05 0.25,32.05 C0.25,55.95 26.95,68.45 30.15,102.55 C30.25,103.55 31.05,104.25 32.05,104.25 C33.05,104.25 33.85,103.55 33.95,102.55 C37.15,68.45 63.85,55.95 63.85,32.05 C63.85,32.05 63.85,31.55 63.85,31.55 C63.45,55.15 36.95,67.65 33.85,101.65c " />
<path
android:name="_R_G_L_1_G_D_3_P_0"
android:fillAlpha="0.45"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M24.65 16.45 C24.65,16.45 24.65,35.65 24.65,35.65 C24.65,35.65 29.85,35.65 29.85,35.65 C29.85,35.65 29.85,51.35 29.85,51.35 C29.85,51.35 42.05,30.35 42.05,30.35 C42.05,30.35 35.05,30.35 35.05,30.35 C35.05,30.35 42.05,16.35 42.05,16.35 C42.15,16.45 24.65,16.45 24.65,16.45c " />
</group>
</group>
<group
android:name="_R_G_L_0_G_N_1_T_0"
android:translateX="94"
android:translateY="96">
<group
android:name="_R_G_L_0_G"
android:translateX="-1.3999999999999995"
android:translateY="-35.8">
<group android:name="_R_G_L_0_C_0_G">
<clip-path
android:name="_R_G_L_0_C_0"
android:pathData=" M23.73 37.15 C23.73,37.15 21.71,37.15 21.71,37.15 C21.71,37.15 13.39,37.15 13.39,37.15 C13.39,37.15 -2.01,37.15 -2.01,37.15 C-2.01,37.15 -6.82,37.15 -6.82,37.15 C-6.82,37.15 -8.27,37.15 -8.27,37.15 C-8.27,37.15 -8.27,40.03 -8.27,40.03 C-8.27,40.03 23.73,40.03 23.73,40.03 C23.73,40.03 23.73,37.15 23.73,37.15c " />
<group android:name="_R_G_L_0_C_0_G_G">
<path
android:name="_R_G_L_0_G_G_0_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#ffffff"
android:fillType="nonZero"
android:pathData=" M0 0.1 C0,0.1 0,19.3 0,19.3 C0,19.3 5.2,19.3 5.2,19.3 C5.2,19.3 5.2,35 5.2,35 C5.2,35 17.4,14 17.4,14 C17.4,14 10.4,14 10.4,14 C10.4,14 17.4,0 17.4,0 C17.5,0.1 0,0.1 0,0.1c " />
<path
android:name="_R_G_L_0_G_G_0_D_1_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M0 0.1 C0,0.1 0,0.69 0,0.69 C0,0.69 0,19.3 0,19.3 C0,19.3 0.55,19.3 0.55,19.3 C0.55,19.3 0.55,0.69 0.55,0.69 C0.55,0.69 17.05,0.69 17.05,0.69 C17.05,0.69 17.4,0 17.4,0 C17.5,0.1 0,0.1 0,0.1c " />
<path
android:name="_R_G_L_0_G_G_0_D_2_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M5.82 33.92 C5.82,33.92 5.2,35 5.2,35 C5.2,35 5.2,19.3 5.2,19.3 C5.2,19.3 5.82,19.3 5.82,19.3 C5.82,19.3 5.82,33.92 5.82,33.92c " />
<path
android:name="_R_G_L_0_G_G_0_D_3_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M17.08 14.55 C17.08,14.55 11.21,14.55 11.21,14.55 C11.21,14.55 10.4,14 10.4,14 C10.4,14 17.4,14 17.4,14 C17.4,14 17.08,14.55 17.08,14.55c " />
</group>
</group>
</group>
</group>
</group>
<group android:name="time_group" />
</vector>
</aapt:attr>
<target android:name="_R_G_L_2_G">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
android:duration="434"
android:propertyName="rotation"
android:startOffset="0"
android:valueFrom="73"
android:valueTo="0"
android:valueType="floatType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
<target android:name="_R_G_L_0_C_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
android:duration="333"
android:propertyName="pathData"
android:startOffset="0"
android:valueFrom="M23.73 37.15 C23.73,37.15 21.71,37.15 21.71,37.15 C21.71,37.15 13.39,37.15 13.39,37.15 C13.39,37.15 -2.01,37.15 -2.01,37.15 C-2.01,37.15 -6.82,37.15 -6.82,37.15 C-6.82,37.15 -8.27,37.15 -8.27,37.15 C-8.27,37.15 -8.27,40.03 -8.27,40.03 C-8.27,40.03 23.73,40.03 23.73,40.03 C23.73,40.03 23.73,37.15 23.73,37.15c "
android:valueTo="M23.73 37.15 C23.73,37.15 21.71,37.15 21.71,37.15 C21.71,37.15 13.39,37.15 13.39,37.15 C13.39,37.15 -2.01,37.15 -2.01,37.15 C-2.01,37.15 -6.82,37.15 -6.82,37.15 C-6.82,37.15 -8.27,37.15 -8.27,37.15 C-8.27,37.15 -8.27,40.03 -8.27,40.03 C-8.27,40.03 23.73,40.03 23.73,40.03 C23.73,40.03 23.73,37.15 23.73,37.15c "
android:valueType="pathType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
android:duration="167"
android:propertyName="pathData"
android:startOffset="333"
android:valueFrom="M23.73 37.15 C23.73,37.15 21.71,37.15 21.71,37.15 C21.71,37.15 13.39,37.15 13.39,37.15 C13.39,37.15 -2.01,37.15 -2.01,37.15 C-2.01,37.15 -6.82,37.15 -6.82,37.15 C-6.82,37.15 -8.27,37.15 -8.27,37.15 C-8.27,37.15 -8.27,40.03 -8.27,40.03 C-8.27,40.03 23.73,40.03 23.73,40.03 C23.73,40.03 23.73,37.15 23.73,37.15c "
android:valueTo="M24.11 22.78 C24.11,22.78 21.82,22.78 21.82,22.78 C21.82,22.78 15.48,20.34 14.4,20.34 C12.43,20.34 2.78,25.37 0.81,25.37 C-0.35,25.37 -5.1,22.78 -5.1,22.78 C-5.1,22.78 -7.89,22.78 -7.89,22.78 C-7.89,22.78 -7.89,39.16 -7.89,39.16 C-7.89,39.16 24.11,39.16 24.11,39.16 C24.11,39.16 24.11,22.78 24.11,22.78c "
android:valueType="pathType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
android:duration="167"
android:propertyName="pathData"
android:startOffset="500"
android:valueFrom="M24.11 22.78 C24.11,22.78 21.82,22.78 21.82,22.78 C21.82,22.78 15.48,20.34 14.4,20.34 C12.43,20.34 2.78,25.37 0.81,25.37 C-0.35,25.37 -5.1,22.78 -5.1,22.78 C-5.1,22.78 -7.89,22.78 -7.89,22.78 C-7.89,22.78 -7.89,39.16 -7.89,39.16 C-7.89,39.16 24.11,39.16 24.11,39.16 C24.11,39.16 24.11,22.78 24.11,22.78c "
android:valueTo="M24.12 9.79 C24.12,9.79 21.56,9.79 21.56,9.79 C21.56,9.79 17.22,11.4 15.06,11.4 C11.13,11.4 7.18,7.73 3.24,7.73 C0.91,7.73 -3.76,9.79 -3.76,9.79 C-3.76,9.79 -7.88,9.79 -7.88,9.79 C-7.88,9.79 -7.88,39.67 -7.88,39.67 C-7.88,39.67 24.12,39.67 24.12,39.67 C24.12,39.67 24.12,9.79 24.12,9.79c "
android:valueType="pathType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
android:duration="167"
android:propertyName="pathData"
android:startOffset="667"
android:valueFrom="M24.12 9.79 C24.12,9.79 21.56,9.79 21.56,9.79 C21.56,9.79 17.22,11.4 15.06,11.4 C11.13,11.4 7.18,7.73 3.24,7.73 C0.91,7.73 -3.76,9.79 -3.76,9.79 C-3.76,9.79 -7.88,9.79 -7.88,9.79 C-7.88,9.79 -7.88,39.67 -7.88,39.67 C-7.88,39.67 24.12,39.67 24.12,39.67 C24.12,39.67 24.12,9.79 24.12,9.79c "
android:valueTo="M24.26 0.67 C24.26,0.67 22,0.67 22,0.67 C22,0.67 15.43,-1.35 14.47,-1.35 C12.71,-1.35 2.44,1.87 0.68,1.87 C-0.36,1.87 -5.09,0.67 -5.09,0.67 C-5.09,0.67 -7.74,0.67 -7.74,0.67 C-7.74,0.67 -7.74,44.06 -7.74,44.06 C-7.74,44.06 24.26,44.06 24.26,44.06 C24.26,44.06 24.26,0.67 24.26,0.67c "
android:valueType="pathType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
</aapt:attr>
</objectAnimator>
<objectAnimator
android:duration="133"
android:propertyName="pathData"
android:startOffset="833"
android:valueFrom="M24.26 0.67 C24.26,0.67 22,0.67 22,0.67 C22,0.67 15.43,-1.35 14.47,-1.35 C12.71,-1.35 2.44,1.87 0.68,1.87 C-0.36,1.87 -5.09,0.67 -5.09,0.67 C-5.09,0.67 -7.74,0.67 -7.74,0.67 C-7.74,0.67 -7.74,44.06 -7.74,44.06 C-7.74,44.06 24.26,44.06 24.26,44.06 C24.26,44.06 24.26,0.67 24.26,0.67c "
android:valueTo="M24.4 -9.98 C24.4,-9.98 22.38,-9.98 22.38,-9.98 C22.38,-9.98 14.07,-9.99 14.06,-9.99 C14.05,-9.99 -1.32,-9.97 -1.32,-9.97 C-1.33,-9.97 -6.14,-9.98 -6.14,-9.98 C-6.14,-9.98 -7.6,-9.98 -7.6,-9.98 C-7.6,-9.98 -7.6,44.22 -7.6,44.22 C-7.6,44.22 24.4,44.22 24.4,44.22 C24.4,44.22 24.4,-9.98 24.4,-9.98c "
android:valueType="pathType">
<aapt:attr name="android:interpolator">
<pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
<target android:name="time_group">
<aapt:attr name="android:animation">
<set android:ordering="together">
<objectAnimator
android:duration="1000"
android:propertyName="translateX"
android:startOffset="0"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@@ -0,0 +1,121 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="192dp"
android:height="192dp"
android:viewportWidth="192"
android:viewportHeight="192">
<group android:name="_R_G">
<group
android:name="_R_G_L_2_G_N_1_T_0"
android:translateX="94"
android:translateY="96">
<group
android:name="_R_G_L_2_G"
android:pivotX="53.625"
android:pivotY="43.025"
android:rotation="0"
android:translateX="-37.85"
android:translateY="6.550000000000004">
<path
android:name="_R_G_L_2_G_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#ffb300"
android:fillType="nonZero"
android:pathData=" M9.45 18.05 C9.45,18.05 7.55,1.45 7.55,1.45 C7.55,1.45 4.65,1.75 4.65,1.75 C4.65,1.75 6.55,18.35 6.55,18.35 C6.55,18.35 9.45,18.05 9.45,18.05c M19.75 16.85 C19.75,16.85 17.85,0.25 17.85,0.25 C17.85,0.25 14.95,0.55 14.95,0.55 C14.95,0.55 16.85,17.15 16.85,17.15 C16.85,17.15 19.75,16.85 19.75,16.85c " />
<path
android:name="_R_G_L_2_G_D_1_P_0"
android:fillAlpha="1"
android:fillColor="#90a4ae"
android:fillType="nonZero"
android:pathData=" M25.15 39.45 C24.25,40.55 23.55,41.25 23.45,41.35 C20.85,43.45 18.75,44.05 17.05,43.25 C14.05,41.75 14.25,36.15 14.35,35.55 C14.35,35.55 16.45,35.65 16.45,35.65 C16.35,37.25 16.65,40.65 18.05,41.35 C18.85,41.75 20.25,41.25 22.05,39.75 C22.05,39.75 27.85,33.95 26.65,29.35 C25.25,23.85 31.65,15.95 33.75,13.25 C33.75,13.25 34.05,12.95 34.05,12.95 C34.05,12.95 35.75,14.25 35.75,14.25 C35.75,14.25 35.45,14.65 35.45,14.65 C28.95,22.65 28.25,26.75 28.75,28.85 C29.75,32.85 27.05,37.15 25.15,39.45c " />
<path
android:name="_R_G_L_2_G_D_2_P_0"
android:fillAlpha="1"
android:fillColor="#90a4ae"
android:fillType="nonZero"
android:pathData=" M3.05 17.85 C3.05,17.85 3.85,24.65 3.85,24.65 C3.85,24.65 10.15,28.85 10.15,28.85 C10.15,28.85 18.65,27.95 18.65,27.95 C18.65,27.95 23.85,22.45 23.85,22.45 C23.85,22.45 23.05,15.65 23.05,15.65 C23.05,15.65 3.05,17.85 3.05,17.85c " />
<path
android:name="_R_G_L_2_G_D_3_P_0"
android:fillAlpha="1"
android:fillColor="#546e7a"
android:fillType="nonZero"
android:pathData=" M18.55 27.95 C18.55,27.95 10.05,28.85 10.05,28.85 C10.05,28.85 11.85,36.35 11.85,36.35 C11.85,36.35 18.55,35.55 18.55,35.55 C18.55,35.55 18.55,27.95 18.55,27.95c M24.65 9.95 C24.65,9.95 25.35,16.15 25.35,16.15 C25.35,16.15 0.95,18.95 0.95,18.95 C0.95,18.95 0.25,12.75 0.25,12.75 C0.25,12.75 24.65,9.95 24.65,9.95c " />
</group>
</group>
<group
android:name="_R_G_L_1_G_N_1_T_0"
android:translateX="94"
android:translateY="96">
<group
android:name="_R_G_L_1_G"
android:translateX="-26.049"
android:translateY="-52.150000000000006">
<path
android:name="_R_G_L_1_G_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#00e676"
android:fillType="nonZero"
android:pathData=" M31.95 0.25 C14.45,0.25 0.25,14.45 0.25,31.95 C0.25,55.85 26.95,68.35 30.15,102.45 C30.25,103.45 31.05,104.15 32.05,104.15 C33.05,104.15 33.85,103.45 33.95,102.45 C37.15,68.35 63.85,55.85 63.85,31.95 C63.65,14.35 49.45,0.25 31.95,0.25c " />
<path
android:name="_R_G_L_1_G_D_1_P_0"
android:fillAlpha="0.2"
android:fillColor="#ffffff"
android:fillType="nonZero"
android:pathData=" M31.95 0.95 C49.35,0.95 63.45,14.95 63.65,32.25 C63.65,32.25 63.65,31.95 63.65,31.95 C63.65,14.45 49.45,0.25 31.95,0.25 C14.45,0.25 0.25,14.35 0.25,31.95 C0.25,31.95 0.25,32.25 0.25,32.25 C0.45,14.95 14.55,0.95 31.95,0.95c " />
<path
android:name="_R_G_L_1_G_D_2_P_0"
android:fillAlpha="0.2"
android:fillColor="#3e2723"
android:fillType="nonZero"
android:pathData=" M33.85 101.65 C33.75,102.65 32.95,103.35 31.95,103.35 C30.95,103.35 30.15,102.65 30.05,101.65 C26.95,67.65 0.45,55.15 0.25,31.55 C0.25,31.55 0.25,32.05 0.25,32.05 C0.25,55.95 26.95,68.45 30.15,102.55 C30.25,103.55 31.05,104.25 32.05,104.25 C33.05,104.25 33.85,103.55 33.95,102.55 C37.15,68.45 63.85,55.95 63.85,32.05 C63.85,32.05 63.85,31.55 63.85,31.55 C63.45,55.15 36.95,67.65 33.85,101.65c " />
<path
android:name="_R_G_L_1_G_D_3_P_0"
android:fillAlpha="0.45"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M24.65 16.45 C24.65,16.45 24.65,35.65 24.65,35.65 C24.65,35.65 29.85,35.65 29.85,35.65 C29.85,35.65 29.85,51.35 29.85,51.35 C29.85,51.35 42.05,30.35 42.05,30.35 C42.05,30.35 35.05,30.35 35.05,30.35 C35.05,30.35 42.05,16.35 42.05,16.35 C42.15,16.45 24.65,16.45 24.65,16.45c " />
</group>
</group>
<group
android:name="_R_G_L_0_G_N_1_T_0"
android:translateX="94"
android:translateY="96">
<group
android:name="_R_G_L_0_G"
android:translateX="-1.3999999999999995"
android:translateY="-35.8">
<group android:name="_R_G_L_0_C_0_G">
<clip-path
android:name="_R_G_L_0_C_0"
android:pathData="M24.4 -9.98 C24.4,-9.98 22.38,-9.98 22.38,-9.98 C22.38,-9.98 14.07,-9.99 14.06,-9.99 C14.05,-9.99 -1.32,-9.97 -1.32,-9.97 C-1.33,-9.97 -6.14,-9.98 -6.14,-9.98 C-6.14,-9.98 -7.6,-9.98 -7.6,-9.98 C-7.6,-9.98 -7.6,44.22 -7.6,44.22 C-7.6,44.22 24.4,44.22 24.4,44.22 C24.4,44.22 24.4,-9.98 24.4,-9.98c " />
<group android:name="_R_G_L_0_C_0_G_G">
<path
android:name="_R_G_L_0_G_G_0_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#ffffff"
android:fillType="nonZero"
android:pathData=" M0 0.1 C0,0.1 0,19.3 0,19.3 C0,19.3 5.2,19.3 5.2,19.3 C5.2,19.3 5.2,35 5.2,35 C5.2,35 17.4,14 17.4,14 C17.4,14 10.4,14 10.4,14 C10.4,14 17.4,0 17.4,0 C17.5,0.1 0,0.1 0,0.1c " />
<path
android:name="_R_G_L_0_G_G_0_D_1_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M0 0.1 C0,0.1 0,0.69 0,0.69 C0,0.69 0,19.3 0,19.3 C0,19.3 0.55,19.3 0.55,19.3 C0.55,19.3 0.55,0.69 0.55,0.69 C0.55,0.69 17.05,0.69 17.05,0.69 C17.05,0.69 17.4,0 17.4,0 C17.5,0.1 0,0.1 0,0.1c " />
<path
android:name="_R_G_L_0_G_G_0_D_2_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M5.82 33.92 C5.82,33.92 5.2,35 5.2,35 C5.2,35 5.2,19.3 5.2,19.3 C5.2,19.3 5.82,19.3 5.82,19.3 C5.82,19.3 5.82,33.92 5.82,33.92c " />
<path
android:name="_R_G_L_0_G_G_0_D_3_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M17.08 14.55 C17.08,14.55 11.21,14.55 11.21,14.55 C11.21,14.55 10.4,14 10.4,14 C10.4,14 17.4,14 17.4,14 C17.4,14 17.08,14.55 17.08,14.55c " />
</group>
</group>
</group>
</group>
</group>
<group android:name="time_group" />
</vector>

View File

@@ -0,0 +1,120 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="160dp"
android:height="160dp"
android:viewportWidth="120"
android:viewportHeight="120">
<group android:name="_R_G">
<group
android:name="_R_G_L_2_G_N_1_T_0"
android:translateX="58"
android:translateY="60">
<group
android:name="_R_G_L_2_G"
android:pivotX="53.625"
android:pivotY="43.025"
android:rotation="0"
android:translateX="-37.85"
android:translateY="6.550000000000004">
<path
android:name="_R_G_L_2_G_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#ffb300"
android:fillType="nonZero"
android:pathData=" M9.45 18.05 C9.45,18.05 7.55,1.45 7.55,1.45 C7.55,1.45 4.65,1.75 4.65,1.75 C4.65,1.75 6.55,18.35 6.55,18.35 C6.55,18.35 9.45,18.05 9.45,18.05c M19.75 16.85 C19.75,16.85 17.85,0.25 17.85,0.25 C17.85,0.25 14.95,0.55 14.95,0.55 C14.95,0.55 16.85,17.15 16.85,17.15 C16.85,17.15 19.75,16.85 19.75,16.85c " />
<path
android:name="_R_G_L_2_G_D_1_P_0"
android:fillAlpha="1"
android:fillColor="#90a4ae"
android:fillType="nonZero"
android:pathData=" M25.15 39.45 C24.25,40.55 23.55,41.25 23.45,41.35 C20.85,43.45 18.75,44.05 17.05,43.25 C14.05,41.75 14.25,36.15 14.35,35.55 C14.35,35.55 16.45,35.65 16.45,35.65 C16.35,37.25 16.65,40.65 18.05,41.35 C18.85,41.75 20.25,41.25 22.05,39.75 C22.05,39.75 27.85,33.95 26.65,29.35 C25.25,23.85 31.65,15.95 33.75,13.25 C33.75,13.25 34.05,12.95 34.05,12.95 C34.05,12.95 35.75,14.25 35.75,14.25 C35.75,14.25 35.45,14.65 35.45,14.65 C28.95,22.65 28.25,26.75 28.75,28.85 C29.75,32.85 27.05,37.15 25.15,39.45c " />
<path
android:name="_R_G_L_2_G_D_2_P_0"
android:fillAlpha="1"
android:fillColor="#90a4ae"
android:fillType="nonZero"
android:pathData=" M3.05 17.85 C3.05,17.85 3.85,24.65 3.85,24.65 C3.85,24.65 10.15,28.85 10.15,28.85 C10.15,28.85 18.65,27.95 18.65,27.95 C18.65,27.95 23.85,22.45 23.85,22.45 C23.85,22.45 23.05,15.65 23.05,15.65 C23.05,15.65 3.05,17.85 3.05,17.85c " />
<path
android:name="_R_G_L_2_G_D_3_P_0"
android:fillAlpha="1"
android:fillColor="#546e7a"
android:fillType="nonZero"
android:pathData=" M18.55 27.95 C18.55,27.95 10.05,28.85 10.05,28.85 C10.05,28.85 11.85,36.35 11.85,36.35 C11.85,36.35 18.55,35.55 18.55,35.55 C18.55,35.55 18.55,27.95 18.55,27.95c M24.65 9.95 C24.65,9.95 25.35,16.15 25.35,16.15 C25.35,16.15 0.95,18.95 0.95,18.95 C0.95,18.95 0.25,12.75 0.25,12.75 C0.25,12.75 24.65,9.95 24.65,9.95c " />
</group>
</group>
<group
android:name="_R_G_L_1_G_N_1_T_0"
android:translateX="58"
android:translateY="60">
<group
android:name="_R_G_L_1_G"
android:translateX="-26.049"
android:translateY="-52.150000000000006">
<path
android:name="_R_G_L_1_G_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#00e676"
android:fillType="nonZero"
android:pathData=" M31.95 0.25 C14.45,0.25 0.25,14.45 0.25,31.95 C0.25,55.85 26.95,68.35 30.15,102.45 C30.25,103.45 31.05,104.15 32.05,104.15 C33.05,104.15 33.85,103.45 33.95,102.45 C37.15,68.35 63.85,55.85 63.85,31.95 C63.65,14.35 49.45,0.25 31.95,0.25c " />
<path
android:name="_R_G_L_1_G_D_1_P_0"
android:fillAlpha="0.2"
android:fillColor="#ffffff"
android:fillType="nonZero"
android:pathData=" M31.95 0.95 C49.35,0.95 63.45,14.95 63.65,32.25 C63.65,32.25 63.65,31.95 63.65,31.95 C63.65,14.45 49.45,0.25 31.95,0.25 C14.45,0.25 0.25,14.35 0.25,31.95 C0.25,31.95 0.25,32.25 0.25,32.25 C0.45,14.95 14.55,0.95 31.95,0.95c " />
<path
android:name="_R_G_L_1_G_D_2_P_0"
android:fillAlpha="0.2"
android:fillColor="#3e2723"
android:fillType="nonZero"
android:pathData=" M33.85 101.65 C33.75,102.65 32.95,103.35 31.95,103.35 C30.95,103.35 30.15,102.65 30.05,101.65 C26.95,67.65 0.45,55.15 0.25,31.55 C0.25,31.55 0.25,32.05 0.25,32.05 C0.25,55.95 26.95,68.45 30.15,102.55 C30.25,103.55 31.05,104.25 32.05,104.25 C33.05,104.25 33.85,103.55 33.95,102.55 C37.15,68.45 63.85,55.95 63.85,32.05 C63.85,32.05 63.85,31.55 63.85,31.55 C63.45,55.15 36.95,67.65 33.85,101.65c " />
<path
android:name="_R_G_L_1_G_D_3_P_0"
android:fillAlpha="0.45"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M24.65 16.45 C24.65,16.45 24.65,35.65 24.65,35.65 C24.65,35.65 29.85,35.65 29.85,35.65 C29.85,35.65 29.85,51.35 29.85,51.35 C29.85,51.35 42.05,30.35 42.05,30.35 C42.05,30.35 35.05,30.35 35.05,30.35 C35.05,30.35 42.05,16.35 42.05,16.35 C42.15,16.45 24.65,16.45 24.65,16.45c " />
</group>
</group>
<group
android:name="_R_G_L_0_G_N_1_T_0"
android:translateX="58"
android:translateY="60">
<group
android:name="_R_G_L_0_G"
android:translateX="-1.3999999999999995"
android:translateY="-35.8">
<group android:name="_R_G_L_0_C_0_G">
<clip-path
android:name="_R_G_L_0_C_0"
android:pathData="M23.73 37.15 C23.73,37.15 21.71,37.15 21.71,37.15 C21.71,37.15 13.39,37.15 13.39,37.15 C13.39,37.15 -2.01,37.15 -2.01,37.15 C-2.01,37.15 -6.82,37.15 -6.82,37.15 C-6.82,37.15 -8.27,37.15 -8.27,37.15 C-8.27,37.15 -8.27,40.03 -8.27,40.03 C-8.27,40.03 23.73,40.03 23.73,40.03 C23.73,40.03 23.73,37.15 23.73,37.15c " />
<group android:name="_R_G_L_0_C_0_G_G">
<path
android:name="_R_G_L_0_G_G_0_D_0_P_0"
android:fillAlpha="1"
android:fillColor="#ffffff"
android:fillType="nonZero"
android:pathData=" M0 0.1 C0,0.1 0,19.3 0,19.3 C0,19.3 5.2,19.3 5.2,19.3 C5.2,19.3 5.2,35 5.2,35 C5.2,35 17.4,14 17.4,14 C17.4,14 10.4,14 10.4,14 C10.4,14 17.4,0 17.4,0 C17.5,0.1 0,0.1 0,0.1c " />
<path
android:name="_R_G_L_0_G_G_0_D_1_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M0 0.1 C0,0.1 0,0.69 0,0.69 C0,0.69 0,19.3 0,19.3 C0,19.3 0.55,19.3 0.55,19.3 C0.55,19.3 0.55,0.69 0.55,0.69 C0.55,0.69 17.05,0.69 17.05,0.69 C17.05,0.69 17.4,0 17.4,0 C17.5,0.1 0,0.1 0,0.1c " />
<path
android:name="_R_G_L_0_G_G_0_D_2_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M5.82 33.92 C5.82,33.92 5.2,35 5.2,35 C5.2,35 5.2,19.3 5.2,19.3 C5.2,19.3 5.82,19.3 5.82,19.3 C5.82,19.3 5.82,33.92 5.82,33.92c " />
<path
android:name="_R_G_L_0_G_G_0_D_3_P_0"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:fillType="nonZero"
android:pathData=" M17.08 14.55 C17.08,14.55 11.21,14.55 11.21,14.55 C11.21,14.55 10.4,14 10.4,14 C10.4,14 17.4,14 17.4,14 C17.4,14 17.08,14.55 17.08,14.55c " />
</group>
</group>
</group>
</group>
</group>
</vector>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<item
android:drawable="@drawable/ic_appicon_splashscreen"
android:gravity="center" />
</layer-list>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="81dp"
android:height="20dp"
android:viewportWidth="81"
android:viewportHeight="20">
<path
android:fillColor="?colorControlNormal"
android:pathData="M9.1,0.9C4.1,0.9 0,5 0,10s4.1,9.1 9.1,9.1s9.1,-4.1 9.1,-9.1S14.1,0.9 9.1,0.9zM55.7,2.9c-0.1,0 -0.2,0.1 -0.2,0.2v10.5c0,0.1 0.1,0.2 0.2,0.2h1.4c0.1,0 0.2,-0.1 0.2,-0.2v-0.7c0.7,0.7 1.7,1.2 2.7,1.2c2.1,0 3.9,-1.8 3.9,-4.1S62.1,5.9 60,5.9c-1,0 -2,0.4 -2.7,1.2V3.1c0,-0.1 -0.1,-0.2 -0.2,-0.2H55.7zM10,4.4c1.2,0 2.3,0.5 3.2,1.4c1.8,1.8 1.9,4.7 0.1,6.4c-3.1,3.1 -8.6,2.1 -8.6,2.1s-1,-5.5 2.1,-8.6C7.7,4.8 8.9,4.4 10,4.4zM26.4,5.9c-0.8,0 -1.6,0.4 -2.1,1.1V6.3c0,-0.1 -0.1,-0.2 -0.2,-0.2h-1.4c-0.1,0 -0.2,0.1 -0.2,0.2v7.4c0,0.1 0.1,0.2 0.2,0.2H24c0.1,0 0.2,-0.1 0.2,-0.2V9.3c0.1,-1 0.7,-1.8 1.6,-1.8c0.9,0 1.6,0.7 1.6,1.7v4.5c0,0.1 0.1,0.2 0.2,0.2H29c0.1,0 0.2,-0.1 0.2,-0.2l0,-4.6c0.1,-0.9 0.8,-1.6 1.6,-1.6c0.9,0 1.6,0.7 1.6,1.7v4.5c0,0.1 0.1,0.2 0.2,0.2H34c0.1,0 0.2,-0.1 0.2,-0.2l0,-5.1c0,-1.5 -1.3,-2.7 -2.8,-2.7c-1,0 -2,0.6 -2.4,1.5C28.4,6.5 27.4,5.9 26.4,5.9L26.4,5.9zM39.4,5.9c-2.1,0 -3.9,1.8 -3.9,4.1s1.7,4.1 3.9,4.1c1,0 2,-0.4 2.7,-1.2v0.7c0,0.1 0.1,0.2 0.2,0.2h1.4c0.1,0 0.2,-0.1 0.2,-0.2V6.3c0,-0.1 -0.1,-0.2 -0.2,-0.2h-1.4c-0.1,0 -0.2,0.1 -0.2,0.2V7C41.4,6.3 40.4,5.9 39.4,5.9zM50.2,5.9c-1,0 -2,0.4 -2.7,1.2V6.3c0,-0.1 -0.1,-0.2 -0.2,-0.2h-1.4c-0.1,0 -0.2,0.1 -0.2,0.2v10.5c0,0.1 0.1,0.2 0.2,0.2h1.4c0.1,0 0.2,-0.1 0.2,-0.2v-3.9c0.7,0.7 1.7,1.2 2.7,1.2c2.1,0 3.9,-1.8 3.9,-4.1S52.3,5.9 50.2,5.9zM69.1,5.9c-2.3,0 -4.2,1.8 -4.2,4.1s1.9,4.1 4.2,4.1c2.3,0 4.2,-1.8 4.2,-4.1S71.4,5.9 69.1,5.9zM73.7,6.1c-0.1,0 -0.2,0.1 -0.2,0.2c0,0 0,0.1 0,0.1l2.3,3.6l-2.4,3.6c-0.1,0.1 0,0.2 0.1,0.3c0,0 0.1,0 0.1,0h1.6c0.1,0 0.2,-0.1 0.3,-0.2l1.4,-2.4l1.4,2.4c0.1,0.1 0.2,0.2 0.3,0.2h1.6c0.1,0 0.2,-0.1 0.2,-0.2c0,0 0,-0.1 0,-0.1L78.1,10l2.3,-3.6c0.1,-0.1 0,-0.2 -0.1,-0.3c0,0 -0.1,0 -0.1,0h-1.6c-0.1,0 -0.2,0.1 -0.3,0.2L77,8.6l-1.4,-2.3c-0.1,-0.1 -0.2,-0.2 -0.3,-0.2H73.7zM10.1,6.2L9.2,8.1L7.4,8.9l1.8,0.9l0.9,1.8L11,9.8l1.8,-0.9L11,8.1L10.1,6.2zM39.7,7.5c1.3,0 2.3,1.1 2.4,2.4V10c0,1.3 -1.1,2.4 -2.4,2.4c-1.3,0 -2.4,-1.1 -2.4,-2.5S38.4,7.5 39.7,7.5L39.7,7.5zM49.9,7.5c1.3,0 2.4,1.1 2.4,2.5s-1.1,2.5 -2.4,2.5c-1.3,0 -2.3,-1.1 -2.4,-2.4V10C47.5,8.6 48.6,7.5 49.9,7.5L49.9,7.5zM59.7,7.5C61,7.5 62,8.6 62,10s-1.1,2.5 -2.4,2.5c-1.3,0 -2.3,-1.1 -2.4,-2.4V10C57.3,8.6 58.4,7.5 59.7,7.5L59.7,7.5zM69.1,7.5c1.3,0 2.4,1.1 2.4,2.5s-1.1,2.5 -2.4,2.5c-1.3,0 -2.4,-1.1 -2.4,-2.5S67.8,7.5 69.1,7.5z" />
</vector>

View File

@@ -10,7 +10,8 @@
android:name="net.vonforst.evmap.navigation.NavHostFragment"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:fitsSystemWindows="true" />
android:fitsSystemWindows="true"
app:defaultNavHost="true" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"

View File

@@ -69,7 +69,7 @@
android:focusable="true"
android:focusableInTouchMode="true">
<AutoCompleteTextView
<net.vonforst.evmap.ui.AutocompleteTextViewWithSuggestions
android:id="@+id/search"
android:layout_width="0dp"
android:layout_weight="1"

View File

@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.airbnb.lottie.LottieAnimationView
<ImageView
android:id="@+id/animation_view"
android:layout_width="0dp"
android:layout_height="0dp"
@@ -21,9 +21,8 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.85"
app:layout_constraintWidth_max="256dp"
app:lottie_autoPlay="true"
app:lottie_rawRes="@raw/logo_anim"
app:lottie_speed="0.75" />
app:srcCompat="@drawable/intro_anim_onboarding"
android:contentDescription="@string/app_name" />
<TextView
android:id="@+id/welcomeTitle"

View File

@@ -237,4 +237,11 @@
<string name="github_sponsors">GitHub Sponsors</string>
<string name="donate_desc">Unterstütze die Weiterentwicklung von EVMap mit einer einmaligen Spende</string>
<string name="github_sponsors_desc">Unterstütze EVMap über GitHub Sponsors</string>
<string name="unnamed_filter_profile">Unbenanntes Filterprofil</string>
<string name="privacy_link">https://evmap.vonforst.net/de/privacy.html</string>
<string name="faq_link">https://evmap.vonforst.net/de/faq.html</string>
<string name="required">erforderlich</string>
<string name="edit_filter_profile">„%s“ bearbeiten</string>
<string name="pref_search_delete_recent">Suchverlauf löschen</string>
<string name="deleted_recent_search_results">Suchverlauf wurde gelöscht</string>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="background">#121212</color>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<drawable name="intro_anim_onboarding">@drawable/intro_anim_finished</drawable>
</resources>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme.LaunchScreen" parent="AppTheme.LaunchScreen.Base">
<item name="windowSplashScreenAnimatedIcon">@drawable/intro_anim</item>
</style>
</resources>

View File

@@ -22,4 +22,5 @@
<color name="chargeprice_lock">#546E7A</color>
<color name="chargeprice_star">#00C853</color>
<color name="chip_background">#1F000000</color>
<color name="background">#FFFFFF</color>
</resources>

View File

@@ -2,8 +2,6 @@
<resources>
<string name="shared_element_picture">picture</string>
<string name="github_link">https://github.com/johan12345/EVMap</string>
<string name="privacy_link">https://evmap.vonforst.net/privacy.html</string>
<string name="faq_link">https://evmap.vonforst.net/faq.html</string>
<string name="twitter_handle">\@ev_map</string>
<string name="twitter_url">https://twitter.com/ev_map</string>
<string name="goingelectric_forum_url"><![CDATA[https://www.goingelectric.de/forum/viewtopic.php?f=5&t=56342]]></string>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<drawable name="intro_anim_onboarding">@drawable/intro_anim</drawable>
</resources>

View File

@@ -222,4 +222,11 @@
<string name="github_sponsors">GitHub Sponsors</string>
<string name="donate_desc">Support EVMap\'s development with a one-time donation</string>
<string name="github_sponsors_desc">Support EVMap on GitHub Sponsors</string>
<string name="unnamed_filter_profile">Unnamed filter profile</string>
<string name="privacy_link">https://evmap.vonforst.net/en/privacy.html</string>
<string name="faq_link">https://evmap.vonforst.net/en/faq.html</string>
<string name="required">required</string>
<string name="edit_filter_profile">Edit “%s”</string>
<string name="pref_search_delete_recent">Delete recent search results</string>
<string name="deleted_recent_search_results">Recent search results have been deleted</string>
</resources>

View File

@@ -17,8 +17,14 @@
<style name="AppTheme" parent="AppTheme.Base" />
<style name="AppTheme.LaunchScreen">
<item name="android:windowBackground">@drawable/launch_screen</item>
<style name="AppTheme.LaunchScreen.Base" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/background</item>
<item name="windowSplashScreenAnimationDuration">999</item>
<item name="postSplashScreenTheme">@style/AppTheme</item>
</style>
<style name="AppTheme.LaunchScreen" parent="AppTheme.LaunchScreen.Base">
<item name="windowSplashScreenAnimatedIcon">@drawable/intro_static</item>
</style>
<style name="FullScreenDialogStyle" parent="AppTheme">

View File

@@ -47,6 +47,10 @@
android:defaultValue="@string/pref_search_provider_default"
android:summary="%s" />
<Preference
android:key="search_delete_recent"
android:title="@string/pref_search_delete_recent" />
<CheckBoxPreference
android:key="navigate_use_maps"
android:title="@string/pref_navigate_use_maps"

View File

@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.5.10'
ext.kotlin_version = '1.5.20'
ext.about_libs_version = '8.8.5'
ext.nav_version = '2.3.5'
repositories {
@@ -10,7 +10,7 @@ buildscript {
gradlePluginPortal()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.0'
classpath 'com.android.tools.build:gradle:7.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:$about_libs_version"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"

View File

@@ -0,0 +1,12 @@
Neue Funktionen:
- Android Auto: Preisvergleich mit Chargeprice
- Android Auto: Neuer Bildschirm zur Anzeige von Fahrzeugdaten (falls verfügbar)
- Kürzlich gesuchte Orte werden gespeichert und als Vorschläge angezeigt
- Unterstützung für Android 12
Verbesserungen:
- Android Auto: Nutzung des Fahrzeug-GPS (falls verfügbar, ab Android Auto 6.7)
- In Auswahldialogen werden bereits ausgewählte Einträge nach oben verschoben
- FAQ aktualisiert
- Verbesserte Behandlung des Zurück-Buttons
- Verschiedene Abstürze behoben

View File

@@ -0,0 +1,12 @@
New features:
- Android Auto: Price comparison with Chargeprice (only in certain countries)
- Android Auto: New screen displaying vehicle data (if available)
- Recently searched places are stored and shown as suggestions
- Android 12 support
Improvements:
- Android Auto: Use vehicle GPS (if available, starting with Android Auto 6.7)
- Move already selected entries to the top in selection dialogs
- FAQ and privacy policy updated and now also available in English
- Improved back button handling
- Fixed various crashes