feat: Add settings activity
This commit is contained in:
parent
49ca0f79a2
commit
5cd48cfed6
|
@ -3,8 +3,10 @@ package com.p_vacho.neat_calendar
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.p_vacho.neat_calendar.activities.ApiUnreachableActivity
|
import com.p_vacho.neat_calendar.activities.ApiUnreachableActivity
|
||||||
import com.p_vacho.neat_calendar.activities.LoginActivity
|
import com.p_vacho.neat_calendar.activities.LoginActivity
|
||||||
|
import com.p_vacho.neat_calendar.api.models.ValidationError
|
||||||
import com.p_vacho.neat_calendar.util.ExceptionSerializer
|
import com.p_vacho.neat_calendar.util.ExceptionSerializer
|
||||||
import com.p_vacho.neat_calendar.util.SerializedException
|
import com.p_vacho.neat_calendar.util.SerializedException
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
|
@ -43,6 +45,19 @@ class GlobalExceptionHandler(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.code() == 422) {
|
||||||
|
Log.e("GlobalExceptionHandler", "Caught HTTP 422 Exception")
|
||||||
|
val errorBody = e.response()?.errorBody()?.string()
|
||||||
|
val validationError = Gson().fromJson(errorBody, ValidationError::class.java)
|
||||||
|
Log.e("GlobalExceptionHandler", "Details: $validationError")
|
||||||
|
|
||||||
|
// This exception is still unhandled, the above just logs it in a nicer way
|
||||||
|
// so we can see what exactly went wrong. We still want to propagate the exception
|
||||||
|
// up to default handler now.
|
||||||
|
defaultHandler?.uncaughtException(t, e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Log.e("GlobalExceptionHandler", "Propgating unhandled exception", e)
|
Log.e("GlobalExceptionHandler", "Propgating unhandled exception", e)
|
||||||
defaultHandler?.uncaughtException(t, e)
|
defaultHandler?.uncaughtException(t, e)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,13 +1,40 @@
|
||||||
package com.p_vacho.neat_calendar.activities
|
package com.p_vacho.neat_calendar.activities
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import com.p_vacho.neat_calendar.MyApplication
|
||||||
import com.p_vacho.neat_calendar.R
|
import com.p_vacho.neat_calendar.R
|
||||||
|
import com.p_vacho.neat_calendar.api.RetrofitClient
|
||||||
|
import com.p_vacho.neat_calendar.api.models.PartialUserRequest
|
||||||
|
import com.p_vacho.neat_calendar.api.models.UserResponse
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import retrofit2.HttpException
|
||||||
|
|
||||||
class SettingsActivity : AppCompatActivity() {
|
class SettingsActivity : AppCompatActivity() {
|
||||||
|
private lateinit var etBaseUrl: TextInputEditText
|
||||||
|
private lateinit var etUsername: TextInputEditText
|
||||||
|
private lateinit var etEmail: TextInputEditText
|
||||||
|
private lateinit var etNewPassword: TextInputEditText
|
||||||
|
private lateinit var btnLogout: MaterialButton
|
||||||
|
private lateinit var btnDeleteAccount: MaterialButton
|
||||||
|
private lateinit var btnSave: MaterialButton
|
||||||
|
private lateinit var btnBack: MaterialButton
|
||||||
|
|
||||||
|
private lateinit var user: UserResponse
|
||||||
|
private lateinit var oldBaseUrl: String
|
||||||
|
private lateinit var oldUsername: String
|
||||||
|
private lateinit var oldEmail: String
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
@ -17,5 +44,114 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
insets
|
insets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
etBaseUrl = findViewById(R.id.etBaseUrl)
|
||||||
|
etUsername = findViewById(R.id.etUsername)
|
||||||
|
etEmail = findViewById(R.id.etEmail)
|
||||||
|
etNewPassword = findViewById(R.id.etNewPassword)
|
||||||
|
btnLogout = findViewById(R.id.btnLogout)
|
||||||
|
btnDeleteAccount = findViewById(R.id.btnDeleteAccount)
|
||||||
|
btnSave = findViewById(R.id.btnSave)
|
||||||
|
btnBack = findViewById(R.id.btnBack)
|
||||||
|
|
||||||
|
oldBaseUrl = RetrofitClient.getCurrentBaseUrl()
|
||||||
|
etBaseUrl.setText(oldBaseUrl)
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
user = withContext(Dispatchers.IO) {
|
||||||
|
RetrofitClient.usersService.getCurrentUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
oldEmail = user.email
|
||||||
|
etEmail.setText(oldEmail)
|
||||||
|
|
||||||
|
oldUsername = user.username
|
||||||
|
etUsername.setText(oldUsername)
|
||||||
|
}
|
||||||
|
|
||||||
|
btnBack.setOnClickListener { finish() }
|
||||||
|
btnSave.setOnClickListener { onSave() }
|
||||||
|
btnLogout.setOnClickListener { onLogout() }
|
||||||
|
btnDeleteAccount.setOnClickListener { onDeleteAccount() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSave() {
|
||||||
|
var changed = false
|
||||||
|
|
||||||
|
val newBaseUrl = etBaseUrl.text.toString()
|
||||||
|
if (newBaseUrl != oldBaseUrl) {
|
||||||
|
RetrofitClient.updateBaseUrl(newBaseUrl)
|
||||||
|
oldBaseUrl = newBaseUrl
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val newUsername = etUsername.text.toString()
|
||||||
|
val newEmail = etEmail.text.toString()
|
||||||
|
val newPassword = etNewPassword.text.toString()
|
||||||
|
|
||||||
|
lifecycleScope.launch() {
|
||||||
|
val req = PartialUserRequest(
|
||||||
|
username = if (newUsername != oldUsername) newUsername else null,
|
||||||
|
email = if (newEmail != oldEmail) newEmail else null,
|
||||||
|
password = if (newPassword.isNotEmpty()) newPassword else null,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (req.username != null || req.email != null || req.password != null) {
|
||||||
|
try {
|
||||||
|
val response = withContext(Dispatchers.IO) {
|
||||||
|
RetrofitClient.usersService.updateUser(user.user_id, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldUsername = response.username
|
||||||
|
oldEmail = response.email
|
||||||
|
etNewPassword.setText("")
|
||||||
|
changed = true
|
||||||
|
} catch (e: HttpException) {
|
||||||
|
if (e.code() != 409) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
Toast.makeText(this@SettingsActivity, "This username or email is already taken", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
Toast.makeText(this@SettingsActivity, "Changes saved", Toast.LENGTH_SHORT).show()
|
||||||
|
// Make a ping request, to re-check api connectivity
|
||||||
|
// TODO: Ping isn't a good enough check here, we should also validate tokens
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
RetrofitClient.ping()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this@SettingsActivity, "No changes made", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onLogout() {
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
(application as MyApplication).authRepository.logout()
|
||||||
|
navigateToLoginActivity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun onDeleteAccount() {
|
||||||
|
// TODO: Add a modal asking for confirmation
|
||||||
|
lifecycleScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
RetrofitClient.usersService.deleteUser(user.user_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
(application as MyApplication).tokenManager.clearTokens()
|
||||||
|
navigateToLoginActivity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigateToLoginActivity() {
|
||||||
|
val intent = Intent(this, LoginActivity::class.java)
|
||||||
|
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,4 +7,10 @@ data class UserResponse(
|
||||||
val username: String,
|
val username: String,
|
||||||
val email: String,
|
val email: String,
|
||||||
val created_at: OffsetDateTime,
|
val created_at: OffsetDateTime,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class PartialUserRequest(
|
||||||
|
val username: String?,
|
||||||
|
val password: String?,
|
||||||
|
val email: String?,
|
||||||
)
|
)
|
|
@ -1,13 +1,26 @@
|
||||||
package com.p_vacho.neat_calendar.api.services
|
package com.p_vacho.neat_calendar.api.services
|
||||||
|
|
||||||
|
import com.p_vacho.neat_calendar.api.models.PartialUserRequest
|
||||||
import com.p_vacho.neat_calendar.api.models.UserResponse
|
import com.p_vacho.neat_calendar.api.models.UserResponse
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.DELETE
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.PATCH
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
|
|
||||||
interface UsersService {
|
interface UsersService {
|
||||||
@GET("users")
|
@GET("users")
|
||||||
suspend fun getUsers(): List<UserResponse>
|
suspend fun getUsers(): List<UserResponse>
|
||||||
|
|
||||||
|
@GET("users/me")
|
||||||
|
suspend fun getCurrentUser(): UserResponse
|
||||||
|
|
||||||
@GET("users/{user_id}")
|
@GET("users/{user_id}")
|
||||||
suspend fun getUser(@Path("user_id") userId: String): UserResponse
|
suspend fun getUser(@Path("user_id") userId: String): UserResponse
|
||||||
|
|
||||||
|
@DELETE("users/{user_id}")
|
||||||
|
suspend fun deleteUser(@Path("user_id") userId: String): Unit
|
||||||
|
|
||||||
|
@PATCH("users/{user_id}")
|
||||||
|
suspend fun updateUser(@Path("user_id") userId: String, @Body userData: PartialUserRequest): UserResponse
|
||||||
}
|
}
|
9
app/src/main/res/drawable/ic_warning.xml
Normal file
9
app/src/main/res/drawable/ic_warning.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:pathData="m40,840 l440,-760 440,760L40,840ZM178,760h604L480,240 178,760ZM480,720q17,0 28.5,-11.5T520,680q0,-17 -11.5,-28.5T480,640q-17,0 -28.5,11.5T440,680q0,17 11.5,28.5T480,720ZM440,600h80v-200h-80v200ZM480,500Z"
|
||||||
|
android:fillColor="#e8eaed"/>
|
||||||
|
</vector>
|
|
@ -1,10 +1,193 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".activities.SettingsActivity">
|
android:fillViewport="true"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<LinearLayout
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- A single card containing all settings sections -->
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="4dp"
|
||||||
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<!-- ============= Section 1: Connection ============= -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvConnectionSectionHeader"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/connection_settings_section"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
<!-- Divider for the 'Connection' section -->
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:dividerColor="@android:color/darker_gray" />
|
||||||
|
|
||||||
|
<!-- Base URL field -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/tilBaseUrl"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/base_url"
|
||||||
|
app:boxStrokeWidth="1dp"
|
||||||
|
app:boxStrokeColor="?attr/colorPrimary">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etBaseUrl"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- ========== Section 2: User Management ========== -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUserManagementHeader"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/user_settings_section"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
<!-- Divider for the 'User Management' section -->
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:dividerColor="@android:color/darker_gray" />
|
||||||
|
|
||||||
|
<!-- Username field -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/tilUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/username"
|
||||||
|
app:boxStrokeWidth="1dp"
|
||||||
|
app:boxStrokeColor="?attr/colorPrimary"
|
||||||
|
android:layout_marginTop="4dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Email field -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/tilEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/email"
|
||||||
|
app:boxStrokeWidth="1dp"
|
||||||
|
app:boxStrokeColor="?attr/colorPrimary"
|
||||||
|
android:layout_marginTop="4dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textEmailAddress" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Password field (for changing password) -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/tilPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/new_password"
|
||||||
|
app:boxStrokeWidth="1dp"
|
||||||
|
app:boxStrokeColor="?attr/colorPrimary"
|
||||||
|
android:layout_marginTop="4dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etNewPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textPassword" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- Logout Button -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnLogout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:text="@string/logout"
|
||||||
|
app:icon="@drawable/ic_exit"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="8dp"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
|
||||||
|
|
||||||
|
<!-- Account Deletion Button -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnDeleteAccount"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/delete_account"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:icon="@drawable/ic_warning"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="8dp"
|
||||||
|
app:iconTint="@android:color/holo_red_dark"
|
||||||
|
app:strokeColor="@android:color/holo_red_dark"
|
||||||
|
app:strokeWidth="2dp"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
|
||||||
|
|
||||||
|
<!-- ========== Section 3: Controls ========== -->
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:dividerColor="@android:color/darker_gray" />
|
||||||
|
|
||||||
|
<!-- Save Settings Button -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnSave"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/save"
|
||||||
|
app:cornerRadius="8dp" />
|
||||||
|
|
||||||
|
<!-- Go back Button -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnBack"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:text="@string/back"
|
||||||
|
app:icon="@drawable/ic_arrow_back"
|
||||||
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="8dp"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
<string name="delete_event">Delete this event</string>
|
<string name="delete_event">Delete this event</string>
|
||||||
<string name="edit_event">Edit this event</string>
|
<string name="edit_event">Edit this event</string>
|
||||||
<string name="add_event">Add a new event</string>
|
<string name="add_event">Add a new event</string>
|
||||||
<string name="back">Go to the previous page</string>
|
<string name="back">Go back</string>
|
||||||
<string name="event_title">Event Title</string>
|
<string name="event_title">Event Title</string>
|
||||||
<string name="event_description">Event Description</string>
|
<string name="event_description">Event Description</string>
|
||||||
<string name="instant_event">Instant Event</string>
|
<string name="instant_event">Instant Event</string>
|
||||||
|
@ -47,4 +47,10 @@
|
||||||
<string name="leave_invited_event">Leave invited event</string>
|
<string name="leave_invited_event">Leave invited event</string>
|
||||||
<string name="open_app_settings">Open Settings</string>
|
<string name="open_app_settings">Open Settings</string>
|
||||||
<string name="open_notifications">Open Notifications</string>
|
<string name="open_notifications">Open Notifications</string>
|
||||||
|
<string name="connection_settings_section">Connection</string>
|
||||||
|
<string name="user_settings_section">User Settings</string>
|
||||||
|
<string name="new_password">New Password</string>
|
||||||
|
<string name="delete_account">Delete Account</string>
|
||||||
|
<string name="controls">Controls</string>
|
||||||
|
<string name="logout">Log out</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue