Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 3 additions & 8 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ android {

defaultConfig {
applicationId = "com.example.assignment_3"
minSdk = 24
minSdk = 22
targetSdk = 34
versionCode = 1
versionName = "1.0"
Expand All @@ -27,11 +27,11 @@ android {
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "11"
jvmTarget = "1.8"
}
}

Expand All @@ -40,11 +40,11 @@ dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation("com.google.android.material:material:1.4.0")
implementation("androidx.fragment:fragment-ktx:1.6.1")
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
testImplementation(libs.junit.jupiter)
testImplementation(libs.junit.jupiter)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
14 changes: 6 additions & 8 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,18 @@
tools:targetApi="31">

<activity
android:name=".CreateAccountActivity"
android:exported="true">
android:name=".MainActivity"

android:exported="true" >

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SignUpDetailsActivity"
android:exported="true" />
<activity
android:name=".MainActivity"
android:exported="true" />
<activity android:name=".RecipeDetailActivity" />

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.example.assignment_3
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
class CreateAccountFragment : Fragment() {
private val credentialsManager = CredentialsManager
private lateinit var emailField: TextInputEditText
private lateinit var emailLayout: TextInputLayout
private lateinit var passwordField: TextInputEditText
private lateinit var passwordLayout: TextInputLayout
private lateinit var nextButton: Button
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_create_account, container, false)
emailField = view.findViewById(R.id.etEmail)
emailLayout = view.findViewById(R.id.textInputEmail)
passwordField = view.findViewById(R.id.etPassword)
passwordLayout = view.findViewById(R.id.textInputPassword)
nextButton = view.findViewById(R.id.btnNext)
nextButton.setOnClickListener { onNextButtonClick() }
view.findViewById<TextView>(R.id.tvRegisterNoww).setOnClickListener {
navigateToSignUpDetailsFragment()
}
return view
}
private fun onNextButtonClick() {
val email = emailField.text.toString().trim()
val password = passwordField.text.toString().trim()
clearAllErrors()
when {
email.isEmpty() -> setError(emailLayout, R.string.error_email_required)
!credentialsManager.isEmailValid(email) -> setError(
emailLayout,
R.string.error_invalid_email
)
password.isEmpty() -> setError(passwordLayout, R.string.error_password_required)
!credentialsManager.isValidPassword(password) -> setError(
passwordLayout,
R.string.error_password_invalid
)
else -> {
if (CredentialsManager.validateCredentials(email, password)) {
navigateToMainActivity(email, password)
} else {
showToast(R.string.error_invalid_credentials)
}
}
}
}
private fun setError(layout: TextInputLayout, errorResId: Int?) {
layout.error = errorResId?.let { getString(it) }
}
private fun clearAllErrors() {
setError(emailLayout, null)
setError(passwordLayout, null)
}
private fun showToast(messageResId: Int) {
Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show()
}
private fun navigateToMainActivity(email: String, password: String) {
credentialsManager.setLoggedIn(requireContext(), true)
credentialsManager.saveUserCredentials(requireContext(), email, password)
val intent = Intent(requireContext(), MainActivity::class.java).apply {
putExtra("email", email)
putExtra("password", password)
}
startActivity(intent)
requireActivity().finish()
}
private fun navigateToSignUpDetailsFragment() {
parentFragmentManager.beginTransaction()
.replace(R.id.fragmentContainerView, SignUpDetailsFragment())
.addToBackStack(null)
.commit()
}
}
69 changes: 49 additions & 20 deletions app/src/main/java/com/example/assignment_3/CredentialsManager.kt
Original file line number Diff line number Diff line change
@@ -1,38 +1,70 @@
// Put your package name here. Check your activity for reference.

package com.example.assignment_3

import android.content.Context

object CredentialsManager {

private const val PREFS_NAME = "user_prefs"
private const val KEY_IS_LOGGED_IN = "is_logged_in"
private const val KEY_EMAIL = "email"
private const val KEY_PASSWORD = "password"

private val emailPattern = ("[a-zA-Z0-9\\+\\%\\-\\+]{1,256}" +
"\\@" +
"[a-zA-Z0-9][0-zA-Z0-9\\-]{0,64}" +
"[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
"(" +
"\\." +
"[a-zA-Z0-9][0-zA-Z0-9\\-]{0,25}" +
"[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
")+").toRegex()

private val registeredUsers = mutableMapOf<String, String>()

fun isEmailValid(email: String): Boolean {
return email.matches(emailPattern)
}
fun isEmailValid(email: String): Boolean = email.matches(emailPattern)

fun isEmailAlreadyUsed(email: String): Boolean {
return registeredUsers.containsKey(email.lowercase())
}
fun isEmailAlreadyUsed(email: String): Boolean = registeredUsers.containsKey(email.lowercase())

fun isValidPassword(password: String): Boolean = password.length >= 8

fun isValidFullName(fullName: String): Boolean = fullName.isNotEmpty()

fun isValidPassword(password: String): Boolean {
return password.length >= 8
}

fun registerUser(email: String, password: String): Boolean {
if (isEmailAlreadyUsed(email)) {
return false
}
if (isEmailAlreadyUsed(email)) return false

registeredUsers[email.lowercase()] = password
return true
}


private fun getSharedPreferences(context: Context) =
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
fun isLoggedIn(context: Context): Boolean {
return getSharedPreferences(context).getBoolean(KEY_IS_LOGGED_IN, false)
}


fun setLoggedIn(context: Context, isLoggedIn: Boolean) {
getSharedPreferences(context).edit()
.putBoolean(KEY_IS_LOGGED_IN, isLoggedIn)
.apply()
}


fun saveUserCredentials(context: Context, email: String, password: String) {
getSharedPreferences(context).edit()
.putString(KEY_EMAIL, email)
.putString(KEY_PASSWORD, password)
.apply()
}

fun getUserCredentials(context: Context): Pair<String?, String?> {
val sharedPreferences = getSharedPreferences(context)
val email = sharedPreferences.getString(KEY_EMAIL, null)
val password = sharedPreferences.getString(KEY_PASSWORD, null)
return Pair(email, password)
}

fun validateLogin(email: String, password: String): Boolean {
return registeredUsers[email.lowercase()] == password
}
Expand All @@ -41,9 +73,6 @@ object CredentialsManager {
return isEmailValid(email) && isValidPassword(password)
}

fun isValidFullName(fullName: String): Boolean {
return fullName.isNotEmpty()
}

fun isHardcodedCredentials(email: String, password: String): Boolean {
val hardcodedEmail = "test@te.st"
Expand Down Expand Up @@ -71,6 +100,6 @@ object CredentialsManager {
isEmailValid(email) &&
isValidPhoneNumber(phoneNumber) &&
isValidPassword(password) &&
isTermsAccepted(isTermsAccepted)
isTermsAccepted
}
}
}
34 changes: 34 additions & 0 deletions app/src/main/java/com/example/assignment_3/LoginFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.assignment_3
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
class LoginFragment(private val credentialsManager: CredentialsManager) : Fragment() {
private var listener: EventsListener? = null
interface EventsListener {
fun onRegisterPressed()
}
override fun onAttach(context: Context) {
super.onAttach(context)
require(context is EventsListener) {
"Activity holding fragment must implement its EventsInterface"
}
listener = context
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_create_account, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.btnNext).setOnClickListener {
listener?.onRegisterPressed()
}
}
}
Loading