rearrange nav menu
This commit is contained in:
219
app/src/main/java/sh/sar/gridflow/AddAccountActivity.kt
Normal file
219
app/src/main/java/sh/sar/gridflow/AddAccountActivity.kt
Normal file
@@ -0,0 +1,219 @@
|
||||
package sh.sar.gridflow
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.launch
|
||||
import sh.sar.gridflow.databinding.ActivityAddAccountBinding
|
||||
import sh.sar.gridflow.network.ApiResult
|
||||
import sh.sar.gridflow.network.FenakaApiService
|
||||
import sh.sar.gridflow.utils.Account
|
||||
import sh.sar.gridflow.utils.SecureStorage
|
||||
|
||||
class AddAccountActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityAddAccountBinding
|
||||
private lateinit var secureStorage: SecureStorage
|
||||
private lateinit var apiService: FenakaApiService
|
||||
|
||||
companion object {
|
||||
private const val TAG = "AddAccountActivity"
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Force system theme (follows device dark mode setting)
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
|
||||
Log.d(TAG, "AddAccountActivity onCreate")
|
||||
|
||||
binding = ActivityAddAccountBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
// Set up the toolbar
|
||||
setSupportActionBar(binding.toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.title = "Add Account"
|
||||
|
||||
try {
|
||||
secureStorage = SecureStorage(this)
|
||||
apiService = FenakaApiService()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to initialize SecureStorage, continuing without it", e)
|
||||
apiService = FenakaApiService()
|
||||
Toast.makeText(this, "Warning: Secure storage not available", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
setupClickListeners()
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun setupClickListeners() {
|
||||
binding.btnSignIn.setOnClickListener {
|
||||
handleSignIn()
|
||||
}
|
||||
|
||||
binding.btnRegister.setOnClickListener {
|
||||
handleRegister()
|
||||
}
|
||||
|
||||
binding.btnForgotPassword.setOnClickListener {
|
||||
handleForgotPassword()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLoginError(message: String) {
|
||||
val dialog = androidx.appcompat.app.AlertDialog.Builder(this)
|
||||
.setTitle("Login Failed")
|
||||
.setMessage(message)
|
||||
.setPositiveButton("Retry") { _, _ ->
|
||||
// Retry the login with the same credentials
|
||||
handleSignIn()
|
||||
}
|
||||
.setNegativeButton("Cancel") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setCancelable(true)
|
||||
.create()
|
||||
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
private fun handleSignIn() {
|
||||
val mobileNumber = binding.etMobileNumber.text.toString().trim()
|
||||
val password = binding.etPassword.text.toString().trim()
|
||||
|
||||
Log.d(TAG, "handleSignIn called with mobile: $mobileNumber")
|
||||
|
||||
if (validateInput(mobileNumber, password)) {
|
||||
Log.d(TAG, "Input validation passed, calling performLogin")
|
||||
performLogin(mobileNumber, password)
|
||||
} else {
|
||||
Log.d(TAG, "Input validation failed")
|
||||
}
|
||||
}
|
||||
|
||||
private fun performLogin(mobile: String, password: String) {
|
||||
Log.d(TAG, "performLogin called with mobile: $mobile")
|
||||
|
||||
// Check if account already exists
|
||||
val existingAccounts = secureStorage.getAllAccounts()
|
||||
if (existingAccounts.any { it.mobile == mobile }) {
|
||||
Toast.makeText(this, "Account already exists", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
|
||||
lifecycleScope.launch {
|
||||
Log.d(TAG, "Starting coroutine for API call")
|
||||
try {
|
||||
when (val result = apiService.login(mobile, password)) {
|
||||
is ApiResult.Success -> {
|
||||
Log.d(TAG, "Login successful: ${result.data}")
|
||||
|
||||
// Create new account object
|
||||
val newAccount = Account(
|
||||
id = mobile,
|
||||
name = result.data.name,
|
||||
mobile = mobile,
|
||||
email = result.data.email,
|
||||
password = password,
|
||||
cookie = extractSessionId(result.cookie ?: ""),
|
||||
userId = result.data.id,
|
||||
isActive = false // Will be set as active when switched to
|
||||
)
|
||||
|
||||
// Save the new account
|
||||
secureStorage.saveAccount(newAccount)
|
||||
|
||||
setLoading(false)
|
||||
|
||||
// Show success message and finish
|
||||
Toast.makeText(this@AddAccountActivity, "Account added successfully", Toast.LENGTH_SHORT).show()
|
||||
|
||||
// Return to main activity
|
||||
val intent = Intent(this@AddAccountActivity, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
is ApiResult.Error -> {
|
||||
Log.d(TAG, "Login failed: ${result.message} (code: ${result.code})")
|
||||
setLoading(false)
|
||||
showLoginError(result.message)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Exception in performLogin coroutine", e)
|
||||
setLoading(false)
|
||||
showLoginError("Login failed: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractSessionId(setCookieHeader: String): String {
|
||||
// Extract the session ID from Set-Cookie header
|
||||
return setCookieHeader.substringBefore(";").substringAfter("connect.sid=")
|
||||
}
|
||||
|
||||
private fun setLoading(isLoading: Boolean) {
|
||||
binding.btnSignIn.isEnabled = !isLoading
|
||||
binding.btnSignIn.text = if (isLoading) "Signing in..." else "Sign In"
|
||||
|
||||
// Disable other buttons during loading
|
||||
binding.btnRegister.isEnabled = !isLoading
|
||||
binding.btnForgotPassword.isEnabled = !isLoading
|
||||
|
||||
// Show/hide progress indicator
|
||||
binding.etMobileNumber.isEnabled = !isLoading
|
||||
binding.etPassword.isEnabled = !isLoading
|
||||
}
|
||||
|
||||
private fun handleRegister() {
|
||||
Log.d(TAG, "Register button clicked")
|
||||
val intent = Intent(this, RegisterActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun handleForgotPassword() {
|
||||
Log.d(TAG, "Forgot password button clicked")
|
||||
val intent = Intent(this, ForgotPasswordActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun validateInput(mobileNumber: String, password: String): Boolean {
|
||||
if (mobileNumber.isEmpty()) {
|
||||
binding.etMobileNumber.error = "Mobile number is required"
|
||||
return false
|
||||
}
|
||||
|
||||
if (password.isEmpty()) {
|
||||
binding.etPassword.error = "Password is required"
|
||||
return false
|
||||
}
|
||||
|
||||
// Client-side password validation - must be at least 8 characters
|
||||
if (password.length < 8) {
|
||||
binding.etPassword.error = "Password must be at least 8 characters"
|
||||
return false
|
||||
}
|
||||
|
||||
// Basic Maldives mobile number validation (7xxxxxx format)
|
||||
if (!mobileNumber.matches(Regex("^[79]\\d{6}$"))) {
|
||||
binding.etMobileNumber.error = "Enter a valid Maldives mobile number"
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user