I hope you are all doing well.
I have run into a few problems and can't seem to find the answer online in an applicable way to my scenario. I am coding in Kotlin.
My database resides on an external host but I have already got the database connection set up and connected.
- I have a login activity with a username and password field, and a login button. I have managed to verify the login details by setting specific credentials but I now have a database,
SQL
, linked to myandroid app
. How do I verify the login credentials the user input against the database and check if the user is active?
Name: Bobby
Database Host: sql99.dbn7.host-h.net
Database Name: JimmysWorldDB
Driver Source: Built-in library
The tables used here are as follows:
1. UserLogins
Column 1 : UserID
Column 2 : FullName
Column 3 : Username
Column 4 : Password
Column 5 : HasAccess
2. LoginRecords
Column 1 : RecordID
Column 2 : Date
Column 3 : Logon <--- This is a time field
Column 4 : Logoff <--- This is a time field
Column 5 : Username
- So basically I would like to know how to make the
app
check the verify theUsername
andPassword
and only if the memberHasAccess = true
then have a successful login. <--- All fromUserLogins
table
Then if the user has logged in successfully, save a LoginRecord
where it puts the date
, login time
and the username
.
My code is as follows below.
LoginActivity.kt
name of the button is button_login
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.jimmysworld.MainActivity
import com.jimmysworld.R
import com.jimmysworld.databinding.ActivityLoginBinding
class LoginActivity : AppCompatActivity() {
private lateinit var loginViewModel: LoginViewModel
private lateinit var binding: ActivityLoginBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
val username = binding.username
val password = binding.password
val login = binding.login
val loading = binding.loading
loginViewModel = ViewModelProvider(this, LoginViewModelFactory())[LoginViewModel::class.java]
loginViewModel.loginFormState.observe(this@LoginActivity, Observer {
val loginState = it ?: return@Observer
// disable login button unless both username / password is valid
login.isEnabled = loginState.isDataValid
if (loginState.usernameError != null) {
username.error = getString(loginState.usernameError)
}
if (loginState.passwordError != null) {
password.error = getString(loginState.passwordError)
}
})
loginViewModel.loginResult.observe(this@LoginActivity, Observer {
val loginResult = it ?: return@Observer
loading.visibility = View.GONE
if (loginResult.error != null) {
showLoginFailed(loginResult.error)
}
if (loginResult.success != null) {
updateUiWithUser(loginResult.success)
}
setResult(Activity.RESULT_OK)
//Complete and destroy login activity once successful
finish()
})
username.afterTextChanged {
loginViewModel.loginDataChanged(
username.text.toString(),
password.text.toString()
)
}
password.apply {
afterTextChanged {
loginViewModel.loginDataChanged(
username.text.toString(),
password.text.toString()
)
}
setOnEditorActionListener { _, actionId, _ ->
when (actionId) {
EditorInfo.IME_ACTION_DONE ->
loginViewModel.login(
username.text.toString(),
password.text.toString()
)
}
false
}
login.setOnClickListener {
loading.visibility = View.VISIBLE
loginViewModel.login(username.text.toString(), password.text.toString())
}
}
}
private fun updateUiWithUser(model: LoggedInUserView) {
val welcome = getString(R.string.welcome)
val displayName = model.displayName
// TODO : initiate successful logged in experience
Toast.makeText(
applicationContext,
"$welcome $displayName",
Toast.LENGTH_LONG
).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
private fun showLoginFailed(@StringRes errorString: Int) {
Toast.makeText(applicationContext, errorString, Toast.LENGTH_SHORT).show()
}
}
LoginViewModel.kt
import android.util.Patterns
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.jimmysworld.R
import com.jimmysworld.data.LoginRepository
import com.jimmysworld.data.Result
class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() {
private val _loginForm = MutableLiveData<LoginFormState>()
val loginFormState: LiveData<LoginFormState> = _loginForm
private val _loginResult = MutableLiveData<LoginResult>()
val loginResult: LiveData<LoginResult> = _loginResult
fun login(username: String, password: String) {
// can be launched in a separate asynchronous job
val result = loginRepository.login(username, password)
val user = "Admin"
val pass = "1234567"
if (username.toString() == user && password.toString() == pass) {
if (result is Result.Success) {
_loginResult.value =
LoginResult(success = LoggedInUserView(displayName = result.data.displayName))
}
} else {
_loginResult.value = LoginResult(error = R.string.login_failed)
}
}
fun loginDataChanged(username: String, password: String) {
if (!isUserNameValid(username)) {
_loginForm.value = LoginFormState(usernameError = R.string.invalid_username)
} else if (!isPasswordValid(password)) {
_loginForm.value = LoginFormState(passwordError = R.string.invalid_password)
} else {
_loginForm.value = LoginFormState(isDataValid = true)
}
}
// A placeholder username validation check
private fun isUserNameValid(username: String): Boolean {
return if (username.contains('@')) {
Patterns.EMAIL_ADDRESS.matcher(username).matches()
} else {
username.isNotBlank()
}
}
// A placeholder password validation check
private fun isPasswordValid(password: String): Boolean {
return password.length > 7
}
}
LoggedInUser
import com.jimmysworld.data.model.LoggedInUser
class LoginRepository(val dataSource: LoginDataSource) {
var user: LoggedInUser? = null
private set
val isLoggedIn: Boolean
get() = user != null
init {
user = null
}
fun logout() {
user = null
dataSource.logout()
}
fun login(username: String, password: String): Result<LoggedInUser> {
// handle login
val result = dataSource.login(username, password)
if (result is Result.Success) {
setLoggedInUser(result.data)
}
return result
}
private fun setLoggedInUser(loggedInUser: LoggedInUser) {
this.user = loggedInUser
}
}
LoginViewModelFactory.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.jimmysworld.data.LoginDataSource
import com.jimmysworld.data.LoginRepository
class LoginViewModelFactory : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
return LoginViewModel(
loginRepository = LoginRepository(
dataSource = LoginDataSource()
)
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
I am sorry for it being so long winded and appreciate any help I can get. Thanks in advance.
CodePudding user response:
You probably need a database driver.
I have not written for Android, but it looks like Android does not natively support mysql db connections. One way to make this happen is to use a PHP middleman. That's wild.
Here is a link about using PHP for this purpose. https://www.tutorialspoint.com/android/android_php_mysql.htm