Compare commits

...

2 Commits

Author SHA1 Message Date
Sebastian Böckelmann
c7a71fd1bf ADD: Network Communication 2025-05-04 19:35:25 +02:00
Sebastian Böckelmann
c8e9452a7e UPD: Dataformat for sync 2025-05-04 11:23:33 +02:00
10 changed files with 111 additions and 5 deletions

View File

@ -63,4 +63,7 @@ dependencies {
implementation(libs.compose.runtime.livedata)
implementation(libs.coil.compose)
ksp(libs.androidx.room.compiler)
implementation(libs.retrofit)
implementation(libs.converter.gson)
implementation(libs.logging.interceptor)
}

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"

View File

@ -8,8 +8,9 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import come.stormborntales.notevault.data.local.dao.NoteDao
import come.stormborntales.notevault.data.local.entity.NoteEntity
import come.stormborntales.notevault.data.local.entity.SyncTime
@Database(entities = [NoteEntity::class], version = 1)
@Database(entities = [NoteEntity::class, SyncTime::class], version = 1)
@TypeConverters(UriListConverter::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao

View File

@ -3,6 +3,11 @@ package come.stormborntales.notevault.data.local.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
enum class SyncStatus {
PENDING, // Lokale Änderungen warten auf Synchronisation
SYNCHRONIZED, // Der Eintrag wurde mit dem Server synchronisiert
DELETED // Der Eintrag wurde lokal gelöscht und wartet auf Serverabgleich
}
@Entity(tableName = "notes")
data class NoteEntity(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
@ -12,5 +17,10 @@ data class NoteEntity(
var year: Int?,
var genre: String?,
var description: String?,
val imagePreview: String
val imagePreview: String,
val remoteId: String? = null,
val localModificationTimestamp: Long = System.currentTimeMillis(), // Zeitstempel der letzten lokalen Änderung
val syncStatus: SyncStatus = SyncStatus.PENDING // Status der Synchronisation
)

View File

@ -0,0 +1,10 @@
package come.stormborntales.notevault.data.local.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "sync_time_table")
data class SyncTime(
@PrimaryKey val id: Long = 1, // Einziger Eintrag für das Gerät
val lastSyncTimestamp: Long = System.currentTimeMillis() // Zeitstempel des letzten Syncsy
)

View File

@ -0,0 +1,13 @@
package come.stormborntales.notevault.data.remote
import come.stormborntales.notevault.data.remote.model.user.RegisterRequest
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
interface ApiInterface {
@POST("user/register")
suspend fun register(@Body user: RegisterRequest): Response<Unit>
}

View File

@ -0,0 +1,27 @@
package come.stormborntales.notevault.data.remote
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import kotlin.getValue
object ApiClient {
private const val BASE_URL = "https://notevault.fawkes100.de" // < Anpassen!
val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
}

View File

@ -0,0 +1,10 @@
package come.stormborntales.notevault.data.remote.model.user
data class RegisterRequest(
val email: String,
val password: String
)
data class RegisterResponse(
val userId: String
)

View File

@ -1,5 +1,6 @@
package come.stormborntales.notevault.ui.screens
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -13,12 +14,20 @@ import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import come.stormborntales.notevault.data.remote.ApiClient
import come.stormborntales.notevault.data.remote.ApiInterface
import come.stormborntales.notevault.data.remote.model.user.RegisterRequest
import kotlinx.coroutines.launch
@Composable
fun SettingsScreen() {
val coroutineScope = rememberCoroutineScope()
val syncApi = remember { ApiClient.retrofit.create(ApiInterface::class.java) }
Column(
modifier = Modifier
.fillMaxSize()
@ -70,10 +79,25 @@ fun SettingsScreen() {
Spacer(modifier = Modifier.height(32.dp))
OutlinedButton(
onClick = { /* TODO: Impressum anzeigen */ },
onClick = {
coroutineScope.launch {
try {
val request = RegisterRequest("test@example.com", "123456")
val response = syncApi.register(request)
if(response.isSuccessful) {
Log.d("Response", "Response was successful")
} else {
Log.d("Response", "Error: ${response.errorBody()}")
}
} catch (e: Exception) {
println("Netzwerkfehler: ${e.message}")
}
}
},
modifier = Modifier.fillMaxWidth()
) {
Text("Impressum")
Text("Registrierung testen")
}
}
}

View File

@ -1,6 +1,7 @@
[versions]
agp = "8.8.2"
composeBomVersion = "2024.01.00"
converterGson = "2.9.0"
kotlin = "2.0.0"
coreKtx = "1.10.1"
junit = "4.13.2"
@ -9,14 +10,17 @@ espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.8.0"
composeBom = "2024.04.01"
loggingInterceptor = "4.12.0"
navigationCompose = "2.8.9"
retrofit = "2.9.0"
room = "2.7.1"
ksp="2.1.21-RC-2.0.0"
ksp="2.0.0-1.0.21"
compose = "1.6.0" # oder was immer deine aktuelle Compose-Version ist
[libraries]
coil-compose = { group = "io.coil-kt", name = "coil-compose", version = "2.5.0" } # oder aktueller
compose-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "compose" }
converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" }
lifecycle-livedata-ktx = "androidx.lifecycle:lifecycle-livedata-ktx:2.8.7"
androidx-compose-bom-v20240100 = { module = "androidx.compose:compose-bom", version.ref = "composeBomVersion" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -39,6 +43,8 @@ androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "loggingInterceptor" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
[plugins]