Added UserRepository and ExpenseShareRepository
Implemented `UserRepository` and `ExpenseShareRepository` to handle data fetching with a caching strategy (local DAO + remote API). Specific changes include: - Added `getUserById` to `UserDao` and updated `getShareById` in `ExpenseShareDao` to support nullable returns. - Updated `APIService` and `ComDataTypes` to include endpoints and data models for User info, Expense Shares, and pluralized Expense responses. - Refactored `ExpenseRepository` to use the updated API naming conventions and removed debug print statements.
This commit is contained in:
@@ -24,7 +24,7 @@ interface ExpenseShareDao {
|
||||
fun getAllShares(): Flow<List<ExpenseShare>>
|
||||
|
||||
@Query("SELECT * FROM expense_shares WHERE id = :shareId")
|
||||
fun getShareById(shareId: UUID): Flow<ExpenseShare>
|
||||
fun getShareById(shareId: UUID): Flow<ExpenseShare?>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertShare(share: ExpenseShare)
|
||||
|
||||
@@ -22,6 +22,9 @@ interface UserDao {
|
||||
@Query("SELECT * FROM users")
|
||||
fun getAllUsers(): Flow<List<User>>
|
||||
|
||||
@Query("SELECT * FROM users WHERE id = :userId")
|
||||
fun getUserById(userId: UUID): Flow<User?>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertUser(user: User)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ interface APIService {
|
||||
|
||||
// Expenses
|
||||
@GET("api/expenses")
|
||||
suspend fun expenseGet(@Header("Authorization") token: String): Response<ExpenseResponse>
|
||||
suspend fun expensesGet(@Header("Authorization") token: String): Response<ExpensesResponse>
|
||||
@POST("api/expenses")
|
||||
suspend fun expenseCreate(@Header("Authorization") token: String)
|
||||
@PUT("api/expenses")
|
||||
@@ -29,7 +29,13 @@ interface APIService {
|
||||
@DELETE("api/expenses")
|
||||
suspend fun expenseDelete(@Header("Authorization") token: String)
|
||||
|
||||
// Shares
|
||||
@GET("api/shares")
|
||||
suspend fun sharesGet(@Header("Authorization") token: String): Response<ExpenseSharesResponse>
|
||||
@GET("api/shares")
|
||||
suspend fun shareGet(@Header("Authorization") token: String, @Query("id") shareId: UUID): Response<ExpenseShareResponse>
|
||||
|
||||
// User
|
||||
@GET("api/userinfo")
|
||||
suspend fun userinfo(@Header("Authorization") token: String, @Query("id") userId: UUID)
|
||||
suspend fun userinfo(@Header("Authorization") token: String, @Query("id") userId: UUID): Response<UserinfoResponse>
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package de.miaurizius.shap_planner.network
|
||||
|
||||
import de.miaurizius.shap_planner.entities.Expense
|
||||
import de.miaurizius.shap_planner.entities.ExpenseShare
|
||||
import de.miaurizius.shap_planner.entities.User
|
||||
|
||||
// Login
|
||||
data class LoginRequest(val username: String, val password: String)
|
||||
@@ -12,4 +14,11 @@ data class RefreshRequest(val refresh_token: String)
|
||||
data class RefreshResponse(val access_token: String, val refresh_token: String)
|
||||
|
||||
// Expenses
|
||||
data class ExpenseResponse(val expenses: List<Expense>)
|
||||
data class ExpensesResponse(val expenses: List<Expense>)
|
||||
|
||||
// ExpenseShares
|
||||
data class ExpenseSharesResponse(val shares: List<ExpenseShare>)
|
||||
data class ExpenseShareResponse(val share: ExpenseShare)
|
||||
|
||||
// User
|
||||
data class UserinfoResponse(val user: User)
|
||||
@@ -13,18 +13,15 @@ class ExpenseRepository(
|
||||
) {
|
||||
fun getExpenses(token: String, forceRefresh: Boolean = false): Flow<Resource<List<Expense>>> = flow {
|
||||
val cachedExpense = dao.getAllExpenses().first()
|
||||
println("CachedExpense: $cachedExpense")
|
||||
emit(Resource.Loading(cachedExpense))
|
||||
|
||||
if(cachedExpense.isEmpty() || forceRefresh) {
|
||||
try {
|
||||
val response = api.expenseGet("Bearer $token")
|
||||
val response = api.expensesGet("Bearer $token")
|
||||
if(response.isSuccessful) {
|
||||
val remoteExpense = response.body()?.expenses ?: emptyList()
|
||||
println("Fetched expenses: $remoteExpense")
|
||||
remoteExpense.forEach {
|
||||
dao.insertExpense(it)
|
||||
println("Added $it")
|
||||
}
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package de.miaurizius.shap_planner.repository
|
||||
|
||||
import de.miaurizius.shap_planner.entities.ExpenseShare
|
||||
import de.miaurizius.shap_planner.entities.ExpenseShareDao
|
||||
import de.miaurizius.shap_planner.network.APIService
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import java.util.UUID
|
||||
|
||||
class ExpenseShareRepository(
|
||||
private val dao: ExpenseShareDao,
|
||||
private val api: APIService
|
||||
) {
|
||||
fun getShares(token: String, forceRefresh: Boolean = false): Flow<Resource<List<ExpenseShare>>> = flow {
|
||||
val cachedData = dao.getAllShares().first()
|
||||
emit(Resource.Loading(cachedData))
|
||||
|
||||
if(cachedData.isEmpty() || forceRefresh) {
|
||||
try {
|
||||
val response = api.sharesGet("Bearer $token")
|
||||
if(response.isSuccessful) {
|
||||
val remoteShare = response.body()?.shares ?: emptyList()
|
||||
remoteShare.forEach {
|
||||
dao.insertShare(it)
|
||||
}
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
emit(Resource.Error("Network Error: ${e.localizedMessage}", cachedData))
|
||||
}
|
||||
}
|
||||
dao.getAllShares().collect { emit(Resource.Success(it)) }
|
||||
}
|
||||
|
||||
fun getShareById(token: String, shareId: UUID, forceRefresh: Boolean = false): Flow<Resource<ExpenseShare>> = flow {
|
||||
val cached = dao.getShareById(shareId).first()
|
||||
emit(Resource.Loading(cached))
|
||||
if(cached == null || forceRefresh) {
|
||||
try {
|
||||
val response = api.shareGet("Bearer $token", shareId)
|
||||
if(response.isSuccessful) {
|
||||
response.body()?.share?.let { remoteShare -> dao.insertShare(remoteShare) }
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
emit(Resource.Error("Network-Error: ${e.localizedMessage}", cached))
|
||||
}
|
||||
}
|
||||
dao.getShareById(shareId).collect { share ->
|
||||
if(share != null) emit(Resource.Success(share))
|
||||
else emit(Resource.Error("Share nicht gefunden", null))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package de.miaurizius.shap_planner.repository
|
||||
|
||||
import de.miaurizius.shap_planner.entities.User
|
||||
import de.miaurizius.shap_planner.entities.UserDao
|
||||
import de.miaurizius.shap_planner.network.APIService
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import java.util.UUID
|
||||
|
||||
class UserRepository(
|
||||
private val dao: UserDao,
|
||||
private val api: APIService
|
||||
) {
|
||||
fun getUser(token: String, userId: UUID, forceRefresh: Boolean = false): Flow<Resource<User>> = flow {
|
||||
val cached = dao.getUserById(userId).first()
|
||||
emit(Resource.Loading(cached))
|
||||
if(cached == null || forceRefresh) {
|
||||
try {
|
||||
val response = api.userinfo("Bearer $token", userId)
|
||||
if(response.isSuccessful) {
|
||||
response.body()?.user?.let { remoteUser -> dao.insertUser(remoteUser) }
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
emit(Resource.Error("Network-Error: ${e.localizedMessage}", cached))
|
||||
}
|
||||
}
|
||||
dao.getUserById(userId).collect { user -> if(user != null) emit(Resource.Success(user)) else emit(
|
||||
Resource.Error("User nicht gefunden", null)) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user