diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e99e79f..53b468a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.compose) + id("com.google.devtools.ksp") version "2.3.4"// apply false } android { @@ -60,4 +61,8 @@ dependencies { //Manually added implementation("androidx.datastore:datastore-preferences:1.2.0") + + val room_version = "2.8.4" + implementation("androidx.room:room-runtime:$room_version") + ksp("androidx.room:room-compiler:$room_version") } \ No newline at end of file diff --git a/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt b/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt index d2c1e4e..fc8cb37 100644 --- a/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt +++ b/app/src/main/java/de/miaurizius/shap_planner/activities/MainActivity.kt @@ -3,25 +3,46 @@ 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.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect 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.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import de.miaurizius.shap_planner.UserPreferences +import de.miaurizius.shap_planner.entities.Account +import de.miaurizius.shap_planner.room.AppDatabase import de.miaurizius.shap_planner.ui.theme.ShapPlannerTheme import de.miaurizius.shap_planner.viewmodels.LoginViewModel +import de.miaurizius.shap_planner.viewmodels.MainViewModel +import java.util.UUID class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -29,24 +50,61 @@ class MainActivity : ComponentActivity() { // enableEdgeToEdge() val prefs = UserPreferences(this) - val viewModel = LoginViewModel(prefs) + val loginViewModel = LoginViewModel(prefs) + + val database = AppDatabase.getDatabase(applicationContext) + val dao = database.accountDao() + val mainViewModel = MainViewModel(dao) setContent { ShapPlannerTheme { - val isLoggedIn by viewModel.isLoggedIn.collectAsState() - if(isLoggedIn) MainScreen() - else LoginScreen { userId -> viewModel.login(userId) } + LaunchedEffect(Unit) { + mainViewModel.addAccount(Account(UUID.randomUUID(), "MiauRizius", "Pfadi-WG")) + } + + val isLoggedIn by loginViewModel.isLoggedIn.collectAsState() + val accountList by mainViewModel.accounts.collectAsState() // Lädt aus Room + + if (isLoggedIn) { + if (accountList.isEmpty()) { + // Zeige Button "Ersten Account erstellen" + } else { + AccountSelectionScreen( + accounts = accountList, + onAccountClick = { account -> + mainViewModel.selectAccount(account) + } + ) + } + } else { + LoginScreen { userId -> loginViewModel.login(userId) } + } } } } } @Composable -fun MainScreen() { - Column(modifier = Modifier.padding(16.dp)) { - Text("Willkommen zurück!") - Button(onClick = { /* TODO: Logout */ }) { - Text("Logout") +fun AccountSelectionScreen(accounts: List, onAccountClick: (Account) -> Unit) { + LazyColumn( + modifier = Modifier.fillMaxSize().padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + item { + Text("Wähle einen Account", style = MaterialTheme.typography.headlineSmall) + } + + items(accounts) { account -> + Card(modifier = Modifier.fillMaxWidth().clickable{ onAccountClick(account) }) { + Row(modifier = Modifier.padding(16.dp), verticalAlignment = Alignment.CenterVertically) { + Box(modifier = Modifier.size(40.dp).background(Color.Gray, shape = CircleShape)) + Spacer(modifier = Modifier.width(16.dp)) + Column { + Text(text = account.name, fontWeight = FontWeight.Bold) + Text(text = account.wgName, style = MaterialTheme.typography.bodyMedium) + } + } + } } } } diff --git a/app/src/main/java/de/miaurizius/shap_planner/entities/Account.kt b/app/src/main/java/de/miaurizius/shap_planner/entities/Account.kt new file mode 100644 index 0000000..415566c --- /dev/null +++ b/app/src/main/java/de/miaurizius/shap_planner/entities/Account.kt @@ -0,0 +1,31 @@ +package de.miaurizius.shap_planner.entities + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Entity +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.PrimaryKey +import androidx.room.Query +import kotlinx.coroutines.flow.Flow +import java.util.UUID + +@Entity(tableName = "accounts") +data class Account ( + @PrimaryKey val id: UUID, + val name: String, + val wgName: String, + val avatarUrl: String? = null +) + +@Dao +interface AccountDao { + @Query("SELECT * FROM accounts") + fun getAllAccounts(): Flow> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertAccount(account: Account) + + @Delete + suspend fun deleteAccount(account: Account) +} \ No newline at end of file diff --git a/app/src/main/java/de/miaurizius/shap_planner/room/AppDatabase.kt b/app/src/main/java/de/miaurizius/shap_planner/room/AppDatabase.kt new file mode 100644 index 0000000..c1ec6ef --- /dev/null +++ b/app/src/main/java/de/miaurizius/shap_planner/room/AppDatabase.kt @@ -0,0 +1,29 @@ +package de.miaurizius.shap_planner.room + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import de.miaurizius.shap_planner.entities.Account +import de.miaurizius.shap_planner.entities.AccountDao + +@Database(entities = [Account::class], version = 1) +abstract class AppDatabase : RoomDatabase() { + abstract fun accountDao(): AccountDao + companion object { + @Volatile + private var INSTANCE: AppDatabase? = null + + fun getDatabase(context: Context): AppDatabase { + return INSTANCE ?: synchronized(this) { + val instance = Room.databaseBuilder( + context.applicationContext, + AppDatabase::class.java, + "shap_planner_database" + ).build() + INSTANCE = instance + instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/de/miaurizius/shap_planner/viewmodels/MainViewModel.kt b/app/src/main/java/de/miaurizius/shap_planner/viewmodels/MainViewModel.kt new file mode 100644 index 0000000..bcd43d0 --- /dev/null +++ b/app/src/main/java/de/miaurizius/shap_planner/viewmodels/MainViewModel.kt @@ -0,0 +1,27 @@ +package de.miaurizius.shap_planner.viewmodels + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import de.miaurizius.shap_planner.entities.Account +import de.miaurizius.shap_planner.entities.AccountDao +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import kotlin.collections.emptyList + +class MainViewModel(private val accountDao: AccountDao) : ViewModel() { + + // Das ist der State, den dein SetContent beobachtet + val accounts: StateFlow> = accountDao.getAllAccounts() + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) + + // Funktion zum Hinzufügen (z.B. nach Login) + fun addAccount(account: Account) { + viewModelScope.launch { + accountDao.insertAccount(account) + } + } + + fun selectAccount(account: Account) {} +} \ No newline at end of file