realize that i need to call the serveer, not become the server - i was mentally drained when making that i presume
This commit is contained in:
@@ -46,6 +46,7 @@ dependencies {
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(platform(libs.androidx.compose.bom))
|
||||
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
|
||||
@@ -56,4 +57,12 @@ dependencies {
|
||||
|
||||
implementation(libs.hilt.android)
|
||||
ksp(libs.hilt.android.compiler)
|
||||
|
||||
// retrofit
|
||||
implementation(libs.retrofit)
|
||||
// GSON
|
||||
implementation(libs.converter.gson)
|
||||
// coroutines
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
@@ -12,7 +13,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MiniTicketSystem">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:name=".activities.MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.MiniTicketSystem"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.odweta.mts
|
||||
|
||||
import android.app.Application
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class MainApplication : Application()
|
||||
+7
-9
@@ -1,25 +1,23 @@
|
||||
package app.odweta.mts
|
||||
package app.odweta.mts.activities
|
||||
|
||||
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 androidx.navigation.compose.rememberNavController
|
||||
import app.odweta.mts.nav.NavigationHost
|
||||
import app.odweta.mts.ui.screens.list.ListScreen
|
||||
import app.odweta.mts.ui.theme.MiniTicketSystemTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
MiniTicketSystemTheme {
|
||||
|
||||
NavigationHost()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package app.odweta.mts.data
|
||||
|
||||
import app.odweta.mts.data.api.TicketApi
|
||||
import app.odweta.mts.data.model.Ticket
|
||||
import app.odweta.mts.data.network.RetrofitClient
|
||||
import retrofit2.Retrofit
|
||||
import javax.inject.Inject
|
||||
|
||||
class TicketRepository @Inject constructor(
|
||||
private val retrofit: Retrofit = RetrofitClient.getClient(),
|
||||
private val ticketApi: TicketApi
|
||||
) {
|
||||
suspend fun successfulUsersResponse() {
|
||||
val usersResponse = ticketApi.getTickets().execute()
|
||||
|
||||
val successful = usersResponse.isSuccessful
|
||||
val httpStatusCode = usersResponse.code()
|
||||
val httpStatusMessage = usersResponse.message()
|
||||
|
||||
val tickets: List<Ticket>? = usersResponse.body()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package app.odweta.mts.data.api
|
||||
|
||||
import app.odweta.mts.data.model.Ticket
|
||||
import retrofit2.Call
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.PATCH
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
|
||||
interface TicketApi {
|
||||
@GET("/tickets")
|
||||
suspend fun getTickets(): Call<List<Ticket>>
|
||||
|
||||
@POST("/tickets")
|
||||
suspend fun createTicket(): Call<Ticket>
|
||||
|
||||
@PATCH("/tickets/{id}")
|
||||
suspend fun updateTicket(@Path("id") id: Long)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package app.odweta.mts.data.model
|
||||
|
||||
import java.time.LocalDateTime
|
||||
|
||||
data class Ticket(
|
||||
private val id: Long,
|
||||
private val title: String,
|
||||
private val description: String,
|
||||
private val status: TicketStatus,
|
||||
private val createdAt: LocalDateTime,
|
||||
private val updatedAt: LocalDateTime
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.odweta.mts.data.model
|
||||
|
||||
enum class TicketStatus {
|
||||
Open,
|
||||
InProgress,
|
||||
Closed
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package app.odweta.mts.data.network
|
||||
|
||||
import app.odweta.mts.data.network.interceptors.AuthorizationInterceptor
|
||||
import app.odweta.mts.data.network.interceptors.RequestInterceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
||||
object RetrofitClient {
|
||||
private const val BASE_URL = "http://localhost:8090/"
|
||||
|
||||
val okHttpClient = OkHttpClient()
|
||||
.newBuilder()
|
||||
.addInterceptor(RequestInterceptor)
|
||||
.addInterceptor(AuthorizationInterceptor)
|
||||
.build()
|
||||
|
||||
fun getClient(): Retrofit =
|
||||
Retrofit.Builder()
|
||||
.client(okHttpClient)
|
||||
.baseUrl(BASE_URL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: add token generation to the server
|
||||
TODO: add a real auth call for that token in the AuthorizationInterceptor
|
||||
*/
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package app.odweta.mts.data.network.interceptors
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.util.UUID
|
||||
|
||||
object AuthorizationInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val requestWithHeader = chain.request()
|
||||
.newBuilder()
|
||||
.header(
|
||||
"Authorization", UUID.randomUUID().toString()
|
||||
).build()
|
||||
return chain.proceed(requestWithHeader)
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package app.odweta.mts.data.network.interceptors
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
object RequestInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
println("Outgoing request to ${request.url()}")
|
||||
return chain.proceed(request)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package app.odweta.mts.nav
|
||||
|
||||
import androidx.compose.animation.SharedTransitionLayout
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.toRoute
|
||||
import app.odweta.mts.ui.screens.list.ListScreen
|
||||
import app.odweta.mts.ui.screens.create.CreateScreen
|
||||
import app.odweta.mts.ui.screens.detail.DetailScreen
|
||||
|
||||
@Composable
|
||||
fun NavigationHost() {
|
||||
val navController = rememberNavController()
|
||||
|
||||
val startDestination = remember { Route.ListScreen }
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = startDestination
|
||||
) {
|
||||
composable<Route.ListScreen> {
|
||||
ListScreen(navController = navController)
|
||||
}
|
||||
|
||||
composable<Route.CreateScreen> {
|
||||
CreateScreen(navController = navController)
|
||||
}
|
||||
|
||||
composable<Route.DetailScreen> { backStackEntry ->
|
||||
val ticketId = backStackEntry.arguments?.getLong("ticketId")
|
||||
?: throw IllegalArgumentException("Missing required argument: ticketId for DetailScreen")
|
||||
DetailScreen(
|
||||
navController = navController,
|
||||
ticketId = ticketId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.odweta.mts.nav
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
sealed interface Route {
|
||||
@Serializable
|
||||
data object ListScreen : Route
|
||||
|
||||
@Serializable
|
||||
data object CreateScreen : Route
|
||||
|
||||
@Serializable
|
||||
data class DetailScreen(
|
||||
val ticketId: Long
|
||||
) : Route
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package app.odweta.mts.ui.screens.create
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavController
|
||||
|
||||
@Composable
|
||||
fun CreateScreen(
|
||||
navController: NavController,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Text("create a ticket")
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text("back!")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package app.odweta.mts.ui.screens.create
|
||||
|
||||
class CreateScreenViewModel {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package app.odweta.mts.ui.screens.detail
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavController
|
||||
|
||||
@Composable
|
||||
fun DetailScreen(
|
||||
navController: NavController,
|
||||
ticketId: Long,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Text("detail of ticket id $ticketId")
|
||||
TextButton(onClick = {
|
||||
navController.popBackStack()
|
||||
}) {
|
||||
Text("back!")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package app.odweta.mts.ui.screens.list
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavController
|
||||
import app.odweta.mts.nav.Route
|
||||
|
||||
@Composable
|
||||
fun ListScreen(
|
||||
navController: NavController,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text("all of the tickets")
|
||||
TextButton(onClick = {
|
||||
navController.navigate(Route.CreateScreen)
|
||||
}) {
|
||||
Text("to create screen!")
|
||||
}
|
||||
TextButton(onClick = {
|
||||
navController.navigate(Route.DetailScreen(1))
|
||||
}) {
|
||||
Text("to detail screen!")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,25 @@
|
||||
[versions]
|
||||
agp = "9.3.1"
|
||||
converterGson = "3.0.0"
|
||||
coreKtx = "1.10.1"
|
||||
hiltAndroid = "2.60.1"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.1.5"
|
||||
espressoCore = "3.5.1"
|
||||
kotlinxCoroutinesAndroid = "1.11.0"
|
||||
kotlinxCoroutinesCore = "1.11.0"
|
||||
lifecycleRuntimeKtx = "2.6.1"
|
||||
activityCompose = "1.8.0"
|
||||
kotlin = "2.2.10"
|
||||
composeBom = "2026.02.01"
|
||||
ksp = "2.3.11"
|
||||
dagger-hilt = "2.60.1"
|
||||
navigationCompose = "2.9.8"
|
||||
retrofit = "3.0.0"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" }
|
||||
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
|
||||
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroid" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
@@ -29,6 +35,10 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
|
||||
androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||
androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
|
||||
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
||||
Reference in New Issue
Block a user