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"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
@ -40,8 +41,16 @@
android:exported="false" /> android:exported="false" />
<activity <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> </application>
</manifest> </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 @Serializable
data class CreateUserRequest(val email: String, val userName: String, val password: String) 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) data class UserInfoResponse(val id: Int, val userName: String, val email: String)
fun getUserInfo(ctx: Context): UserInfoResponse { fun getUserInfo(ctx: Context): UserInfoResponse {
val response = requestJson<Unit, UserInfoResponse>(ctx, "GET", "/api/User/get", null) return requestJson<Unit, UserInfoResponse>(ctx, "GET", "/api/User/get", null)
}
return response
@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 package tech.mercantec.easyeat.ui.profile
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment 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.databinding.FragmentProfileBinding
import tech.mercantec.easyeat.helpers.ApiRequestException import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.UserInfoResponse import tech.mercantec.easyeat.helpers.UserInfoResponse
import tech.mercantec.easyeat.helpers.getUserInfo import tech.mercantec.easyeat.helpers.getUserInfo
import tech.mercantec.easyeat.helpers.logout
import kotlin.concurrent.thread import kotlin.concurrent.thread
class ProfileFragment : Fragment() { class ProfileFragment : Fragment() {
@ -31,9 +37,28 @@ class ProfileFragment : Fragment() {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.username.text = userInfo.userName binding.username.text = userInfo.userName
binding.email.text = userInfo.email 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 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 <TextView
android:layout_marginTop="50sp" android:layout_marginTop="50sp"
android:layout_marginLeft="2sp" android:layout_marginStart="2sp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/email_label" android:text="@string/email_label"
@ -33,11 +33,11 @@
<TextView <TextView
android:layout_marginTop="20sp" android:layout_marginTop="20sp"
android:layout_marginLeft="2sp" android:layout_marginStart="2sp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/password_label" android:text="@string/password_label"
/> />
<EditText <EditText
android:id="@+id/password" android:id="@+id/password"

View File

@ -43,11 +43,36 @@
android:text="@string/loading" android:text="@string/loading"
/> />
<Button <LinearLayout
android:layout_marginTop="40dp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="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="email_hint">john@doe.com</string>
<string name="password_label">Password</string> <string name="password_label">Password</string>
<string name="confirm_password_label">Confirm 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="password_hint">&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;</string>
<string name="back_label">Back</string> <string name="back_label">Back</string>
<string name="save_label">Save</string>
<string name="create_dish_heading">Create Dish</string> <string name="create_dish_heading">Create Dish</string>
<string name="ingredient_label">Ingredient</string> <string name="ingredient_label">Ingredient</string>
<string name="measurement_label">Measurement</string> <string name="measurement_label">Measurement</string>
@ -32,6 +36,8 @@
<string name="ingredient_amount_hint">500</string> <string name="ingredient_amount_hint">500</string>
<string name="ingredient_name_label">Name</string> <string name="ingredient_name_label">Name</string>
<string name="ingredient_name_hint">Beef</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"> <string-array name="units">
<item>g</item> <item>g</item>
<item>kg</item> <item>kg</item>