Skip to content
Snippets Groups Projects
Unverified Commit 7856f87c authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

wip: impl with custom navigation

parent 5af15372
Branches
No related tags found
No related merge requests found
Showing
with 828 additions and 46 deletions
@file:Suppress("UnstableApiUsage")
/*
* Quasseldroid - Quassel client for Android
*
* Copyright (c) 2019 Janne Mareike Koschinski
* Copyright (c) 2019 The Quassel Project
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
plugins {
id("justjanne.kotlin")
alias(libs.plugins.kotlin.serialization)
}
dependencies {
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines.core)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.kotlin.test)
testImplementation(libs.junit.api)
testImplementation(libs.junit.params)
testRuntimeOnly(libs.junit.engine)
implementation(libs.kotlinx.datetime)
implementation(libs.okhttp)
implementation(libs.retrofit.core)
implementation(libs.retrofit.converter.kotlinx)
implementation(libs.kotlinx.serialization.json)
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/lib/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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
# The project is open source anyway, obfuscation is useless.
-dontobfuscate
# remove unnecessary warnings
# Android HTTP Libs
-dontnote android.net.http.**
-dontnote org.apache.http.**
# Kotlin stuff
-dontnote kotlin.**
# Gson
-dontnote com.google.gson.**
# Dagger
-dontwarn com.google.errorprone.annotations.*
# Retrofit
-dontwarn retrofit2.**
# Annotation used by Retrofit on Java 8 VMs
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
-dontwarn javax.annotation.concurrent.GuardedBy
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
# Okio
-dontwarn okio.**
-dontwarn org.conscrypt.**
# OkHttp3
-dontwarn okhttp3.**
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete
import kotlinx.serialization.Serializable
@Serializable
@JvmInline
value class BarcodeId(val value: Long)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete
import kotlinx.serialization.Serializable
@Serializable
@JvmInline
value class DrinkId(val value: Long)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete
import kotlinx.serialization.Serializable
@Serializable
data class PwaIcon(
val src: String?,
val sizes: String?,
val type: String?
)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class PwaManifest(
val name: String?,
@SerialName("short_name")
val shortName: String?,
val icons: List<PwaIcon>,
val display: String?,
@SerialName("start_url")
val startUrl: String?,
val scope: String?
)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete
import kotlinx.serialization.Serializable
@Serializable
@JvmInline
value class UserId(val value: Long)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete.v1
import de.chaosdorf.mete.DrinkId
import de.chaosdorf.mete.UserId
import kotlinx.datetime.Instant
data class AuditEntryModelV1(
val difference: Double,
val drink: DrinkId,
val user: UserId,
val createdAt: Instant
)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete.v1
import de.chaosdorf.mete.BarcodeId
import de.chaosdorf.mete.DrinkId
import kotlinx.serialization.Serializable
@Serializable
data class BarcodeModelV1(
val id: BarcodeId,
val drink: DrinkId,
)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete.v1
import de.chaosdorf.mete.DrinkId
import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class DrinkModelV1(
val id: DrinkId,
val name: String,
@SerialName("bottle_size")
val bottleSize: Double,
val caffeine: Int?,
val price: Double,
@SerialName("logo_file_name")
val logoFileName: String,
@SerialName("created_at")
val createdAt: Instant,
@SerialName("updated_at")
val updatedAt: Instant,
@SerialName("logo_content_type")
val logoContentType: String,
@SerialName("logo_file_size")
val logoFileSize: Long,
@SerialName("logo_updated_at")
val logoUpdatedAt: Instant,
@SerialName("logo_url")
val logoUrl: String,
val active: Boolean
)
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete.v1
interface MeteApiFactory<T> {
fun newInstance(baseUrl: String): T
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete.v1
import de.chaosdorf.mete.DrinkId
import de.chaosdorf.mete.PwaManifest
import de.chaosdorf.mete.UserId
import retrofit2.http.GET
import retrofit2.http.Path
interface MeteApiV1 {
@GET("manifest.json")
suspend fun getManifest(): PwaManifest?
@GET("api/v1/audits.json")
suspend fun getAudits(): List<AuditEntryModelV1>
@GET("api/v1/barcodes.json")
suspend fun listBarcodes(): List<BarcodeModelV1>
@GET("api/v1/barcodes/{id}.json")
suspend fun getBarcode(): BarcodeModelV1?
@GET("api/v1/drinks.json")
suspend fun listDrinks(): List<DrinkModelV1>
@GET("api/v1/drinks/{id}.json")
suspend fun getDrink(@Path("id") id: DrinkId): DrinkModelV1?
@GET("api/v1/users.json")
suspend fun listUsers(): List<UserModelV1>
@GET("api/v1/users/{id}.json")
suspend fun getUser(@Path("id") id: UserId): UserModelV1?
@GET("api/v1/users/{id}/deposit.json")
suspend fun deposit(@Path("id") id: UserId)
@GET("api/v1/users/{id}/payment.json")
suspend fun payment(@Path("id") id: UserId)
@GET("api/v1/users/{id}/buy.json")
suspend fun buy(@Path("id") id: UserId)
@GET("api/v1/users/{id}/buy_barcode.json")
suspend fun buyWithBarcode(@Path("id") id: UserId)
@GET("api/v1/users/stats.json")
suspend fun getStats()
}
......@@ -22,33 +22,25 @@
* THE SOFTWARE.
*/
package de.chaosdorf.meteroid.ui
package de.chaosdorf.mete.v1
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Person
import androidx.compose.material.icons.twotone.Person
import androidx.compose.ui.graphics.vector.ImageVector
import de.chaosdorf.meteroid.icons.MeteroidIcons
import de.chaosdorf.meteroid.icons.outlined.WaterFull
import de.chaosdorf.meteroid.icons.twotone.WaterFull
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import retrofit2.Retrofit
import retrofit2.create
sealed class Screen(
val label: String,
val route: String,
val icon: ImageVector,
val selectedIcon: ImageVector = icon
) {
object Drinks : Screen(
"Drinks",
"drinks",
MeteroidIcons.Outlined.WaterFull,
MeteroidIcons.TwoTone.WaterFull
)
object MeteApiV1Factory : MeteApiFactory<MeteApiV1> {
private val json = Json {
ignoreUnknownKeys = true
}
object Users : Screen(
"Users",
"users",
Icons.Outlined.Person,
Icons.TwoTone.Person
)
override fun newInstance(baseUrl: String): MeteApiV1 {
val contentType = "application/json".toMediaType()
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(json.asConverterFactory(contentType))
.build()
return retrofit.create<MeteApiV1>()
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.mete.v1
import de.chaosdorf.mete.UserId
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
@Serializable
data class UserModelV1(
val id: UserId,
val name: String,
val email: String,
val createdAt: Instant,
val updatedAt: Instant,
val balance: Double,
val active: Boolean,
val audit: Boolean,
val redirect: Boolean
)
......@@ -76,8 +76,18 @@ dependencies {
implementation(libs.androidx.compose.runtime)
implementation(libs.androidx.compose.ui.tooling)
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
implementation(libs.androidx.room.paging)
implementation(libs.androidx.navigation.compose)
implementation(libs.okhttp)
implementation(libs.kotlinx.serialization.json)
implementation(libs.coil.compose)
implementation(project(":api"))
implementation(project(":persistence"))
debugImplementation(libs.androidx.compose.ui.tooling)
implementation(libs.androidx.compose.ui.preview)
testImplementation(libs.androidx.compose.ui.test)
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.chaosdorf.meteroid">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
......@@ -14,7 +13,6 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/application_name"
android:theme="@style/Theme.Meteroid">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......
......@@ -27,32 +27,37 @@ package de.chaosdorf.meteroid
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.ui.Modifier
import androidx.navigation.compose.rememberNavController
import de.chaosdorf.meteroid.ui.MeteroidBottomBar
import de.chaosdorf.meteroid.ui.MeteroidRouter
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import de.chaosdorf.meteroid.di.RootViewModel
import de.chaosdorf.meteroid.di.RootViewModelFactory
import de.chaosdorf.meteroid.routes.RootRouter
import de.chaosdorf.meteroid.ui.theme.MeteroidTheme
import kotlinx.coroutines.MainScope
class MainActivity : ComponentActivity() {
private val rootViewModelFactory = object : RootViewModelFactory {}
private lateinit var rootViewModel: RootViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
val scope = MainScope()
rootViewModel =
rootViewModelFactory.newInstance(scope, applicationContext)
setContent {
MeteroidTheme {
Scaffold(
bottomBar = { MeteroidBottomBar(navController) }
) { padding: PaddingValues ->
MeteroidRouter(
navController,
modifier = Modifier.padding(padding)
)
App(rootViewModel)
}
}
}
}
@Composable
fun App(viewModel: RootViewModel) {
val route by viewModel.route.collectAsState()
RootRouter(route)
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.meteroid.di
import android.util.Log
import de.chaosdorf.mete.PwaManifest
import de.chaosdorf.meteroid.model.Server
import de.chaosdorf.meteroid.model.ServerId
import de.chaosdorf.meteroid.util.await
import de.chaosdorf.meteroid.util.findBestIcon
import de.chaosdorf.meteroid.util.resolve
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.stateIn
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
interface AddServerViewModelFactory {
fun newInstance(
scope: CoroutineScope,
isFirstServer: Boolean,
onSubmit: (url: String, manifest: PwaManifest?) -> Unit,
onCancel: () -> Unit
) = AddServerViewModelImpl(scope, isFirstServer, onSubmit, onCancel)
}
interface AddServerViewModel {
val url: MutableStateFlow<String>
val server: StateFlow<Server?>
val loading: StateFlow<Boolean>
val isFirstServer: Boolean
fun submit()
fun cancel()
}
class AddServerViewModelImpl(
scope: CoroutineScope,
override val isFirstServer: Boolean,
private val onSubmit: (url: String, manifest: PwaManifest?) -> Unit,
private val onCancel: () -> Unit
) : AddServerViewModel {
private val json = Json {
ignoreUnknownKeys = true
}
private val httpClient = OkHttpClient()
override val url = MutableStateFlow("")
private val _loading = MutableStateFlow(false)
override val loading = _loading
@OptIn(ExperimentalSerializationApi::class)
private val manifest = url.debounce(300).mapNotNull { address ->
_loading.value = true
try {
val url = address.toHttpUrl().resolve("manifest.json")
val call = httpClient.newCall(Request.Builder().url(url!!).build())
val body = call.await()
val manifest = json.decodeFromStream<PwaManifest>(body.byteStream())
Pair(address, manifest)
} catch (_: Exception) {
null
} finally {
_loading.value = false
}
}.stateIn(scope, SharingStarted.WhileSubscribed(), null)
override val server = manifest.mapLatest { pair ->
pair?.let { (url, manifest) ->
Server(
id = ServerId(-1),
url = url,
name = manifest.name,
logoUrl = manifest.findBestIcon()?.resolve(url)
)
}
}.stateIn(scope, SharingStarted.WhileSubscribed(), null)
override fun submit() {
onSubmit(url.value, manifest.value?.second)
}
override fun cancel() {
onCancel()
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.meteroid.di
import de.chaosdorf.mete.DrinkId
import de.chaosdorf.meteroid.model.Drink
import de.chaosdorf.meteroid.Repository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
interface DrinkViewModelFactory {
fun newInstance(
scope: CoroutineScope,
repository: Repository<DrinkId, Drink>
) = DrinkListViewModelImpl(scope, repository)
}
interface DrinkListViewModel {
val drinks: StateFlow<List<Drink>>
}
class DrinkListViewModelImpl(
scope: CoroutineScope,
repository: Repository<DrinkId, Drink>
) : DrinkListViewModel {
override val drinks: StateFlow<List<Drink>> = repository.getAllFlow()
.stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2013-2023 Chaosdorf e.V.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.chaosdorf.meteroid.di
import androidx.room.withTransaction
import de.chaosdorf.mete.v1.MeteApiV1Factory
import de.chaosdorf.meteroid.MeteroidDatabase
import de.chaosdorf.meteroid.RepositorySyncHandler
import de.chaosdorf.meteroid.SyncHandler
import de.chaosdorf.meteroid.model.Drink
import de.chaosdorf.meteroid.model.Server
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
interface MainLayoutViewModelFactory {
fun newInstance(
scope: CoroutineScope, db: MeteroidDatabase, server: Server, onOpenServerSelection: () -> Unit
): MainLayoutViewModel = MainLayoutViewModelImpl(scope, db, server, onOpenServerSelection)
}
interface MainLayoutViewModel {
val server: Server
val syncState: StateFlow<SyncHandler.State>
val drinkListViewModel: DrinkListViewModel
fun openServerSelection()
}
class MainLayoutViewModelImpl(
scope: CoroutineScope,
db: MeteroidDatabase,
override val server: Server,
private val onOpenServerSelection: () -> Unit
) : MainLayoutViewModel {
private val api = MeteApiV1Factory.newInstance(server.url)
override val drinkListViewModel = DrinkListViewModelImpl(scope, db.drinks())
private val syncHandler = RepositorySyncHandler(db::withTransaction, db.drinks()) {
api.listDrinks().map { Drink.fromModelV1(it) }
}
override val syncState: StateFlow<SyncHandler.State> = syncHandler.state
init {
scope.launch {
syncHandler.doSync()
}
}
override fun openServerSelection() {
onOpenServerSelection()
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment