Compare commits

..

2 Commits

Author SHA1 Message Date
89c8a4b985 Started Login Process 2026-02-20 21:30:57 +01:00
534f844196 Added first datatypes 2026-02-20 21:09:43 +01:00
8 changed files with 159 additions and 48 deletions

View File

@@ -40,6 +40,8 @@ android {
}
dependencies {
//Android Studio Auto-Gen
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
@@ -55,4 +57,7 @@ dependencies {
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
debugImplementation(libs.androidx.compose.ui.tooling)
debugImplementation(libs.androidx.compose.ui.test.manifest)
//Manually added
implementation("androidx.datastore:datastore-preferences:1.2.0")
}

View File

@@ -12,7 +12,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.ShapPlanner">
<activity
android:name=".MainActivity"
android:name=".activities.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.ShapPlanner">

View File

@@ -1,47 +0,0 @@
package de.miaurizius.shap_planner
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import de.miaurizius.shap_planner.ui.theme.ShapPlannerTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ShapPlannerTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ShapPlannerTheme {
Greeting("Android")
}
}

View File

@@ -0,0 +1,39 @@
package de.miaurizius.shap_planner
import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
val Context.dataStore by preferencesDataStore(name = "user_prefs")
object UserPreferencesKeys {
val IS_LOGGED_IN = booleanPreferencesKey("is_logged_in")
val LAST_USER_ID = stringPreferencesKey("last_user_id")
}
class UserPreferences(private val context: Context) {
//Stave status
suspend fun saveLogin(userId: String) {
context.dataStore.edit { prefs ->
prefs[UserPreferencesKeys.IS_LOGGED_IN] = true
prefs[UserPreferencesKeys.LAST_USER_ID] = userId;
}
}
//Logout
suspend fun clearLogin() {
context.dataStore.edit { prefs ->
prefs[UserPreferencesKeys.IS_LOGGED_IN] = false
prefs[UserPreferencesKeys.LAST_USER_ID] = ""
}
}
//Get state
val isLoggedInFlow: Flow<Boolean> = context.dataStore.data.map { prefs -> prefs[UserPreferencesKeys.IS_LOGGED_IN] ?: false }
val lastUserLoginFlow: Flow<String?> = context.dataStore.data.map { prefs -> prefs[UserPreferencesKeys.LAST_USER_ID] }
}

View File

@@ -0,0 +1,71 @@
package de.miaurizius.shap_planner.activities
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import de.miaurizius.shap_planner.UserPreferences
import de.miaurizius.shap_planner.ui.theme.ShapPlannerTheme
import de.miaurizius.shap_planner.viewmodels.LoginViewModel
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// enableEdgeToEdge()
val prefs = UserPreferences(this)
val viewModel = LoginViewModel(prefs)
setContent {
ShapPlannerTheme {
val isLoggedIn by viewModel.isLoggedIn.collectAsState()
if(isLoggedIn) MainScreen()
else LoginScreen { userId -> viewModel.login(userId) }
}
}
}
}
@Composable
fun MainScreen() {
Column(modifier = Modifier.padding(16.dp)) {
Text("Willkommen zurück!")
Button(onClick = { /* TODO: Logout */ }) {
Text("Logout")
}
}
}
@Composable
fun LoginScreen(onLogin: (String) -> Unit) {
var userId by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
Text("Bitte anmelden")
Spacer(modifier = Modifier.height(8.dp))
TextField(
value = userId,
onValueChange = { userId = it },
label = { Text("User ID") }
)
Spacer(modifier = Modifier.height(8.dp))
Button(onClick = { if(userId.isNotEmpty()) onLogin(userId) }) {
Text("Login")
}
}
}

View File

@@ -0,0 +1,12 @@
package de.miaurizius.shap_planner.entities
import java.util.UUID
data class Expense (
val id: UUID,
val amt: Double,
val desc: String,
val payerId: UUID,
val debtors: List<User>
)

View File

@@ -0,0 +1,8 @@
package de.miaurizius.shap_planner.entities
import java.util.UUID
data class User (
val id: UUID,
val name: String,
)

View File

@@ -0,0 +1,23 @@
package de.miaurizius.shap_planner.viewmodels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import de.miaurizius.shap_planner.UserPreferences
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class LoginViewModel(private val prefs: UserPreferences) : ViewModel() {
val isLoggedIn = prefs.isLoggedInFlow.stateIn(viewModelScope, SharingStarted.Lazily, false)
val lastUserId = prefs.lastUserLoginFlow.stateIn(viewModelScope, SharingStarted.Lazily, null)
fun login(userId: String) {
viewModelScope.launch { prefs.saveLogin(userId) }
}
fun logout() {
viewModelScope.launch { prefs.clearLogin() }
}
}