Implement updating username/email and changing password and logout

This commit is contained in:
Reimar 2025-05-05 13:20:33 +02:00
parent a446ad934c
commit 0c1f167e20
Signed by: Reimar
GPG Key ID: 93549FA07F0AE268
10 changed files with 330 additions and 12 deletions

View File

@ -1,6 +1,7 @@
<?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" />
<application
@ -40,8 +41,16 @@
android:exported="false" />
<activity
android:name=".CreateDishActivity" />
android:name=".CreateDishActivity"
android:exported="false" />
<activity
android:name=".ChangePasswordActivity"
android:exported="false" />
<activity
android:name=".EditProfileActivity"
android:exported="false" />
</application>
</manifest>

View File

@ -0,0 +1,59 @@
package tech.mercantec.easyeat
import android.app.ProgressDialog
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.changePassword
import kotlin.concurrent.thread
class ChangePasswordActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_change_password)
findViewById<Button>(R.id.save).setOnClickListener {
val currentPassword = findViewById<EditText>(R.id.current_password).text.toString()
val newPassword = findViewById<EditText>(R.id.new_password).text.toString()
val confirmPassword = findViewById<EditText>(R.id.confirm_password).text.toString()
if (newPassword != confirmPassword) {
Toast.makeText(this, "Passwords must match", Toast.LENGTH_LONG).show()
return@setOnClickListener
}
val progressDialog = ProgressDialog(this)
progressDialog.setMessage("Loading...")
progressDialog.show()
thread {
try {
changePassword(this, currentPassword, newPassword)
} catch (e: ApiRequestException) {
runOnUiThread {
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
}
return@thread
} finally {
runOnUiThread {
progressDialog.hide()
}
}
runOnUiThread {
Toast.makeText(this, "Password changed successfully", Toast.LENGTH_LONG).show()
}
finish()
}
}
}
}

View File

@ -0,0 +1,49 @@
package tech.mercantec.easyeat
import android.app.ProgressDialog
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.updateUser
import kotlin.concurrent.thread
class EditProfileActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit_profile)
findViewById<EditText>(R.id.username).setText(intent.extras?.getString("username"), TextView.BufferType.EDITABLE)
findViewById<EditText>(R.id.email).setText(intent.extras?.getString("email"), TextView.BufferType.EDITABLE)
findViewById<Button>(R.id.save).setOnClickListener {
val username = findViewById<EditText>(R.id.username).text.toString().trim()
val email = findViewById<EditText>(R.id.email).text.toString().trim()
val progressDialog = ProgressDialog(this)
progressDialog.setMessage("Loading...")
progressDialog.show()
thread {
try {
updateUser(this, username, email)
} catch (e: ApiRequestException) {
runOnUiThread {
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
}
return@thread
} finally {
runOnUiThread {
progressDialog.hide()
}
}
finish()
}
}
}
}

View File

@ -24,6 +24,16 @@ fun login(ctx: Context, email: String, password: String) {
}
}
fun logout(ctx: Context) {
with (ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) {
remove("user-id")
remove("username")
remove("auth-token")
remove("refresh-token")
apply()
}
}
@Serializable
data class CreateUserRequest(val email: String, val userName: String, val password: String)
@ -79,7 +89,23 @@ fun isLoggedIn(ctx: Context): Boolean {
data class UserInfoResponse(val id: Int, val userName: String, val email: String)
fun getUserInfo(ctx: Context): UserInfoResponse {
val response = requestJson<Unit, UserInfoResponse>(ctx, "GET", "/api/User/get", null)
return response
return requestJson<Unit, UserInfoResponse>(ctx, "GET", "/api/User/get", null)
}
@Serializable
data class UpdateUserRequest(val userName: String, val email: String)
fun updateUser(ctx: Context, username: String, email: String) {
val request = UpdateUserRequest(username, email)
return requestJson<UpdateUserRequest, Unit>(ctx, "PUT", "/api/User/update", request)
}
@Serializable
data class ChangePasswordRequest(val oldPassword: String, val newPassword: String)
fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
val request = ChangePasswordRequest(oldPassword, newPassword)
return requestJson<ChangePasswordRequest, Unit>(ctx, "PUT", "/api/User/change-password", request)
}

View File

@ -1,15 +1,21 @@
package tech.mercantec.easyeat.ui.profile
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.ChangePasswordActivity
import tech.mercantec.easyeat.EditProfileActivity
import tech.mercantec.easyeat.LoginActivity
import tech.mercantec.easyeat.WelcomeActivity
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 tech.mercantec.easyeat.helpers.logout
import kotlin.concurrent.thread
class ProfileFragment : Fragment() {
@ -31,9 +37,28 @@ class ProfileFragment : Fragment() {
activity?.runOnUiThread {
binding.username.text = userInfo.userName
binding.email.text = userInfo.email
binding.editProfile.setOnClickListener {
val intent = Intent(activity, EditProfileActivity::class.java)
intent.putExtra("username", userInfo.userName)
intent.putExtra("email", userInfo.email)
startActivity(intent)
}
}
}
binding.changePassword.setOnClickListener {
startActivity(Intent(activity, ChangePasswordActivity::class.java))
}
binding.logout.setOnClickListener {
logout(requireContext())
val intent = Intent(activity, WelcomeActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(intent)
}
return binding.root
}
}

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="2dp"
android:text="@string/current_password_label"
/>
<EditText
android:id="@+id/current_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password_hint"
android:autofillHints="password"
android:inputType="textPassword"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="2dp"
android:text="@string/new_password_label"
/>
<EditText
android:id="@+id/new_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password_hint"
android:autofillHints="password"
android:inputType="textPassword"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="2dp"
android:text="@string/confirm_new_password_label"
/>
<EditText
android:id="@+id/confirm_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password_hint"
android:autofillHints="password"
android:inputType="textPassword"
/>
<Button
android:id="@+id/save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="@string/save_label"
/>
</LinearLayout>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="2dp"
android:text="@string/username_label"
/>
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/username_hint"
android:autofillHints="username"
android:inputType="text"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="2dp"
android:text="@string/email_label"
/>
<EditText
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email_hint"
android:autofillHints="emailAddress"
android:inputType="textEmailAddress"
/>
<Button
android:id="@+id/save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="@string/save_label"
/>
</LinearLayout>

View File

@ -17,7 +17,7 @@
<TextView
android:layout_marginTop="50sp"
android:layout_marginLeft="2sp"
android:layout_marginStart="2sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/email_label"
@ -33,11 +33,11 @@
<TextView
android:layout_marginTop="20sp"
android:layout_marginLeft="2sp"
android:layout_marginStart="2sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/password_label"
/>
/>
<EditText
android:id="@+id/password"

View File

@ -43,11 +43,36 @@
android:text="@string/loading"
/>
<Button
android:layout_marginTop="40dp"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/edit_profile_label"
/>
android:orientation="vertical">
</LinearLayout>
<Button
android:id="@+id/edit_profile"
android:layout_marginTop="40dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/edit_profile_label"
/>
<Button
android:id="@+id/change_password"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/change_password_label"
/>
<Button
android:id="@+id/logout"
android:layout_marginTop="40dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/dark_gray"
android:text="@string/logout_label"
/>
</LinearLayout>
</LinearLayout>

View File

@ -14,8 +14,12 @@
<string name="email_hint">john@doe.com</string>
<string name="password_label">Password</string>
<string name="confirm_password_label">Confirm password</string>
<string name="current_password_label">Current password</string>
<string name="new_password_label">New password</string>
<string name="confirm_new_password_label">Confirm new password</string>
<string name="password_hint">&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;</string>
<string name="back_label">Back</string>
<string name="save_label">Save</string>
<string name="create_dish_heading">Create Dish</string>
<string name="ingredient_label">Ingredient</string>
<string name="measurement_label">Measurement</string>
@ -32,6 +36,8 @@
<string name="ingredient_amount_hint">500</string>
<string name="ingredient_name_label">Name</string>
<string name="ingredient_name_hint">Beef</string>
<string name="change_password_label">Change password</string>
<string name="logout_label">Log out</string>
<string-array name="units">
<item>g</item>
<item>kg</item>