From a63b98e18023093fb44af55080d02f4bdf93fc44 Mon Sep 17 00:00:00 2001 From: Reimar Date: Thu, 1 May 2025 09:43:14 +0200 Subject: [PATCH 1/3] Save tokens when logging in and implement refresh token --- .../tech/mercantec/easyeat/LoginActivity.kt | 2 +- .../mercantec/easyeat/RegisterActivity.kt | 2 +- .../tech/mercantec/easyeat/SplashActivity.kt | 6 +- .../tech/mercantec/easyeat/helpers/api.kt | 12 +++- .../tech/mercantec/easyeat/helpers/auth.kt | 56 +++++++++++++++++-- 5 files changed, 63 insertions(+), 15 deletions(-) diff --git a/app/app/src/main/java/tech/mercantec/easyeat/LoginActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/LoginActivity.kt index 3091da5..a56504a 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/LoginActivity.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/LoginActivity.kt @@ -27,7 +27,7 @@ class LoginActivity : AppCompatActivity() { thread { try { - login(email, password) + login(this, email, password) } catch (e: ApiRequestException) { runOnUiThread { Toast.makeText(this, e.message, Toast.LENGTH_LONG).show() diff --git a/app/app/src/main/java/tech/mercantec/easyeat/RegisterActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/RegisterActivity.kt index 52059b7..d3c0037 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/RegisterActivity.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/RegisterActivity.kt @@ -34,7 +34,7 @@ class RegisterActivity : AppCompatActivity() { thread { try { - register(email, username, password) + register(this, email, username, password) } catch (e: ApiRequestException) { runOnUiThread { Toast.makeText(this, e.message, Toast.LENGTH_LONG).show() diff --git a/app/app/src/main/java/tech/mercantec/easyeat/SplashActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/SplashActivity.kt index 414bc9a..d6141ce 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/SplashActivity.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/SplashActivity.kt @@ -3,15 +3,13 @@ package tech.mercantec.easyeat import android.app.Activity import android.content.Intent import android.os.Bundle +import tech.mercantec.easyeat.helpers.isLoggedIn class SplashActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // TODO do auth check - val loggedIn = false - - if (!loggedIn) { + if (!isLoggedIn(this)) { startActivity(Intent(this, WelcomeActivity::class.java)) return diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/api.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/api.kt index 0adb879..b4290ed 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/api.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/api.kt @@ -16,9 +16,12 @@ class ApiRequestException(message: String, cause: Throwable?) : Exception(messag class HttpResponse(val body: String, val code: Int) -fun request(method: String, path: String, data: String?): HttpResponse { +fun request(ctx: Context, method: String, path: String, data: String?): HttpResponse { val url = URL(BuildConfig.API_BASE_URL + path) + val prefs = ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE) + val authToken = prefs.getString("auth-token", null) + try { with(url.openConnection() as HttpURLConnection) { requestMethod = method @@ -26,6 +29,9 @@ fun request(method: String, path: String, data: String?): HttpResponse { if (data != null) { setRequestProperty("Content-Type", "application/json") + if (authToken != null) + setRequestProperty("Authorization", "Bearer $authToken") + outputStream.write(data.toByteArray()) outputStream.flush() } @@ -45,13 +51,13 @@ fun request(method: String, path: String, data: String?): HttpResponse { @Serializable class HttpErrorResponse(val message: String) -inline fun requestJson(method: String, path: String, data: Req?): Res { +inline fun requestJson(ctx: Context, method: String, path: String, data: Req?): Res { val requestJson = if (data != null) Json.encodeToString(serializer(), data) else null - val response = request(method, path, requestJson) + val response = request(ctx, method, path, requestJson) if (response.code >= 400) { try { diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt index 0467bc4..6c45884 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt @@ -9,20 +9,64 @@ data class LoginRequest(val emailUsr: String, val password: String) @Serializable data class LoginResponse(val token: String, val userName: String, val id: Int, val refreshToken: String) -fun login(email: String, password: String) { +fun login(ctx: Context, email: String, password: String) { val request = LoginRequest(email, password) - val response = requestJson("POST", "/api/User/login", request) - - // TODO save tokens + val response = requestJson(ctx, "POST", "/api/User/login", request) + with (ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) { + putInt("user-id", response.id) + putString("username", response.userName) + putString("auth-token", response.token) + putString("refresh-token", response.refreshToken) + apply() + } } @Serializable data class CreateUserRequest(val email: String, val userName: String, val password: String) -fun register(email: String, username: String, password: String) { +fun register(ctx: Context, email: String, username: String, password: String) { val request = CreateUserRequest(email, username, password) - requestJson("POST", "/api/User/create", request) + requestJson(ctx, "POST", "/api/User/create", request) +} + +@Serializable +data class RefreshTokenRequest(val refreshToken: String) + +@Serializable +data class RefreshTokenResponse(val token: String, val refreshToken: String) + +fun refreshAuthToken(ctx: Context, refreshToken: String): Boolean { + val response: RefreshTokenResponse + try { + response = requestJson( + ctx, + "POST", "/api/User/refreshtoken", + RefreshTokenRequest(refreshToken) + ) + } catch (e: ApiRequestException) { + return false + } + + with (ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) { + putString("auth-token", response.token) + putString("refresh-token", response.refreshToken) + apply() + } + + return true +} + +fun isLoggedIn(ctx: Context): Boolean { + val prefs = ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE) + val authToken = prefs.getString("auth-token", null) + val refreshToken = prefs.getString("refresh-token", null) ?: return false + + if (authToken == null) { + return refreshAuthToken(ctx, refreshToken) + } + + return true } From 9d9a2975f5db488c661853303c43cbb5de77d73b Mon Sep 17 00:00:00 2001 From: LilleBRG Date: Thu, 1 May 2025 10:13:52 +0200 Subject: [PATCH 2/3] create dish button moved to dishesfragment --- .../mercantec/easyeat/CreateDishActivity.kt | 42 ++++++ .../tech/mercantec/easyeat/MainActivity.kt | 6 - .../mercantec/easyeat/models/Ingredient.kt | 7 + .../easyeat/ui/dishes/DishesFragment.kt | 11 ++ .../res/layout/activity_create_dish_form.xml | 8 ++ .../activity_create_dish_ingredient_row.xml | 123 +++++++++--------- app/app/src/main/res/layout/activity_main.xml | 13 -- .../src/main/res/layout/fragment_dishes.xml | 22 +++- backend/API/appsettings.example.json | 20 +++ 9 files changed, 168 insertions(+), 84 deletions(-) create mode 100644 app/app/src/main/java/tech/mercantec/easyeat/models/Ingredient.kt create mode 100644 backend/API/appsettings.example.json diff --git a/app/app/src/main/java/tech/mercantec/easyeat/CreateDishActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/CreateDishActivity.kt index 7485b2b..f26d8dc 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/CreateDishActivity.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/CreateDishActivity.kt @@ -1,11 +1,15 @@ package tech.mercantec.easyeat import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.widget.Button +import android.widget.EditText import android.widget.LinearLayout +import android.widget.Spinner import androidx.appcompat.app.AppCompatActivity +import tech.mercantec.easyeat.models.Ingredient class CreateDishActivity : AppCompatActivity() { @@ -25,6 +29,19 @@ class CreateDishActivity : AppCompatActivity() { addButton.setOnClickListener { addIngredientRow() } + + val saveButton: Button = findViewById(R.id.saveDishButton) + saveButton.setOnClickListener { + val ingredientList = collectIngredients() + + // Debug/log example + for (ingredient in ingredientList) { + Log.d("INGREDIENT", "Name: ${ingredient.Element}, Amount: ${ingredient.Amount}, Unit: ${ingredient.Unit}") + } + + // You can now save to DB, send to backend, etc. + } + } private fun addIngredientRow() { @@ -39,4 +56,29 @@ class CreateDishActivity : AppCompatActivity() { ingredientContainer.addView(ingredientRow) } + + private fun collectIngredients(): List { + val ingredients = mutableListOf() + + for (i in 0 until ingredientContainer.childCount) { + val ingredientView = ingredientContainer.getChildAt(i) + + // Find views inside this ingredient row + val nameEditText = ingredientView.findViewById(R.id.ingredientNameEditText) + val amountEditText = ingredientView.findViewById(R.id.ingredientAmountEditText) + val spinner = ingredientView.findViewById(R.id.spinner) + + val element = nameEditText.text.toString().trim() + val amount = amountEditText.text.toString().trim() + val unit = spinner.selectedItem.toString() + + // Optional: Only add non-empty rows + if (element.isNotEmpty() && amount.isNotEmpty()) { + ingredients.add(Ingredient(Element = element, Amount = amount.toInt(), Unit = unit)) + } + } + + return ingredients + } + } diff --git a/app/app/src/main/java/tech/mercantec/easyeat/MainActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/MainActivity.kt index 8355af8..24cc32f 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/MainActivity.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/MainActivity.kt @@ -36,11 +36,5 @@ class MainActivity : AppCompatActivity() { setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) - - findViewById(R.id.add_dish).setOnClickListener { - val intent = Intent(this, CreateDishActivity::class.java) - startActivity(intent) - } - } } diff --git a/app/app/src/main/java/tech/mercantec/easyeat/models/Ingredient.kt b/app/app/src/main/java/tech/mercantec/easyeat/models/Ingredient.kt new file mode 100644 index 0000000..7413734 --- /dev/null +++ b/app/app/src/main/java/tech/mercantec/easyeat/models/Ingredient.kt @@ -0,0 +1,7 @@ +package tech.mercantec.easyeat.models + +data class Ingredient( + val Amount: Int, + val Unit: String, + val Element: String +) \ No newline at end of file diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt index c54aeda..72feca8 100644 --- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt +++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt @@ -1,11 +1,13 @@ package tech.mercantec.easyeat.ui.dishes +import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment +import tech.mercantec.easyeat.CreateDishActivity import tech.mercantec.easyeat.databinding.FragmentDishesBinding import tech.mercantec.easyeat.models.Dish @@ -25,6 +27,11 @@ class DishesFragment : Fragment() { _binding = FragmentDishesBinding.inflate(inflater, container, false) val root: View = binding.root + binding.addDish.setOnClickListener { + val intent = Intent(requireContext(), CreateDishActivity::class.java) + startActivity(intent) + } + context?.let { context -> binding.dishesList.setOnItemClickListener { parent, view, position, id -> val selectedItem = parent.getItemAtPosition(position) as Dish @@ -47,9 +54,13 @@ class DishesFragment : Fragment() { binding.dishesList.adapter = DishAdapter(context, listItems) } + return root } + + + override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/app/src/main/res/layout/activity_create_dish_form.xml b/app/app/src/main/res/layout/activity_create_dish_form.xml index 62e333a..cfb4252 100644 --- a/app/app/src/main/res/layout/activity_create_dish_form.xml +++ b/app/app/src/main/res/layout/activity_create_dish_form.xml @@ -27,5 +27,13 @@ android:text="Add Ingredient" android:layout_gravity="center_horizontal" android:layout_marginTop="16dp"/> + +