diff options
author | Isidro Henoch <imhenoch@protonmail.com> | 2021-12-06 01:04:55 -0600 |
---|---|---|
committer | Isidro Henoch <imhenoch@protonmail.com> | 2021-12-06 01:04:55 -0600 |
commit | 93c204bcd190b242f1dea49e52f28c795e4d0b92 (patch) | |
tree | 7fc0b2908afa4a63a1f144bc2d2718d91500333d | |
parent | e51f039b61b0a653b02f5d4d577bfe8f83286a16 (diff) | |
download | etbsa-trackermap-mobile-93c204bcd190b242f1dea49e52f28c795e4d0b92.tar.gz etbsa-trackermap-mobile-93c204bcd190b242f1dea49e52f28c795e4d0b92.tar.bz2 etbsa-trackermap-mobile-93c204bcd190b242f1dea49e52f28c795e4d0b92.zip |
WIP: Implements the Login functionality
- Adds multiple android dependencies, for DI and some utilities
- Updates colors and styles
- Adds an Application
- Adds the Login Fragment and ViewModel
11 files changed, 299 insertions, 6 deletions
diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index ccbc6c8..669b5cb 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -17,6 +17,9 @@ android { isMinifyEnabled = false } } + buildFeatures { + viewBinding = true + } } dependencies { @@ -25,5 +28,10 @@ dependencies { implementation("androidx.appcompat:appcompat:1.4.0") implementation("androidx.constraintlayout:constraintlayout:2.1.2") implementation("com.squareup.okhttp3:okhttp:3.14.2") + implementation("com.github.Zhuinden:live-event:1.2.0") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0") + implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.4.0") + implementation("io.insert-koin:koin-android:3.1.4") + implementation("androidx.core:core-ktx:1.7.0") implementation(group = "", name = "WhirlyGlobeMaply", ext = "aar") }
\ No newline at end of file diff --git a/androidApp/src/main/AndroidManifest.xml b/androidApp/src/main/AndroidManifest.xml index 3d1df5c..142700c 100644 --- a/androidApp/src/main/AndroidManifest.xml +++ b/androidApp/src/main/AndroidManifest.xml @@ -7,9 +7,10 @@ android:allowBackup="false" android:supportsRtl="true" android:theme="@style/AppTheme" - android:icon="@mipmap/ic_launcher"> + android:icon="@mipmap/ic_launcher" + android:name=".TrackerApp"> <activity - android:name=".MainActivity" + android:name=".session.LoginActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt new file mode 100644 index 0000000..a8efbf2 --- /dev/null +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt @@ -0,0 +1,30 @@ +package mx.trackermap.TrackerMap.android + +import android.app.Application +import mx.trackermap.TrackerMap.android.session.LoginViewModel +import mx.trackermap.TrackerMap.client.apis.SessionApi +import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidLogger +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.startKoin +import org.koin.core.logger.Level +import org.koin.dsl.module + +class TrackerApp: Application() { + override fun onCreate() { + super.onCreate() + + val appModule = module { + single { "https://etbsa.net/api/" } + single { SessionApi(get()) } + + viewModel { LoginViewModel(get(), get()) } + } + + startKoin { + androidLogger(Level.ERROR) + androidContext(this@TrackerApp) + modules(appModule) + } + } +}
\ No newline at end of file diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginActivity.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginActivity.kt new file mode 100644 index 0000000..3aec7b8 --- /dev/null +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginActivity.kt @@ -0,0 +1,14 @@ +package mx.trackermap.TrackerMap.android.session + +import android.os.Bundle +import android.os.PersistableBundle +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import mx.trackermap.TrackerMap.android.R + +class LoginActivity: AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.login_activity) + } +}
\ No newline at end of file diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginFragment.kt new file mode 100644 index 0000000..5039a7c --- /dev/null +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginFragment.kt @@ -0,0 +1,76 @@ +package mx.trackermap.TrackerMap.android.session + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.core.widget.doAfterTextChanged +import androidx.fragment.app.Fragment +import com.zhuinden.liveevent.observe +import mx.trackermap.TrackerMap.android.databinding.LoginBinding +import org.koin.androidx.viewmodel.ext.android.viewModel + +class LoginFragment : Fragment() { + + private var _binding: LoginBinding? = null + private val binding get() = _binding!! + private val loginViewModel: LoginViewModel by viewModel() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = LoginBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupEvents() + setupObservers() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + private fun setupEvents() { + binding.usernameEditText.doAfterTextChanged { + loginViewModel.email.value = it.toString() + } + binding.passwordEditText.doAfterTextChanged { + loginViewModel.password.value = it.toString() + } + binding.signinButton.setOnClickListener { + loginViewModel.login() + } + } + + private fun setupObservers() { + loginViewModel.loginResult.observe(this) { result -> + Log.d("LoginFragment", result.toString()) + when (result) { + LoginViewModel.LoginResult.Loading -> { + Toast.makeText(context, "Loading...", Toast.LENGTH_SHORT).show() + } + LoginViewModel.LoginResult.EmailMissing -> { + Toast.makeText(context, "Email is missing", Toast.LENGTH_SHORT).show() + } + LoginViewModel.LoginResult.PasswordMissing -> { + Toast.makeText(context, "Password is missing", Toast.LENGTH_SHORT).show() + } + LoginViewModel.LoginResult.Failure -> { + Toast.makeText(context, "Failed login", Toast.LENGTH_SHORT).show() + } + LoginViewModel.LoginResult.Success -> { + Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show() + } + } + } + } +}
\ No newline at end of file diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginViewModel.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginViewModel.kt new file mode 100644 index 0000000..9df78aa --- /dev/null +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/LoginViewModel.kt @@ -0,0 +1,57 @@ +package mx.trackermap.TrackerMap.android.session + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.zhuinden.eventemitter.EventEmitter +import com.zhuinden.eventemitter.EventSource +import kotlinx.coroutines.launch +import mx.trackermap.TrackerMap.client.apis.SessionApi + +class LoginViewModel( + private val sessionApi: SessionApi, + savedStateHandle: SavedStateHandle +) : ViewModel() { + + sealed class LoginResult { + object Loading: LoginResult() + object EmailMissing : LoginResult() + object PasswordMissing : LoginResult() + object Failure : LoginResult() + object Success : LoginResult() + } + + val email: MutableLiveData<String> = savedStateHandle.getLiveData("user", "") + val password: MutableLiveData<String> = savedStateHandle.getLiveData("password", "") + + private val loginResultEmitter = EventEmitter<LoginResult>() + val loginResult: EventSource<LoginResult> = loginResultEmitter + + fun login() { + val email = email.value!!.toString().trim() + val password = password.value!!.toString().trim() + + if (email.isEmpty()) { + loginResultEmitter.emit(LoginResult.EmailMissing) + return + } + + if (password.isEmpty()) { + loginResultEmitter.emit(LoginResult.PasswordMissing) + return + } + + loginResultEmitter.emit(LoginResult.Loading) + viewModelScope.launch { + try { + val user = sessionApi.sessionPost(email, password) + Log.d("LoginViewModel", user.toString()) + loginResultEmitter.emit(LoginResult.Success) + } catch (e: Exception) { + loginResultEmitter.emit(LoginResult.Failure) + } + } + } +}
\ No newline at end of file diff --git a/androidApp/src/main/res/layout/login.xml b/androidApp/src/main/res/layout/login.xml new file mode 100644 index 0000000..0a5f07a --- /dev/null +++ b/androidApp/src/main/res/layout/login.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.cardview.widget.CardView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:name="mx.trackermap.TrackerMap.android.session.LoginFragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:cardCornerRadius="20dp" + app:cardElevation="5dp" + app:cardUseCompatPadding="true"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingVertical="32dp" + android:paddingHorizontal="16dp"> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/usernameInputLayout" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="Username" + app:layout_constraintBottom_toTopOf="@+id/passwordInputLayout" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/usernameEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textEmailAddress"/> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.textfield.TextInputLayout + android:id="@+id/passwordInputLayout" + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="Password" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/usernameInputLayout" + app:layout_constraintBottom_toTopOf="@id/signinButton" + android:layout_marginTop="24dp"> + + <com.google.android.material.textfield.TextInputEditText + android:id="@+id/passwordEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textPassword"/> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.button.MaterialButton + android:id="@+id/signinButton" + android:layout_width="0dp" + android:layout_height="wrap_content" + app:layout_constraintWidth_percent="0.5" + app:layout_constraintTop_toBottomOf="@id/passwordInputLayout" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintHorizontal_bias="0.5" + android:layout_marginTop="40dp" + android:text="Log in"/> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</androidx.cardview.widget.CardView>
\ No newline at end of file diff --git a/androidApp/src/main/res/layout/login_activity.xml b/androidApp/src/main/res/layout/login_activity.xml new file mode 100644 index 0000000..f1df817 --- /dev/null +++ b/androidApp/src/main/res/layout/login_activity.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.appcompat.widget.AppCompatImageView + android:id="@+id/bannerImage" + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintWidth_percent="0.7" + app:layout_constraintDimensionRatio="1" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:srcCompat="@drawable/ic_launcher_foreground" /> + + <fragment + android:id="@+id/loginFragment" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:name="mx.trackermap.TrackerMap.android.session.LoginFragment" + app:layout_constraintTop_toBottomOf="@id/bannerImage" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" + android:layout_marginBottom="16dp"/> + +</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/androidApp/src/main/res/values/colors.xml b/androidApp/src/main/res/values/colors.xml index 4faecfa..8fb5f28 100644 --- a/androidApp/src/main/res/values/colors.xml +++ b/androidApp/src/main/res/values/colors.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <color name="colorPrimary">#6200EE</color> - <color name="colorPrimaryDark">#3700B3</color> - <color name="colorAccent">#03DAC5</color> + <color name="colorPrimary">#656A74</color> + <color name="colorPrimaryDark">#43474E</color> + <color name="colorAccent">#EB473E</color> </resources>
\ No newline at end of file diff --git a/androidApp/src/main/res/values/styles.xml b/androidApp/src/main/res/values/styles.xml index 1971a0a..4a51239 100644 --- a/androidApp/src/main/res/values/styles.xml +++ b/androidApp/src/main/res/values/styles.xml @@ -1,6 +1,6 @@ <resources> - <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> + <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> diff --git a/build.gradle.kts b/build.gradle.kts index 4602dde..411be83 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,6 +3,7 @@ buildscript { gradlePluginPortal() google() mavenCentral() + maven("https://jitpack.io") } dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0") @@ -15,6 +16,7 @@ allprojects { repositories { google() mavenCentral() + maven("https://jitpack.io") flatDir { dirs("libs") } |