diff --git a/app/app/src/main/AndroidManifest.xml b/app/app/src/main/AndroidManifest.xml
index e51e3fa..913b745 100644
--- a/app/app/src/main/AndroidManifest.xml
+++ b/app/app/src/main/AndroidManifest.xml
@@ -20,9 +20,19 @@
android:theme="@style/Theme.DebtPirate">
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/host/MainActivity.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/host/MainActivity.kt
index d96013c..5a2dc53 100644
--- a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/host/MainActivity.kt
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/host/MainActivity.kt
@@ -1,8 +1,10 @@
package ing.bikeshedengineer.debtpirate.app.host
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
+import android.util.Log
import androidx.activity.ComponentActivity
-import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.AnimatedContentTransitionScope
@@ -18,7 +20,9 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.compose.rememberNavController
+import androidx.navigation.toRoute
import dagger.hilt.android.AndroidEntryPoint
+import ing.bikeshedengineer.debtpirate.app.screen.auth.presentation.confirm.ConfirmationScreen
import ing.bikeshedengineer.debtpirate.app.screen.auth.presentation.login.LoginScreen
import ing.bikeshedengineer.debtpirate.app.screen.auth.presentation.register.RegistrationScreen
import ing.bikeshedengineer.debtpirate.navigation.Destination
@@ -37,6 +41,9 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+
+ handleIntent(intent)
+
enableEdgeToEdge()
setContent {
val navController = rememberNavController()
@@ -79,15 +86,50 @@ class MainActivity : ComponentActivity() {
}
) {
navigation(
- startDestination = Destination.LoginScreen
+ startDestination = Destination.RegistrationConfirmationCheckEmailScreen(
+ emailAddress = "zachary@dziura.email"
+ )
) {
composable() { LoginScreen() }
composable() { RegistrationScreen() }
+ composable() {
+ val (emailAddress, _) = it.toRoute()
+ ConfirmationScreen(
+ emailAddress
+ )
+ }
}
}
}
}
}
+
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
+ handleIntent(intent)
+ }
+
+ private fun handleIntent(intent: Intent) {
+ val action: String? = intent.action
+ val actionUri: Uri? = intent.data
+
+ if (Intent.ACTION_VIEW == action) {
+ when (actionUri?.lastPathSegment) {
+ "verify" -> {
+ val userId = actionUri.getQueryParameter("u")!!.toInt()
+ val verificationToken = actionUri.getQueryParameter("t")!!
+
+ handleNewUserVerificationIntent(userId, verificationToken)
+ }
+
+ else -> {}
+ }
+ }
+ }
+
+ private fun handleNewUserVerificationIntent(userId: Int, sessionToken: String) {
+ Log.d("DebtPirate::MainActivity", "User ID: $userId, Session Token: $sessionToken")
+ }
}
@Composable
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/screen/auth/presentation/confirm/Confirmation.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/screen/auth/presentation/confirm/Confirmation.kt
new file mode 100644
index 0000000..55f69ef
--- /dev/null
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/screen/auth/presentation/confirm/Confirmation.kt
@@ -0,0 +1,89 @@
+package ing.bikeshedengineer.debtpirate.app.screen.auth.presentation.confirm
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.MarkEmailRead
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.unit.dp
+
+@Composable()
+fun ConfirmationScreen(emailAddress: String? = null, redirectedFromEmailConfirmation: Boolean = false) {
+ Scaffold(
+ modifier = Modifier.fillMaxSize()
+ ) { padding ->
+ Column(modifier = Modifier.padding(padding).padding(PaddingValues(4.dp))) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(1f)
+ ) {
+ Icon(
+ Icons.Outlined.MarkEmailRead,
+ null,
+ modifier = Modifier
+ .align(Alignment.Center)
+ .size(96.dp)
+ )
+ }
+
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(3f)
+ ) {
+ Text(
+ "Confirmation Sent!",
+ style = MaterialTheme.typography.displaySmall,
+ textAlign = TextAlign.Center,
+ modifier = Modifier.fillMaxWidth()
+ )
+
+ if (emailAddress != null) {
+ Text(
+ text = buildAnnotatedString {
+ append("We sent your confirmation email to ")
+ withStyle(
+ style = SpanStyle(
+ color = MaterialTheme.colorScheme.primary,
+ fontWeight = FontWeight.Bold
+ )
+ ) {
+ append(emailAddress)
+ }
+ },
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(PaddingValues(top = 16.dp))
+
+ )
+
+ Text(
+ "Follow the instructions listed in that email to finish registering your new account.",
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(PaddingValues(top = 8.dp))
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/screen/auth/usecase/SubmitAccountRegistrationRequestUseCase.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/screen/auth/usecase/SubmitAccountRegistrationRequestUseCase.kt
index 8481240..4142f35 100644
--- a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/screen/auth/usecase/SubmitAccountRegistrationRequestUseCase.kt
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/app/screen/auth/usecase/SubmitAccountRegistrationRequestUseCase.kt
@@ -14,7 +14,7 @@ class SubmitAccountRegistrationRequestUseCase(private val userRepository: UserRe
val request = UserCreatePostRequest(emailAddress, name, password)
try {
- val response = userRepository.submitCreateUserRequest(request)
+ val response = userRepository.createUserPostRequest(request)
Log.d("RegistrationScreen", "Account registration successful! $response")
return response
} catch (err: Throwable) {
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/endpoint/UserEndpoint.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/endpoint/UserEndpoint.kt
index cf44bfd..1b7b82c 100644
--- a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/endpoint/UserEndpoint.kt
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/endpoint/UserEndpoint.kt
@@ -3,11 +3,21 @@ package ing.bikeshedengineer.debtpirate.data.remote.endpoint
import ing.bikeshedengineer.debtpirate.data.remote.ApiResponse
import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserCreatePostRequest
import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserCreatePostResponse
+import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserVerificationGetResponse
import retrofit2.Response
import retrofit2.http.Body
+import retrofit2.http.Field
+import retrofit2.http.GET
import retrofit2.http.POST
+import retrofit2.http.Path
interface UserEndpoint {
@POST("user")
- suspend fun submitUserPostRequest(@Body request: UserCreatePostRequest): Response>
+ suspend fun createUserPostRequest(@Body request: UserCreatePostRequest): Response>
+
+ @GET("user/{userId}/verify")
+ suspend fun userVerificationGetRequest(
+ @Path("userId") userId: Int,
+ @Field("t") verificationToken: String
+ ): Response>
}
\ No newline at end of file
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/model/user/UserVerificationGetRequest.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/model/user/UserVerificationGetRequest.kt
new file mode 100644
index 0000000..63ac7b4
--- /dev/null
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/model/user/UserVerificationGetRequest.kt
@@ -0,0 +1,3 @@
+package ing.bikeshedengineer.debtpirate.data.remote.model.user
+
+data class UserVerificationGetRequest(val userId: Int, val verificationToken: String)
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/model/user/UserVerificationGetResponse.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/model/user/UserVerificationGetResponse.kt
new file mode 100644
index 0000000..e6e5872
--- /dev/null
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/remote/model/user/UserVerificationGetResponse.kt
@@ -0,0 +1,18 @@
+package ing.bikeshedengineer.debtpirate.data.remote.model.user
+
+import com.google.gson.annotations.JsonAdapter
+import ing.bikeshedengineer.debtpirate.domain.adapter.OffsetDateTimeAdapter
+import java.time.OffsetDateTime
+
+data class UserVerificationGetResponse(
+ val userId: Int,
+ val session: UserVerificationGetResponseTokenData,
+ val auth: UserVerificationGetResponseTokenData
+)
+
+data class UserVerificationGetResponseTokenData(
+ val token: String,
+ @JsonAdapter(OffsetDateTimeAdapter::class) val expiresAt: OffsetDateTime
+)
+
+
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/repository/UserRepository.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/repository/UserRepository.kt
index 0d7e3c2..4e15104 100644
--- a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/repository/UserRepository.kt
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/data/repository/UserRepository.kt
@@ -2,7 +2,10 @@ package ing.bikeshedengineer.debtpirate.data.repository
import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserCreatePostRequest
import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserCreatePostResponse
+import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserVerificationGetRequest
+import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserVerificationGetResponse
interface UserRepository {
- suspend fun submitCreateUserRequest(request: UserCreatePostRequest): UserCreatePostResponse
+ suspend fun createUserPostRequest(request: UserCreatePostRequest): UserCreatePostResponse
+ suspend fun verifyUserGetRequest(request: UserVerificationGetRequest): UserVerificationGetResponse
}
\ No newline at end of file
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/domain/repository/UserRepositoryImpl.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/domain/repository/UserRepositoryImpl.kt
index 591e419..4cc6977 100644
--- a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/domain/repository/UserRepositoryImpl.kt
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/domain/repository/UserRepositoryImpl.kt
@@ -7,6 +7,8 @@ import ing.bikeshedengineer.debtpirate.data.remote.ApiResponse
import ing.bikeshedengineer.debtpirate.data.remote.endpoint.UserEndpoint
import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserCreatePostRequest
import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserCreatePostResponse
+import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserVerificationGetRequest
+import ing.bikeshedengineer.debtpirate.data.remote.model.user.UserVerificationGetResponse
import ing.bikeshedengineer.debtpirate.data.repository.UserRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -15,13 +17,31 @@ import retrofit2.Retrofit
class UserRepositoryImpl(httpClient: Retrofit) : UserRepository {
private val userEndpoint: UserEndpoint = httpClient.create(UserEndpoint::class.java)
- override suspend fun submitCreateUserRequest(request: UserCreatePostRequest): UserCreatePostResponse {
+ override suspend fun createUserPostRequest(request: UserCreatePostRequest): UserCreatePostResponse {
return withContext(Dispatchers.IO) {
- val response = userEndpoint.submitUserPostRequest(request)
+ val response = userEndpoint.createUserPostRequest(request)
+
+ if (response.isSuccessful) {
+ val body = response.body()
+ return@withContext body!!.data!!
+ } else {
+ val gson = Gson()
+ val errorType = object : TypeToken>() {}.type
+ val body =
+ gson.fromJson>(response.errorBody()!!.charStream(), errorType)
+
+ throw Throwable(body!!.error!!)
+ }
+ }
+ }
+
+ override suspend fun verifyUserGetRequest(request: UserVerificationGetRequest): UserVerificationGetResponse {
+ return withContext(Dispatchers.IO) {
+ val (userId, verificationToken) = request
+ val response = userEndpoint.userVerificationGetRequest(userId, verificationToken)
if (response.isSuccessful) {
val body = response.body()
- Log.d("Registration", "$body")
return@withContext body!!.data!!
} else {
val gson = Gson()
diff --git a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/navigation/Destination.kt b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/navigation/Destination.kt
index b6e1a22..bdcad8a 100644
--- a/app/app/src/main/java/ing/bikeshedengineer/debtpirate/navigation/Destination.kt
+++ b/app/app/src/main/java/ing/bikeshedengineer/debtpirate/navigation/Destination.kt
@@ -13,4 +13,10 @@ sealed interface Destination {
@Serializable
data object RegistrationScreen : Destination
+
+ @Serializable
+ data class RegistrationConfirmationCheckEmailScreen(
+ val emailAddress: String? = null,
+ val comingFromEmail: Boolean = false
+ ) : Destination
}
\ No newline at end of file
diff --git a/app/gradle/libs.versions.toml b/app/gradle/libs.versions.toml
index d0f7bf2..f928cbb 100644
--- a/app/gradle/libs.versions.toml
+++ b/app/gradle/libs.versions.toml
@@ -2,7 +2,7 @@
activityCompose = "1.9.3"
agp = "8.7.2"
appcompat = "1.7.0"
-composeBom = "2024.10.01"
+composeBom = "2024.11.00"
coreKtx = "1.15.0"
datastore = "1.1.1"
espressoCore = "3.6.1"
@@ -17,8 +17,8 @@ lifecycleRuntimeKtx = "2.8.7"
lifecycleViewModelKtx = "2.8.7"
lifecycleViewmodelCompose = "2.8.7"
material = "1.12.0"
-material3 = "1.4.0-alpha03"
-navigation = "2.8.3"
+material3 = "1.4.0-alpha04"
+navigation = "2.8.4"
protobuf = "0.9.4"
protoLite = "3.21.11"
okhttp = "4.10.0"