From 7c45526563121381df37a30291032be5413c3120 Mon Sep 17 00:00:00 2001 From: Reimar Date: Thu, 1 May 2025 12:02:55 +0200 Subject: [PATCH] Add profile page, implement authentication --- app/app/src/main/AndroidManifest.xml | 3 +- .../tech/mercantec/easyeat/MainActivity.kt | 8 ++- .../tech/mercantec/easyeat/helpers/api.kt | 23 ++++++-- .../tech/mercantec/easyeat/helpers/auth.kt | 13 +++++ .../ui/notifications/NotificationsFragment.kt | 42 --------------- .../notifications/NotificationsViewModel.kt | 13 ----- .../easyeat/ui/profile/ProfileFragment.kt | 39 ++++++++++++++ .../res/drawable/ic_account_circle_24px.xml | 10 ++++ ...lt_black_24px.xml => ic_list_alt_24px.xml} | 0 .../drawable/ic_notifications_black_24dp.xml | 9 ---- .../src/main/res/drawable/ic_person_24px.xml | 10 ++++ ..._black_24px.xml => ic_restaurant_24px.xml} | 0 .../res/layout/fragment_notifications.xml | 22 -------- .../src/main/res/layout/fragment_profile.xml | 53 +++++++++++++++++++ app/app/src/main/res/menu/bottom_nav_menu.xml | 10 ++-- .../main/res/navigation/mobile_navigation.xml | 8 +-- app/app/src/main/res/values/strings.xml | 6 +-- 17 files changed, 164 insertions(+), 105 deletions(-) delete mode 100644 app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsFragment.kt delete mode 100644 app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsViewModel.kt create mode 100644 app/app/src/main/java/tech/mercantec/easyeat/ui/profile/ProfileFragment.kt create mode 100644 app/app/src/main/res/drawable/ic_account_circle_24px.xml rename app/app/src/main/res/drawable/{ic_list_alt_black_24px.xml => ic_list_alt_24px.xml} (100%) delete mode 100644 app/app/src/main/res/drawable/ic_notifications_black_24dp.xml create mode 100644 app/app/src/main/res/drawable/ic_person_24px.xml rename app/app/src/main/res/drawable/{ic_restaurant_black_24px.xml => ic_restaurant_24px.xml} (100%) delete mode 100644 app/app/src/main/res/layout/fragment_notifications.xml create mode 100644 app/app/src/main/res/layout/fragment_profile.xml diff --git a/app/app/src/main/AndroidManifest.xml b/app/app/src/main/AndroidManifest.xml index 215816d..b07b3bd 100644 --- a/app/app/src/main/AndroidManifest.xml +++ b/app/app/src/main/AndroidManifest.xml @@ -25,8 +25,7 @@ + android:exported="false" /> (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/helpers/api.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/api.kt index b4290ed..e9a472d 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 @@ -1,6 +1,7 @@ package tech.mercantec.easyeat.helpers import android.content.Context +import android.content.Intent import android.util.Log import android.widget.Toast import kotlinx.serialization.Serializable @@ -10,32 +11,46 @@ import java.net.HttpURLConnection import java.net.URL import kotlinx.serialization.json.* import kotlinx.serialization.serializer +import tech.mercantec.easyeat.LoginActivity import java.io.IOException class ApiRequestException(message: String, cause: Throwable?) : Exception(message, cause) class HttpResponse(val body: String, val code: Int) -fun request(ctx: Context, method: String, path: String, data: String?): HttpResponse { +fun request(ctx: Context, method: String, path: String, data: String?, autoRefresh: Boolean = true): HttpResponse { val url = URL(BuildConfig.API_BASE_URL + path) val prefs = ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE) val authToken = prefs.getString("auth-token", null) + val refreshToken = prefs.getString("auth-token", null) try { with(url.openConnection() as HttpURLConnection) { requestMethod = method + if (authToken != null) + setRequestProperty("Authorization", "Bearer $authToken") + if (data != null) { setRequestProperty("Content-Type", "application/json") - if (authToken != null) - setRequestProperty("Authorization", "Bearer $authToken") - outputStream.write(data.toByteArray()) outputStream.flush() } + if (responseCode == 401 && refreshToken != null) { + if (!autoRefresh || !refreshAuthToken(ctx, refreshToken)) { + val intent = Intent(ctx, LoginActivity::class.java) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + ctx.startActivity(intent) + + throw ApiRequestException("Please sign in again", null) + } + + return request(ctx, method, path, data, false) + } + if (responseCode >= 400) return HttpResponse(errorStream.readBytes().decodeToString(), responseCode) 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 6c45884..6e5e54b 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 @@ -1,6 +1,7 @@ package tech.mercantec.easyeat.helpers import android.content.Context +import android.util.Log import kotlinx.serialization.Serializable @Serializable @@ -47,6 +48,9 @@ fun refreshAuthToken(ctx: Context, refreshToken: String): Boolean { RefreshTokenRequest(refreshToken) ) } catch (e: ApiRequestException) { + if (e.message != null) + Log.e("EasyEat", e.message!!) + return false } @@ -70,3 +74,12 @@ fun isLoggedIn(ctx: Context): Boolean { return true } + +@Serializable +data class UserInfoResponse(val id: Int, val userName: String, val email: String) + +fun getUserInfo(ctx: Context): UserInfoResponse { + val response = requestJson(ctx, "GET", "/api/User/get", null) + + return response +} diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsFragment.kt deleted file mode 100644 index d84d797..0000000 --- a/app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsFragment.kt +++ /dev/null @@ -1,42 +0,0 @@ -package tech.mercantec.easyeat.ui.notifications - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import tech.mercantec.easyeat.databinding.FragmentNotificationsBinding - -class NotificationsFragment : Fragment() { - - private var _binding: FragmentNotificationsBinding? = null - - // This property is only valid between onCreateView and - // onDestroyView. - private val binding get() = _binding!! - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - val notificationsViewModel = - ViewModelProvider(this).get(NotificationsViewModel::class.java) - - _binding = FragmentNotificationsBinding.inflate(inflater, container, false) - val root: View = binding.root - - val textView: TextView = binding.textNotifications - notificationsViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsViewModel.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsViewModel.kt deleted file mode 100644 index 3575983..0000000 --- a/app/app/src/main/java/tech/mercantec/easyeat/ui/notifications/NotificationsViewModel.kt +++ /dev/null @@ -1,13 +0,0 @@ -package tech.mercantec.easyeat.ui.notifications - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class NotificationsViewModel : ViewModel() { - - private val _text = MutableLiveData().apply { - value = "This is notifications Fragment" - } - val text: LiveData = _text -} \ No newline at end of file diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/profile/ProfileFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/profile/ProfileFragment.kt new file mode 100644 index 0000000..506f555 --- /dev/null +++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/profile/ProfileFragment.kt @@ -0,0 +1,39 @@ +package tech.mercantec.easyeat.ui.profile + +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.databinding.FragmentProfileBinding +import tech.mercantec.easyeat.helpers.ApiRequestException +import tech.mercantec.easyeat.helpers.UserInfoResponse +import tech.mercantec.easyeat.helpers.getUserInfo +import kotlin.concurrent.thread + +class ProfileFragment : Fragment() { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + val binding = FragmentProfileBinding.inflate(inflater, container, false) + + thread { + val userInfo: UserInfoResponse + try { + userInfo = getUserInfo(requireContext()) + } catch (e: ApiRequestException) { + activity?.runOnUiThread { + Toast.makeText(activity?.applicationContext, e.message, Toast.LENGTH_LONG).show() + } + + return@thread + } + + activity?.runOnUiThread { + binding.username.text = userInfo.userName + binding.email.text = userInfo.email + } + } + + return binding.root + } +} diff --git a/app/app/src/main/res/drawable/ic_account_circle_24px.xml b/app/app/src/main/res/drawable/ic_account_circle_24px.xml new file mode 100644 index 0000000..3f33c15 --- /dev/null +++ b/app/app/src/main/res/drawable/ic_account_circle_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/app/src/main/res/drawable/ic_list_alt_black_24px.xml b/app/app/src/main/res/drawable/ic_list_alt_24px.xml similarity index 100% rename from app/app/src/main/res/drawable/ic_list_alt_black_24px.xml rename to app/app/src/main/res/drawable/ic_list_alt_24px.xml diff --git a/app/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/app/src/main/res/drawable/ic_notifications_black_24dp.xml deleted file mode 100644 index 78b75c3..0000000 --- a/app/app/src/main/res/drawable/ic_notifications_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/app/src/main/res/drawable/ic_person_24px.xml b/app/app/src/main/res/drawable/ic_person_24px.xml new file mode 100644 index 0000000..6fcf704 --- /dev/null +++ b/app/app/src/main/res/drawable/ic_person_24px.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/app/src/main/res/drawable/ic_restaurant_black_24px.xml b/app/app/src/main/res/drawable/ic_restaurant_24px.xml similarity index 100% rename from app/app/src/main/res/drawable/ic_restaurant_black_24px.xml rename to app/app/src/main/res/drawable/ic_restaurant_24px.xml diff --git a/app/app/src/main/res/layout/fragment_notifications.xml b/app/app/src/main/res/layout/fragment_notifications.xml deleted file mode 100644 index d417935..0000000 --- a/app/app/src/main/res/layout/fragment_notifications.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/app/src/main/res/layout/fragment_profile.xml b/app/app/src/main/res/layout/fragment_profile.xml new file mode 100644 index 0000000..97bbb99 --- /dev/null +++ b/app/app/src/main/res/layout/fragment_profile.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + +