diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 78de2557497a01a043cb464aff90edf89a953785..591428e16423cfd5eea6981d8c22dd7293fa8c37 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,6 +48,8 @@ dependencies { implementation(libs.androidx.lifecycle.viewmodel.ktx) implementation(libs.androidx.navigation.fragment.ktx) implementation(libs.androidx.navigation.ui.ktx) + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 052318c3097994f2fb30c25f346ff1cc2191dd88..3c98a8ba53033802c3db9594a1fabe427c682126 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <application android:allowBackup="true" diff --git a/app/src/main/java/com/example/myapplication/LoginActivity.kt b/app/src/main/java/com/example/myapplication/LoginActivity.kt index ba57925739990dccf234953d456cb97801766a05..9776f0c5ff177f86c5630fa15c62aa1209c9d74e 100644 --- a/app/src/main/java/com/example/myapplication/LoginActivity.kt +++ b/app/src/main/java/com/example/myapplication/LoginActivity.kt @@ -1,6 +1,7 @@ package com.example.myapplication import android.os.Bundle +import android.util.Log import android.widget.Button import com.google.android.material.bottomnavigation.BottomNavigationView import androidx.appcompat.app.AppCompatActivity @@ -10,10 +11,15 @@ import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.example.myapplication.databinding.ActivityLoginBinding import com.example.myapplication.databinding.ActivityMainBinding +import com.example.myapplication.repository.AuthRepository +import com.example.myapplication.ui.login.UserViewModel +import com.example.myapplication.util.LoginListener -class LoginActivity : AppCompatActivity() { +class LoginActivity : AppCompatActivity() , LoginListener { private lateinit var binding: ActivityLoginBinding + private var userViewModel : UserViewModel = UserViewModel() + private var authRepository : AuthRepository = AuthRepository(this) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,9 +36,20 @@ class LoginActivity : AppCompatActivity() { val loginButton : Button = binding.loginButton loginButton.setOnClickListener { - finish() + authRepository.loginRequest(binding.emailInput.text.toString(), binding.passwordInput.text.toString()) + Log.d("Development", "Activity: Login request sent") } } + override fun onLoginSuccess() { + userViewModel.setUser(binding.emailInput.text.toString(), binding.passwordInput.text.toString()) + Log.d("Development", "Activity: Login success") + finish() + } + + override fun onLoginFailure() { + Log.d("Development", "Activity: Login failed") + } + } \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/MainActivity.kt b/app/src/main/java/com/example/myapplication/MainActivity.kt index d33287594b50f36f6aafb938ed4d896c2b0714c2..4d6ef5da340dda102514f278d9206df3c9dda050 100644 --- a/app/src/main/java/com/example/myapplication/MainActivity.kt +++ b/app/src/main/java/com/example/myapplication/MainActivity.kt @@ -1,7 +1,12 @@ package com.example.myapplication +import android.content.Context import android.content.Intent +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.net.NetworkInfo import android.os.Bundle +import android.util.Log import com.google.android.material.bottomnavigation.BottomNavigationView import androidx.appcompat.app.AppCompatActivity import androidx.navigation.findNavController @@ -33,12 +38,23 @@ class MainActivity : AppCompatActivity() { setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) + val isOnline : String = if (isOnline()) "Online" else "Offline" + Log.i("Development", "Online Connectivity Status: $isOnline") - val loginIntent : Intent = Intent(this, LoginActivity::class.java) + + val loginIntent = Intent(this, LoginActivity::class.java) startActivity(loginIntent) } override fun onStart() { super.onStart() } + + private fun isOnline(): Boolean { + val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val network = connectivityManager.activeNetwork ?: return false + val networkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: return false + return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && + networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/backendconnect/BackendService.kt b/app/src/main/java/com/example/myapplication/backendconnect/BackendService.kt new file mode 100644 index 0000000000000000000000000000000000000000..f759e9c8b97fa53b1e6b02ceb0937b0daa5d2d1f --- /dev/null +++ b/app/src/main/java/com/example/myapplication/backendconnect/BackendService.kt @@ -0,0 +1,19 @@ +package com.example.myapplication.backendconnect + +import com.example.myapplication.model.auth.Token +import com.example.myapplication.model.auth.UserCred +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.POST +import java.net.PasswordAuthentication + +interface BackendService { + @POST("auth/login") + fun login(@Body userCred: UserCred): Call<Token> + + @POST("auth/token") + fun tokenCheck(@Body token: Token): Call<Token> + +// @POST("bill/upload") +// fun uploadBill(@Body bill: Bill): Call<BillResponse> +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/backendconnect/Client.kt b/app/src/main/java/com/example/myapplication/backendconnect/Client.kt new file mode 100644 index 0000000000000000000000000000000000000000..704dcfa3b7c20d005f94be3051ce1f438bf2be09 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/backendconnect/Client.kt @@ -0,0 +1,16 @@ +package com.example.myapplication.backendconnect + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +object Client { + private const val BASE_URL = "https://pbd-backend-2024.vercel.app/api/" + + val connect : BackendService by lazy { + val retrofit = Retrofit.Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + + retrofit.create(BackendService::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/model/auth/Token.kt b/app/src/main/java/com/example/myapplication/model/auth/Token.kt new file mode 100644 index 0000000000000000000000000000000000000000..7fcdd2e724bac0b2f1f76235fbb9b5483de520d5 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/model/auth/Token.kt @@ -0,0 +1,8 @@ +package com.example.myapplication.model.auth + +import com.google.gson.annotations.SerializedName + +data class Token ( + @SerializedName("token") + val token: String +) \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/model/auth/UserCred.kt b/app/src/main/java/com/example/myapplication/model/auth/UserCred.kt new file mode 100644 index 0000000000000000000000000000000000000000..c46eb7c1d95418954d00efb8464c9b49f265f63d --- /dev/null +++ b/app/src/main/java/com/example/myapplication/model/auth/UserCred.kt @@ -0,0 +1,10 @@ +package com.example.myapplication.model.auth + +import com.google.gson.annotations.SerializedName + +data class UserCred ( + @SerializedName("email") + val email: String, + @SerializedName("password") + val password: String + ) \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/repository/AuthRepository.kt b/app/src/main/java/com/example/myapplication/repository/AuthRepository.kt new file mode 100644 index 0000000000000000000000000000000000000000..12787498a5ab0fc15a61414f1cc26d99c4b0201d --- /dev/null +++ b/app/src/main/java/com/example/myapplication/repository/AuthRepository.kt @@ -0,0 +1,40 @@ +package com.example.myapplication.repository + +import android.util.Log +import com.example.myapplication.backendconnect.Client +import com.example.myapplication.model.auth.Token +import com.example.myapplication.model.auth.UserCred +import com.example.myapplication.util.LoginListener +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + +class AuthRepository (private val loginListener: LoginListener) { + + fun loginRequest(email: String, password: String){ + Log.d("Development", "Login request to backend service") + Client.connect.login(UserCred(email, password)).enqueue( + object : Callback<Token> { + override fun onResponse(call: Call<Token>, response: Response<Token>) { + Log.d("Development", "Response: ${response.body()}") + if (response.isSuccessful) { + val token = response.body() + Log.d("Development", "Successful Login\nToken: ${token?.token}") + loginListener.onLoginSuccess() + // TODO: Save token to shared preferences + } else { + Log.d("Development", "LOGIN FAILED, http code : ${response.code()}") + // Handle error + loginListener.onLoginFailure() + } + } + + override fun onFailure(call: Call<Token>, t: Throwable) { + Log.d("Development", "LOGIN FAILED, error on delivery : ${t.message}") + // Handle error + loginListener.onLoginFailure() + } + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/ui/login/UserViewModel.kt b/app/src/main/java/com/example/myapplication/ui/login/UserViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..f1d90ec8a86e10665cf6fcaafc4dfafa1e5764e2 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/ui/login/UserViewModel.kt @@ -0,0 +1,21 @@ +package com.example.myapplication.ui.login + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.ViewModel +import com.example.myapplication.repository.AuthRepository +import com.example.myapplication.util.LoginListener + +class UserViewModel() : ViewModel(){ + var email: String = "" + var password: String = "" + var loginSuccesful: Boolean = false + + + fun setUser(email: String, password: String){ + this.email = email + this.password = password + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/util/LoginListener.kt b/app/src/main/java/com/example/myapplication/util/LoginListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..f04384f5de4b54153dbab28d119dec1ae5df3e1a --- /dev/null +++ b/app/src/main/java/com/example/myapplication/util/LoginListener.kt @@ -0,0 +1,6 @@ +package com.example.myapplication.util + +interface LoginListener { + fun onLoginSuccess() + fun onLoginFailure() +} \ No newline at end of file diff --git a/app/src/main/res/drawable/login_cursor.xml b/app/src/main/res/drawable/login_cursor.xml new file mode 100644 index 0000000000000000000000000000000000000000..b62e07e6eaafe40fdeb6f04a127e0fdc976d08c4 --- /dev/null +++ b/app/src/main/res/drawable/login_cursor.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <size android:width="2dp" /> + <solid android:color="?attr/colorOnSecondary" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_rectangle.xml b/app/src/main/res/drawable/rounded_rectangle.xml index 1008bc013a1fe66b65d41d26babd13471dcf2cdf..11c13dc32f2debea7bd3511363272bba8f9863d7 100644 --- a/app/src/main/res/drawable/rounded_rectangle.xml +++ b/app/src/main/res/drawable/rounded_rectangle.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> - <solid android:color="@color/theme_red" /> + <solid android:color="?attr/colorSecondary" /> <corners android:radius="10dp" /> </shape> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 95be77f44fa099d147ca630460eb83a6da39c6dc..e97cc7b369e479338e3adba1ad531dd8e8335685 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -21,6 +21,8 @@ android:layout_height="wrap_content" android:autofillHints="emailAddress" android:inputType="textEmailAddress" + android:label="@string/email_hint" + android:textCursorDrawable="@drawable/login_cursor" android:hint="@string/email_hint" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -33,6 +35,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:autofillHints="password" + android:label="@string/password_hint" + android:textCursorDrawable="@drawable/login_cursor" android:hint="@string/password_hint" android:inputType="textPassword" app:layout_constraintEnd_toEndOf="parent"