Remove WearOS variant (hasn't been supported for quite some time).

This commit is contained in:
darken
2025-09-29 13:36:21 +02:00
parent da5af8e4b1
commit 0e3ee655ef
136 changed files with 1 additions and 2320 deletions
-17
View File
@@ -67,7 +67,6 @@ jobs:
generate_release_notes: true
files: |
app/build/outputs/apk/foss/beta/*.apk
app-wear/build/outputs/apk/foss/beta/*.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -130,14 +129,6 @@ jobs:
ruby-version: 3.3.6
bundler-cache: true
# - name: Assemble WearOS beta and upload to Google Play
# if: contains(steps.tagger.outputs.tag, '-beta')
# run: bundle exec fastlane beta_wearos
# env:
# STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
# KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
# KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- name: Assemble beta and upload to Google Play
if: contains(steps.tagger.outputs.tag, '-beta')
run: bundle exec fastlane beta
@@ -146,14 +137,6 @@ jobs:
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
# - name: Assemble WearOS production and upload to Google Play
# if: "!contains(steps.tagger.outputs.tag, '-beta')"
# run: bundle exec fastlane production_wearos
# env:
# STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
# KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
# KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
- name: Assemble production and upload to Google Play
if: "!contains(steps.tagger.outputs.tag, '-beta')"
run: bundle exec fastlane production
+1 -2
View File
@@ -65,8 +65,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
### Multi-Module Structure
- **app/**: Main Android application with FOSS and Google Play flavors
- **app-common/**: Shared code between main app and Wear OS
- **app-wear/**: Dedicated Wear OS companion application
- **app-common/**: Shared code between main app
### Core Architecture Patterns
-1
View File
@@ -17,7 +17,6 @@ A companion app that adds support for AirPod specific features to Android:
* Ear detection with automatic play/pause.
* Automatically connect phone & AirPods.
* Show popup when case is opened.
* Support for Wear OS
* Widgets
CAPod is ad-free. Some additional features require an in-app purchase.
-1
View File
@@ -25,6 +25,5 @@ exclude:
- crowdin*
- app
- app-common
- app-wear
- CONTRIBUTING.md
- CLAUDE.md
-1
View File
@@ -1 +0,0 @@
/build
-140
View File
@@ -1,140 +0,0 @@
plugins {
id("com.android.application")
id("kotlin-android")
id("kotlin-kapt")
id("kotlin-parcelize")
}
apply(plugin = "dagger.hilt.android.plugin")
apply(plugin = "androidx.navigation.safeargs.kotlin")
android {
compileSdk = ProjectConfig.compileSdk
namespace = ProjectConfig.packageName
defaultConfig {
applicationId = ProjectConfig.packageName
minSdk = ProjectConfig.minSdk
targetSdk = ProjectConfig.targetSdk
versionCode = ProjectConfig.Version.code + 1 // Wear app
versionName = ProjectConfig.Version.name
testInstrumentationRunner = "eu.darken.capod.HiltTestRunner"
buildConfigField("String", "GITSHA", "\"${lastCommitHash()}\"")
}
signingConfigs {
val basePath = File(System.getProperty("user.home"), ".appconfig/${ProjectConfig.packageName}")
create("releaseFoss") {
setupCredentials(File(basePath, "signing-foss.properties"))
}
create("releaseGplay") {
setupCredentials(File(basePath, "signing-gplay-upload.properties"))
}
}
flavorDimensions.add("version")
productFlavors {
create("foss") {
dimension = "version"
signingConfig = signingConfigs["releaseFoss"]
}
create("gplay") {
dimension = "version"
signingConfig = signingConfigs["releaseGplay"]
}
}
buildTypes {
val customProguardRules = fileTree(File("../proguard")) {
include("*.pro")
}
debug {
isMinifyEnabled = false
isShrinkResources = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
proguardFiles(*customProguardRules.toList().toTypedArray())
proguardFiles("proguard-rules-debug.pro")
}
create("beta") {
lint {
abortOnError = true
fatal.add("StopShip")
}
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
proguardFiles(*customProguardRules.toList().toTypedArray())
}
release {
lint {
abortOnError = true
fatal.add("StopShip")
}
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
proguardFiles(*customProguardRules.toList().toTypedArray())
}
}
buildOutputs.all {
val variantOutputImpl = this as com.android.build.gradle.internal.api.BaseVariantOutputImpl
val variantName: String = variantOutputImpl.name
if (listOf("release", "beta").any { variantName.lowercase().contains(it) }) {
val outputFileName = ProjectConfig.packageName + "-WEAROS" +
"-v${defaultConfig.versionName}-${defaultConfig.versionCode}" +
"-${variantName.uppercase()}.apk"
variantOutputImpl.outputFileName = outputFileName
}
}
buildFeatures {
viewBinding = true
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = freeCompilerArgs + listOf(
"-opt-in=kotlin.ExperimentalStdlibApi",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview",
"-opt-in=kotlin.time.ExperimentalTime",
"-opt-in=kotlin.RequiresOptIn"
)
}
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
implementation(project(":app-common"))
addBaseKotlin()
addDagger()
addBaseWorkManager()
addBaseAndroid()
addBaseAndroidUi()
implementation("androidx.core:core-splashscreen:1.0.1")
addNavigation()
addTesting()
implementation("androidx.wear:wear:1.2.0")
implementation("androidx.wear.tiles:tiles-material:1.1.0")
}
-21
View File
@@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-45
View File
@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="eu.darken.capod">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-feature android:name="android.hardware.type.watch" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:name=".App"
android:theme="@style/AppTheme">
<uses-library
android:name="com.google.android.wearable"
android:required="true" />
<meta-data
android:name="com.google.android.wearable.standalone"
android:value="true" />
<activity
android:name=".wear.ui.MainActivity"
android:exported="true"
android:theme="@style/AppThemeSplash"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
</application>
</manifest>
@@ -1,85 +0,0 @@
package eu.darken.capod
import android.app.Application
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import androidx.work.Data
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import dagger.hilt.android.HiltAndroidApp
import eu.darken.capod.common.BuildConfig
import eu.darken.capod.common.BuildConfigWrap
import eu.darken.capod.common.coroutine.AppScope
import eu.darken.capod.common.debug.autoreport.AutomaticBugReporter
import eu.darken.capod.common.debug.logging.LogCatLogger
import eu.darken.capod.common.debug.logging.Logging
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.asLog
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.main.core.GeneralSettings
import eu.darken.capod.wear.core.MonitorWorker
import kotlinx.coroutines.CoroutineScope
import java.time.Duration
import javax.inject.Inject
@HiltAndroidApp
open class App : Application(), Configuration.Provider {
@Inject lateinit var workerFactory: HiltWorkerFactory
@Inject lateinit var autoReporting: AutomaticBugReporter
@Inject lateinit var generalSettings: GeneralSettings
@Inject lateinit var workManager: WorkManager
@Inject @AppScope lateinit var appScope: CoroutineScope
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) Logging.install(LogCatLogger())
autoReporting.setup(this)
setupWorker()
log(TAG) { "onCreate() done! ${Exception().asLog()}" }
}
private fun setupWorker() {
log(TAG) { "setupWorker()" }
val workRequest = PeriodicWorkRequestBuilder<MonitorWorker>(
Duration.ofMinutes(30),
Duration.ofMinutes(30)
).apply {
setInputData(Data.Builder().build())
}.build()
log(TAG, VERBOSE) { "Worker request: $workRequest" }
val operation = workManager.enqueueUniquePeriodicWork(
"${BuildConfigWrap.APPLICATION_ID}.monitor.worker",
ExistingPeriodicWorkPolicy.KEEP,
workRequest,
)
operation.result.get()
log(TAG) { "Monitor start request send." }
}
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setMinimumLoggingLevel(
when {
BuildConfigWrap.DEBUG -> android.util.Log.VERBOSE
BuildConfigWrap.BUILD_TYPE == BuildConfigWrap.BuildType.DEV -> android.util.Log.DEBUG
BuildConfigWrap.BUILD_TYPE == BuildConfigWrap.BuildType.BETA -> android.util.Log.INFO
BuildConfigWrap.BUILD_TYPE == BuildConfigWrap.BuildType.RELEASE -> android.util.Log.WARN
else -> android.util.Log.VERBOSE
}
)
.setWorkerFactory(workerFactory)
.build()
companion object {
internal val TAG = logTag("CAP")
}
}
@@ -1,92 +0,0 @@
package eu.darken.capod.wear.core
import android.content.Context
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.debug.Bugs
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.debug.logging.logTag
import eu.darken.capod.common.flow.setupCommonEventHandlers
import eu.darken.capod.main.core.PermissionTool
import eu.darken.capod.monitor.core.MonitorCoroutineScope
import eu.darken.capod.monitor.core.PodMonitor
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.take
@HiltWorker
class MonitorWorker @AssistedInject constructor(
@Assisted private val context: Context,
@Assisted private val params: WorkerParameters,
private val dispatcherProvider: DispatcherProvider,
private val permissionTool: PermissionTool,
private val podMonitor: PodMonitor,
) : CoroutineWorker(context, params) {
private val workerScope = MonitorCoroutineScope()
private var finishedWithError = false
init {
log(TAG, VERBOSE) { "init(): workerId=$id" }
}
override suspend fun doWork(): Result = try {
val start = System.currentTimeMillis()
log(TAG, VERBOSE) { "Executing $inputData now (runAttemptCount=$runAttemptCount)" }
doDoWork()
val duration = System.currentTimeMillis() - start
log(TAG, VERBOSE) { "Execution finished after ${duration}ms, $inputData" }
Result.success(inputData)
} catch (e: Throwable) {
if (e !is CancellationException) {
Bugs.report(tag = TAG, "Execution failed", exception = e)
finishedWithError = true
Result.failure(inputData)
} else {
Result.success()
}
} finally {
this.workerScope.cancel("Worker finished (withError?=$finishedWithError).")
}
private suspend fun doDoWork() = withContext(dispatcherProvider.IO) {
val permissionsMissingOnStart = permissionTool.missingPermissions.first()
if (permissionsMissingOnStart.isNotEmpty()) {
log(TAG, WARN) { "Aborting, missing permissions: $permissionsMissingOnStart" }
return@withContext
}
val monitorJob = podMonitor.mainDevice
.filterNotNull()
.take(3)
.setupCommonEventHandlers(TAG) { "monitorJob" }
.launchIn(workerScope)
try {
withTimeout(15 * 1000) {
monitorJob.join()
}
log(TAG) { "Monitor job quit after a few takes." }
} catch (e: TimeoutCancellationException) {
log(TAG) { "Monitor job quit after finding nothing." }
}
}
companion object {
val TAG = logTag("Monitor", "Worker")
}
}
@@ -1,18 +0,0 @@
package eu.darken.capod.wear.core
import android.content.Context
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.util.Locale
data class UserTime(
val time: Instant = Instant.now(),
) {
fun toFormatted(context: Context): String = DateTimeFormatter
.ofLocalizedTime(FormatStyle.SHORT)
.withLocale(Locale.getDefault())
.withZone(ZoneId.systemDefault())
.format(time)
}
@@ -1,35 +0,0 @@
package eu.darken.capod.wear.ui
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.wear.widget.SwipeDismissFrameLayout
import dagger.hilt.android.AndroidEntryPoint
import eu.darken.capod.R
import eu.darken.capod.common.navigation.findNavController
import eu.darken.capod.common.uix.Activity2
import eu.darken.capod.databinding.MainActivityBinding
@AndroidEntryPoint
class MainActivity : Activity2() {
private val vm: MainActivityVM by viewModels()
private lateinit var ui: MainActivityBinding
private val navController by lazy { supportFragmentManager.findNavController(R.id.nav_host) }
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
ui = MainActivityBinding.inflate(layoutInflater)
setContentView(ui.root)
ui.swipeWrapper.addCallback(object : SwipeDismissFrameLayout.Callback() {
override fun onDismissed(layout: SwipeDismissFrameLayout) {
if (!navController.popBackStack()) finish()
super.onDismissed(layout)
}
})
}
}
@@ -1,46 +0,0 @@
package eu.darken.capod.wear.ui
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.permissions.Permission
import eu.darken.capod.common.uix.ViewModel2
import eu.darken.capod.main.core.PermissionTool
import eu.darken.capod.monitor.core.PodMonitor
import eu.darken.capod.pods.core.PodDevice
import kotlinx.coroutines.flow.combine
import javax.inject.Inject
@HiltViewModel
class MainActivityVM @Inject constructor(
handle: SavedStateHandle,
dispatcherProvider: DispatcherProvider,
private val podMonitor: PodMonitor,
private val permissionTool: PermissionTool,
) : ViewModel2(dispatcherProvider = dispatcherProvider) {
sealed class State {
data class PermissionRequired(
val permissions: List<Permission>,
) : State()
data class Devices(
val devices: List<PodDevice>
) : State()
}
val state = combine(
podMonitor.devices,
permissionTool.missingPermissions,
) { devices, missingPermissions ->
when {
missingPermissions.isNotEmpty() -> State.PermissionRequired(
permissions = missingPermissions.toList()
)
else -> State.Devices(
devices = devices
)
}
}
}
@@ -1,45 +0,0 @@
package eu.darken.capod.wear.ui.overview
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.viewbinding.ViewBinding
import eu.darken.capod.common.lists.BindableVH
import eu.darken.capod.common.lists.differ.AsyncDiffer
import eu.darken.capod.common.lists.differ.DifferItem
import eu.darken.capod.common.lists.differ.HasAsyncDiffer
import eu.darken.capod.common.lists.differ.setupDiffer
import eu.darken.capod.common.lists.modular.ModularAdapter
import eu.darken.capod.common.lists.modular.mods.DataBinderMod
import eu.darken.capod.common.lists.modular.mods.TypedVHCreatorMod
import eu.darken.capod.wear.ui.overview.cards.BluetoothDisabledVH
import eu.darken.capod.wear.ui.overview.cards.MissingMainDeviceVH
import eu.darken.capod.wear.ui.overview.cards.PermissionCardVH
import eu.darken.capod.wear.ui.overview.cards.pods.DualPodsCardVH
import eu.darken.capod.wear.ui.overview.cards.pods.SinglePodsCardVH
import javax.inject.Inject
class OverviewAdapter @Inject constructor() :
ModularAdapter<OverviewAdapter.BaseVH<OverviewAdapter.Item, ViewBinding>>(),
HasAsyncDiffer<OverviewAdapter.Item> {
override val asyncDiffer: AsyncDiffer<*, Item> = setupDiffer()
init {
modules.add(DataBinderMod(data))
modules.add(TypedVHCreatorMod({ data[it] is PermissionCardVH.Item }) { PermissionCardVH(it) })
modules.add(TypedVHCreatorMod({ data[it] is DualPodsCardVH.Item }) { DualPodsCardVH(it) })
modules.add(TypedVHCreatorMod({ data[it] is SinglePodsCardVH.Item }) { SinglePodsCardVH(it) })
modules.add(TypedVHCreatorMod({ data[it] is MissingMainDeviceVH.Item }) { MissingMainDeviceVH(it) })
modules.add(TypedVHCreatorMod({ data[it] is BluetoothDisabledVH.Item }) { BluetoothDisabledVH(it) })
}
override fun getItemCount(): Int = data.size
abstract class BaseVH<D : Item, B : ViewBinding>(
@LayoutRes layoutId: Int,
parent: ViewGroup
) : ModularAdapter.VH(layoutId, parent), BindableVH<D, B>
interface Item : DifferItem
}
@@ -1,95 +0,0 @@
package eu.darken.capod.wear.ui.overview
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint
import eu.darken.capod.R
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.lists.differ.update
import eu.darken.capod.common.permissions.Permission
import eu.darken.capod.common.uix.Fragment3
import eu.darken.capod.common.viewbinding.viewBinding
import eu.darken.capod.databinding.MainFragmentBinding
import javax.inject.Inject
@AndroidEntryPoint
class OverviewFragment : Fragment3(R.layout.main_fragment) {
override val vm: OverviewFragmentVM by viewModels()
override val ui: MainFragmentBinding by viewBinding()
@Inject
lateinit var overviewAdapter: OverviewAdapter
lateinit var permissionLauncher: ActivityResultLauncher<String>
var awaitingPermission = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
awaitingPermission = savedInstanceState?.getBoolean("awaitingPermission") ?: false
permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
log { "Request for $id was granted=$granted" }
vm.onPermissionResult(granted)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
ui.list.apply {
layoutManager = LinearLayoutManager(context)
this.adapter = overviewAdapter
}
vm.listItems.observe2(ui) { overviewAdapter.update(it) }
vm.requestPermissionEvent.observe2(ui) {
when (it) {
Permission.IGNORE_BATTERY_OPTIMIZATION -> {
awaitingPermission = true
startActivity(
Intent(
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:${requireContext().packageName}")
)
)
}
Permission.SYSTEM_ALERT_WINDOW -> {
awaitingPermission = true
startActivity(
Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:${requireContext().packageName}")
)
)
}
else -> {
permissionLauncher.launch(it.permissionId)
}
}
}
super.onViewCreated(view, savedInstanceState)
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putBoolean("awaitingPermission", awaitingPermission)
super.onSaveInstanceState(outState)
}
override fun onResume() {
super.onResume()
if (awaitingPermission) {
awaitingPermission = false
log { "awaitingPermission=true" }
vm.onPermissionResult(true)
}
}
}
@@ -1,115 +0,0 @@
package eu.darken.capod.wear.ui.overview
import androidx.lifecycle.LiveData
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.capod.common.bluetooth.BluetoothManager2
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.debug.DebugSettings
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.capod.common.debug.logging.log
import eu.darken.capod.common.flow.combine
import eu.darken.capod.common.flow.throttleLatest
import eu.darken.capod.common.livedata.SingleLiveEvent
import eu.darken.capod.common.permissions.Permission
import eu.darken.capod.common.uix.ViewModel3
import eu.darken.capod.main.core.PermissionTool
import eu.darken.capod.monitor.core.PodMonitor
import eu.darken.capod.pods.core.DualPodDevice
import eu.darken.capod.pods.core.SinglePodDevice
import eu.darken.capod.wear.core.UserTime
import eu.darken.capod.wear.ui.overview.cards.BluetoothDisabledVH
import eu.darken.capod.wear.ui.overview.cards.MissingMainDeviceVH
import eu.darken.capod.wear.ui.overview.cards.PermissionCardVH
import eu.darken.capod.wear.ui.overview.cards.pods.DualPodsCardVH
import eu.darken.capod.wear.ui.overview.cards.pods.SinglePodsCardVH
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.isActive
import java.time.Instant
import javax.inject.Inject
@HiltViewModel
class OverviewFragmentVM @Inject constructor(
@Suppress("UNUSED_PARAMETER") handle: SavedStateHandle,
dispatcherProvider: DispatcherProvider,
private val podMonitor: PodMonitor,
private val permissionTool: PermissionTool,
debugSettings: DebugSettings,
private val bluetoothManager: BluetoothManager2,
) : ViewModel3(dispatcherProvider = dispatcherProvider) {
private val updateTicker = channelFlow<Unit> {
while (isActive) {
trySend(Unit)
delay(3000)
}
}
val requestPermissionEvent = SingleLiveEvent<Permission>()
private val mainDevice = podMonitor.mainDevice.throttleLatest(1000)
val listItems: LiveData<List<OverviewAdapter.Item>> = combine(
updateTicker,
permissionTool.missingPermissions,
debugSettings.isDebugModeEnabled.flow,
bluetoothManager.isBluetoothEnabled,
mainDevice,
) { _, permissions, isDebugMode, isBluetoothEnabled, _ ->
val items = mutableListOf<OverviewAdapter.Item>()
if (permissions.isNotEmpty()) {
permissions
.map { perm ->
PermissionCardVH.Item(
permission = perm,
onRequest = { requestPermissionEvent.postValue(it) },
)
}
.run { items.addAll(this) }
return@combine items
}
if (!isBluetoothEnabled) {
items.add(0, BluetoothDisabledVH.Item)
return@combine items
}
val podToShow = podMonitor.latestMainDevice()
log(TAG, VERBOSE) { "Showing $podToShow" }
val now = Instant.now()
val pod = when (podToShow) {
is DualPodDevice -> DualPodsCardVH.Item(
now = now,
device = podToShow,
showDebug = isDebugMode,
isMainPod = true,
userTime = UserTime(),
)
is SinglePodDevice -> SinglePodsCardVH.Item(
now = now,
device = podToShow,
showDebug = isDebugMode,
isMainPod = true,
userTime = UserTime(),
)
else -> MissingMainDeviceVH.Item(
userTime = UserTime(),
)
}
items.add(pod)
items
}
.catch { errorEvents.postValue(it) }
.asLiveData2()
fun onPermissionResult(granted: Boolean) {
if (granted) permissionTool.recheck()
}
}
@@ -1,33 +0,0 @@
package eu.darken.capod.wear.ui.overview.cards
import android.view.ViewGroup
import eu.darken.capod.R
import eu.darken.capod.common.lists.binding
import eu.darken.capod.common.lists.differ.DifferItem
import eu.darken.capod.databinding.OverviewBluetoothDisabledItemBinding
import eu.darken.capod.wear.ui.overview.OverviewAdapter
class BluetoothDisabledVH(parent: ViewGroup) :
OverviewAdapter.BaseVH<BluetoothDisabledVH.Item, OverviewBluetoothDisabledItemBinding>(
R.layout.overview_bluetooth_disabled_item,
parent
) {
override val viewBinding = lazy {
OverviewBluetoothDisabledItemBinding.bind(itemView)
}
override val onBindData: OverviewBluetoothDisabledItemBinding.(
item: Item,
payloads: List<Any>
) -> Unit = binding(payload = true) { item ->
}
object Item : OverviewAdapter.Item {
override val stableId: Long = Item::class.hashCode().toLong()
override val payloadProvider: ((DifferItem, DifferItem) -> DifferItem?)
get() = { old, new -> if (new::class.isInstance(old)) new else null }
}
}
@@ -1,37 +0,0 @@
package eu.darken.capod.wear.ui.overview.cards
import android.view.ViewGroup
import eu.darken.capod.R
import eu.darken.capod.common.lists.binding
import eu.darken.capod.common.lists.differ.DifferItem
import eu.darken.capod.databinding.OverviewNomaindeviceItemBinding
import eu.darken.capod.wear.core.UserTime
import eu.darken.capod.wear.ui.overview.OverviewAdapter
class MissingMainDeviceVH(parent: ViewGroup) :
OverviewAdapter.BaseVH<MissingMainDeviceVH.Item, OverviewNomaindeviceItemBinding>(
R.layout.overview_nomaindevice_item,
parent
) {
override val viewBinding = lazy {
OverviewNomaindeviceItemBinding.bind(itemView)
}
override val onBindData: OverviewNomaindeviceItemBinding.(
item: Item,
payloads: List<Any>
) -> Unit = binding(payload = true) { item ->
userTime.text = item.userTime.toFormatted(context)
}
data class Item(
val userTime: UserTime,
) : OverviewAdapter.Item {
override val stableId: Long = this.hashCode().toLong()
override val payloadProvider: ((DifferItem, DifferItem) -> DifferItem?)
get() = { old, new -> if (new::class.isInstance(old)) new else null }
}
}
@@ -1,39 +0,0 @@
package eu.darken.capod.wear.ui.overview.cards
import android.view.ViewGroup
import eu.darken.capod.R
import eu.darken.capod.common.lists.binding
import eu.darken.capod.common.lists.differ.DifferItem
import eu.darken.capod.common.permissions.Permission
import eu.darken.capod.databinding.OverviewPermissionItemBinding
import eu.darken.capod.wear.ui.overview.OverviewAdapter
class PermissionCardVH(parent: ViewGroup) :
OverviewAdapter.BaseVH<PermissionCardVH.Item, OverviewPermissionItemBinding>(
R.layout.overview_permission_item,
parent
) {
override val viewBinding = lazy {
OverviewPermissionItemBinding.bind(itemView)
}
override val onBindData: OverviewPermissionItemBinding.(
item: Item,
payloads: List<Any>
) -> Unit = binding(payload = true) { item ->
permissionLabel.setText(item.permission.labelRes)
permissionDescription.setText(item.permission.descriptionRes)
grantAction.setOnClickListener { item.onRequest(item.permission) }
}
data class Item(
val permission: Permission,
val onRequest: (Permission) -> Unit
) : OverviewAdapter.Item {
override val stableId: Long = permission.hashCode().toLong()
override val payloadProvider: ((DifferItem, DifferItem) -> DifferItem?)
get() = { old, new -> if (new::class.isInstance(old)) new else null }
}
}
@@ -1,136 +0,0 @@
package eu.darken.capod.wear.ui.overview.cards.pods
import android.graphics.Typeface
import android.view.ViewGroup
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import eu.darken.capod.R
import eu.darken.capod.common.lists.binding
import eu.darken.capod.databinding.OverviewPodsDualItemBinding
import eu.darken.capod.pods.core.*
import eu.darken.capod.pods.core.apple.DualApplePods
import eu.darken.capod.wear.core.UserTime
import java.time.Instant
class DualPodsCardVH(parent: ViewGroup) :
PodDeviceVH<DualPodsCardVH.Item, OverviewPodsDualItemBinding>(
R.layout.overview_pods_dual_item,
parent
) {
override val viewBinding = lazy { OverviewPodsDualItemBinding.bind(itemView) }
override val onBindData = binding(payload = true) { item: Item ->
userTime.text = item.userTime.toFormatted(context)
val device = item.device
name.apply {
val sb = StringBuilder(device.getLabel(context))
if (device is HasPodStyle && item.showDebug) {
val style = device.podStyle
sb.append(" (${style.getColor(context)})")
}
text = sb
if (item.isMainPod) setTypeface(null, Typeface.BOLD)
else setTypeface(null, Typeface.NORMAL)
if (device is DualApplePods && item.showDebug) {
append(" [${device.primaryPod.name}]")
}
}
deviceIcon.setImageResource(device.iconRes)
podLeftIcon.setImageResource(device.leftPodIcon)
podRightIcon.setImageResource(device.rightPodIcon)
lastSeen.text = device.lastSeenFormatted(item.now)
// Pods battery state
device.apply {
podLeftBatteryIcon.setImageResource(getBatteryDrawable(batteryLeftPodPercent))
podLeftBatteryLabel.text = getBatteryLevelLeftPod(context)
podRightBatteryIcon.setImageResource(getBatteryDrawable(batteryRightPodPercent))
podRightBatteryLabel.text = getBatteryLevelRightPod(context)
}
// Pods charging state
device.apply {
if (this is HasChargeDetectionDual) {
podLeftChargingIcon.isInvisible = !isLeftPodCharging
podRightChargingIcon.isInvisible = !isRightPodCharging
} else {
podLeftChargingIcon.isGone = true
podRightChargingIcon.isGone = true
}
}
// Microphone state
device.apply {
if (this is HasDualMicrophone) {
podLeftMicrophoneIcon.isInvisible = !isLeftPodMicrophone
podRightMicrophoneIcon.isInvisible = !isRightPodMicrophone
} else {
podLeftMicrophoneIcon.isGone = true
podRightMicrophoneIcon.isGone = true
}
}
// Pods wear state
device.apply {
if (this is HasEarDetectionDual) {
podLeftWearIcon.isInvisible = !isLeftPodInEar
podRightWearIcon.isInvisible = !isRightPodInEar
} else {
podLeftWearIcon.isGone = true
podRightWearIcon.isGone = true
}
}
// Case charge state
device.apply {
if (this is HasCase) {
podCaseIcon.setImageResource(caseIcon)
podCaseBatteryIcon.isGone = false
podCaseBatteryIcon.setImageResource(getBatteryDrawable(batteryCasePercent))
podCaseBatteryLabel.text = getBatteryLevelCase(context)
podCaseChargingIcon.isInvisible = !isCaseCharging
} else {
podCaseBatteryIcon.isGone = true
podCaseBatteryLabel.isGone = true
podCaseChargingIcon.isGone = true
}
}
// Connection state
device.apply {
val sb = StringBuilder()
if (this is HasStateDetection) {
sb.append(state.getLabel(context))
}
if (item.showDebug) {
sb.append("\n\n").append("---Debug---")
sb.append("\n").append(rawDataHex)
}
status.text = sb
status.isGone = sb.isEmpty()
}
}
data class Item(
override val now: Instant,
override val device: DualPodDevice,
override val showDebug: Boolean,
override val isMainPod: Boolean,
val userTime: UserTime,
) : PodDeviceVH.Item
}
@@ -1,41 +0,0 @@
package eu.darken.capod.wear.ui.overview.cards.pods
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.viewbinding.ViewBinding
import eu.darken.capod.common.lists.BindableVH
import eu.darken.capod.common.lists.differ.DifferItem
import eu.darken.capod.common.lists.modular.ModularAdapter
import eu.darken.capod.pods.core.PodDevice
import eu.darken.capod.pods.core.getSignalQuality
import eu.darken.capod.wear.ui.overview.OverviewAdapter
import java.time.Instant
abstract class PodDeviceVH<D : PodDeviceVH.Item, B : ViewBinding>(
@LayoutRes layoutId: Int,
parent: ViewGroup
) : ModularAdapter.VH(layoutId, parent), BindableVH<D, B> {
fun Item.getReceptionText(): String = device.getSignalQuality(context)
.let { if (showDebug) "$it ${device.seenCounter}" else it }
.let { if (isMainPod) "$it\n(${getString(eu.darken.capod.common.R.string.pods_yours)})" else it }
interface Item : OverviewAdapter.Item {
val now: Instant
val device: PodDevice
val showDebug: Boolean
val isMainPod: Boolean
override val stableId: Long get() = device.identifier.hashCode().toLong()
override val payloadProvider: ((DifferItem, DifferItem) -> DifferItem?)?
get() = { old, new ->
if (new::class.isInstance(old)) new else null
}
}
}
@@ -1,83 +0,0 @@
package eu.darken.capod.wear.ui.overview.cards.pods
import android.graphics.Typeface
import android.view.ViewGroup
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import eu.darken.capod.R
import eu.darken.capod.common.lists.binding
import eu.darken.capod.databinding.OverviewPodsSingleItemBinding
import eu.darken.capod.pods.core.*
import eu.darken.capod.wear.core.UserTime
import java.time.Instant
class SinglePodsCardVH(parent: ViewGroup) :
PodDeviceVH<SinglePodsCardVH.Item, OverviewPodsSingleItemBinding>(
R.layout.overview_pods_single_item,
parent
) {
override val viewBinding = lazy { OverviewPodsSingleItemBinding.bind(itemView) }
override val onBindData = binding(payload = true) { item: Item ->
userTime.text = item.userTime.toFormatted(context)
val device = item.device
name.apply {
text = device.getLabel(context)
if (item.isMainPod) setTypeface(null, Typeface.BOLD)
else setTypeface(null, Typeface.NORMAL)
}
deviceIcon.setImageResource(device.iconRes)
lastSeen.text = device.lastSeenFormatted(item.now)
// Battery level
device.apply {
batteryLabel.text = getBatteryLevelHeadset(context)
batteryIcon.setImageResource(getBatteryDrawable(batteryHeadsetPercent))
}
// Charge state
device.apply {
if (this is HasChargeDetection) {
chargingIcon.isInvisible = isHeadsetBeingCharged
chargingLabel.isInvisible = isHeadsetBeingCharged
} else {
chargingIcon.isGone = true
chargingLabel.isGone = true
}
}
// Has ear detection
device.apply {
if (this is HasEarDetection) {
wearIcon.isInvisible = isBeingWorn
wearLabel.isInvisible = isBeingWorn
} else {
wearIcon.isGone = true
wearLabel.isGone = true
}
}
status.apply {
val sb = StringBuilder()
if (item.showDebug) {
sb.append("--- Debug ---")
sb.append("\n").append(device.rawDataHex)
}
text = sb
isGone = !item.showDebug
}
}
data class Item(
override val now: Instant,
override val device: SinglePodDevice,
override val showDebug: Boolean,
override val isMainPod: Boolean,
val userTime: UserTime,
) : PodDeviceVH.Item
}
@@ -1,24 +0,0 @@
package eu.darken.capod.wear.ui.settings
import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
import eu.darken.capod.R
import eu.darken.capod.common.BuildConfigWrap
import eu.darken.capod.common.uix.Fragment3
import eu.darken.capod.common.viewbinding.viewBinding
import eu.darken.capod.databinding.SettingsFragmentBinding
@AndroidEntryPoint
class SettingsFragment : Fragment3(R.layout.settings_fragment) {
override val vm: SettingsFragmentVM by viewModels()
override val ui: SettingsFragmentBinding by viewBinding()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
ui.appVersion.text = BuildConfigWrap.VERSION_DESCRIPTION_TINY
super.onViewCreated(view, savedInstanceState)
}
}
@@ -1,13 +0,0 @@
package eu.darken.capod.wear.ui.settings
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.capod.common.coroutine.DispatcherProvider
import eu.darken.capod.common.uix.ViewModel3
import javax.inject.Inject
@HiltViewModel
class SettingsFragmentVM @Inject constructor(
@Suppress("UNUSED_PARAMETER") handle: SavedStateHandle,
dispatcherProvider: DispatcherProvider,
) : ViewModel3(dispatcherProvider = dispatcherProvider)
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:width="48dp"
android:height="48dp"
android:drawable="@mipmap/ic_launcher"
android:gravity="center" />
</layer-list>
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".wear.ui.MainActivity">
<androidx.wear.widget.SwipeDismissFrameLayout
android:id="@+id/swipe_wrapper"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.wear.widget.SwipeDismissFrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="0dp"
android:layout_height="0dp"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/overview_pods_dual_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/bluetooth_label"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/overview_bluetooth_disabled_label"
app:layout_constraintBottom_toTopOf="@+id/bluetooth_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/bluetooth_description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="32dp"
android:text="@string/overview_bluetooth_disabled_description"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bluetooth_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/user_time"
style="@style/UserTimeStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12:23" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/overview_nomaindevice_label"
app:layout_constraintBottom_toTopOf="@id/body"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/body"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="32dp"
android:text="@string/overview_nomaindevice_description"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/title" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/request_description"
style="@style/TextAppearance.Material3.LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/permission_required_title"
app:layout_constraintBottom_toTopOf="@+id/permission_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/permission_label"
style="@style/TextAppearance.Material3.BodyLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="@+id/permission_description"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/request_description"
tools:text="BLUETOOTH_CONNECT" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/permission_description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@+id/grant_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/permission_label"
tools:text="Lorem Ipsum" />
<com.google.android.material.button.MaterialButton
android:id="@+id/grant_action"
style="@style/Widget.Material3.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:text="@string/general_grant_permission_action"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/permission_description" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,289 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
tools:context=".wear.ui.MainActivity">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/user_time"
style="@style/UserTimeStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12:23" />
<ImageView
android:id="@+id/device_icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/devic_airpods_gen1_both" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/name"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
app:layout_constraintBottom_toTopOf="@+id/status"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/device_icon"
tools:text="Apple AirPods Pro" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/status"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:layout_marginBottom="4dp"
android:gravity="center"
android:lines="2"
android:maxLines="2"
app:layout_constraintBottom_toTopOf="@id/barrier_top"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/name"
app:lineHeight="14sp"
tools:text="Music Active, Case Closed" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="status" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/pod_left_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
app:layout_constraintEnd_toStartOf="@id/pod_case_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/pod_right_container">
<ImageView
android:id="@+id/pod_left_icon"
style="@style/PodInfoItemIcon"
android:layout_marginHorizontal="2dp"
android:contentDescription="@string/pods_dual_left_label"
android:src="@drawable/devic_airpods_gen1_left"
app:layout_constraintEnd_toStartOf="@+id/pod_left_wear_icon"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/pod_left_wear_icon"
style="@style/PodInfoItemIcon"
android:layout_marginHorizontal="2dp"
android:src="@drawable/ic_baseline_hearing_24"
app:layout_constraintBottom_toBottomOf="@id/pod_left_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/pod_left_icon"
app:layout_constraintTop_toTopOf="@id/pod_left_icon" />
<ImageView
android:id="@+id/pod_left_battery_icon"
style="@style/PodInfoItemIcon"
android:layout_marginTop="1dp"
android:src="@drawable/ic_baseline_battery_unknown_24"
app:layout_constraintBottom_toTopOf="@id/pod_left_battery_label"
app:layout_constraintEnd_toStartOf="@+id/pod_left_charging_icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pod_left_icon" />
<ImageView
android:id="@+id/pod_left_charging_icon"
style="@style/PodInfoItemIcon"
android:src="@drawable/ic_baseline_power_24"
app:layout_constraintBottom_toBottomOf="@id/pod_left_battery_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/pod_left_battery_icon"
app:layout_constraintTop_toTopOf="@id/pod_left_battery_icon" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/pod_left_battery_label"
style="@style/PodInfoItemText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:text="@string/general_value_not_available_label"
app:layout_constraintEnd_toEndOf="@id/pod_left_charging_icon"
app:layout_constraintStart_toStartOf="@id/pod_left_battery_icon"
app:layout_constraintTop_toBottomOf="@id/pod_left_battery_icon" />
<ImageView
android:id="@+id/pod_left_microphone_icon"
style="@style/PodInfoItemIcon"
android:layout_marginHorizontal="2dp"
android:layout_marginTop="1dp"
android:src="@drawable/ic_baseline_keyboard_voice_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.85"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pod_left_battery_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/pod_case_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
app:layout_constraintBottom_toBottomOf="@id/pod_left_container"
app:layout_constraintEnd_toStartOf="@id/pod_right_container"
app:layout_constraintStart_toEndOf="@id/pod_left_container"
app:layout_constraintTop_toTopOf="@id/pod_left_container"
app:layout_constraintVertical_bias="0.0">
<ImageView
android:id="@+id/pod_case_icon"
style="@style/PodInfoItemIcon"
android:src="@drawable/devic_airpods_gen1_case"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/pod_case_battery_icon"
style="@style/PodInfoItemIcon"
android:layout_marginTop="1dp"
android:src="@drawable/ic_baseline_battery_unknown_24"
app:layout_constraintBottom_toTopOf="@id/pod_case_battery_label"
app:layout_constraintEnd_toStartOf="@+id/pod_case_charging_icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pod_case_icon" />
<ImageView
android:id="@+id/pod_case_charging_icon"
style="@style/PodInfoItemIcon"
android:src="@drawable/ic_baseline_power_24"
app:layout_constraintBottom_toBottomOf="@id/pod_case_battery_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/pod_case_battery_icon"
app:layout_constraintTop_toTopOf="@id/pod_case_battery_icon" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/pod_case_battery_label"
style="@style/PodInfoItemText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:text="@string/general_value_not_available_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pod_case_battery_icon" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/pod_right_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/pod_case_container"
app:layout_constraintTop_toBottomOf="@id/barrier_top">
<ImageView
android:id="@+id/pod_right_icon"
style="@style/PodInfoItemIcon"
android:layout_marginHorizontal="2dp"
android:contentDescription="@string/pods_dual_right_label"
android:src="@drawable/devic_airpods_gen1_right"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="@+id/pod_right_wear_icon"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/pod_right_wear_icon"
style="@style/PodInfoItemIcon"
android:layout_marginHorizontal="2dp"
android:src="@drawable/ic_baseline_hearing_24"
app:layout_constraintBottom_toBottomOf="@id/pod_right_icon"
app:layout_constraintEnd_toStartOf="@id/pod_right_icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/pod_right_icon" />
<ImageView
android:id="@+id/pod_right_battery_icon"
style="@style/PodInfoItemIcon"
android:layout_marginTop="1dp"
android:src="@drawable/ic_baseline_battery_unknown_24"
app:layout_constraintBottom_toTopOf="@id/pod_right_battery_label"
app:layout_constraintEnd_toStartOf="@+id/pod_right_charging_icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pod_right_icon" />
<ImageView
android:id="@+id/pod_right_charging_icon"
style="@style/PodInfoItemIcon"
android:src="@drawable/ic_baseline_power_24"
app:layout_constraintBottom_toBottomOf="@id/pod_right_battery_icon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/pod_right_battery_icon"
app:layout_constraintTop_toTopOf="@id/pod_right_battery_icon" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/pod_right_battery_label"
style="@style/PodInfoItemText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="1dp"
android:text="@string/general_value_not_available_label"
app:layout_constraintEnd_toEndOf="@id/pod_right_charging_icon"
app:layout_constraintStart_toStartOf="@id/pod_right_battery_icon"
app:layout_constraintTop_toBottomOf="@id/pod_right_battery_icon" />
<ImageView
android:id="@+id/pod_right_microphone_icon"
style="@style/PodInfoItemIcon"
android:layout_marginHorizontal="2dp"
android:layout_marginTop="1dp"
android:src="@drawable/ic_baseline_keyboard_voice_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.15"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pod_right_battery_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top"
app:constraint_referenced_ids="last_seen" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/last_seen"
style="@style/TextAppearance.Material3.LabelSmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="32dp"
android:gravity="center"
android:lines="2"
android:maxLines="2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/barrier_bottom"
tools:text="3s ago" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,158 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
tools:context=".wear.ui.MainActivity">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/user_time"
style="@style/UserTimeStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="12:23" />
<ImageView
android:id="@+id/device_icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/devic_headphones_generic" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/name"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
app:layout_constraintBottom_toTopOf="@+id/status"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/device_icon"
tools:text="Apple AirPods Max" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/status"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="8dp"
android:gravity="center"
android:lines="2"
android:maxLines="2"
app:layout_constraintBottom_toTopOf="@id/barrier_top"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/name"
tools:text="Music Active, Case Closed" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="status" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/pod_case_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
app:layout_constraintBottom_toTopOf="@id/barrier_bottom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier_top"
app:layout_constraintVertical_bias="0.20">
<ImageView
android:id="@+id/battery_icon"
style="@style/PodInfoItemIcon"
android:src="@drawable/ic_baseline_battery_unknown_24"
app:layout_constraintBottom_toBottomOf="@id/battery_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/battery_label" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/battery_label"
style="@style/PodInfoItemText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:text="@string/general_value_not_available_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/battery_icon"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/charging_icon"
style="@style/PodInfoItemIcon"
android:src="@drawable/ic_baseline_power_24"
app:layout_constraintBottom_toBottomOf="@id/charging_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/charging_label" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/charging_label"
style="@style/PodInfoItemText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:text="@string/pods_charging_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/charging_icon"
app:layout_constraintTop_toBottomOf="@id/battery_label" />
<ImageView
android:id="@+id/wear_icon"
style="@style/PodInfoItemIcon"
android:src="@drawable/ic_baseline_hearing_24"
app:layout_constraintBottom_toBottomOf="@id/wear_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/wear_label" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/wear_label"
style="@style/PodInfoItemText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="2dp"
android:text="@string/headset_being_worn_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/wear_icon"
app:layout_constraintTop_toBottomOf="@id/charging_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top"
app:constraint_referenced_ids="last_seen" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/last_seen"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:gravity="center"
app:drawableStartCompat="@drawable/ic_baseline_watch_later_12"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="3s ago" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorPrimary"
android:gravity="center"
android:orientation="vertical"
android:paddingHorizontal="8dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_baseline_settings_24"
app:tint="?colorOnPrimary" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/app_version"
style="@style/TextAppearance.Material3.LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLines="1"
android:textColor="?colorOnPrimary"
tools:text="v1.0.0" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
android:id="@+id/main"
app:startDestination="@id/overviewFragment">
<fragment
android:id="@+id/overviewFragment"
android:name="eu.darken.capod.wear.ui.overview.OverviewFragment"
tools:layout="@layout/main_fragment">
<action
android:id="@+id/action_overviewFragment_to_settingsFragment"
app:destination="@id/settingsFragment" />
</fragment>
<fragment
android:id="@+id/settingsFragment"
android:name="eu.darken.capod.wear.ui.settings.SettingsFragment"
android:label="SettingsFragment"
tools:layout="@layout/settings_fragment" />
</navigation>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
</resources>

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