aboutsummaryrefslogtreecommitdiff
path: root/androidApp
diff options
context:
space:
mode:
authorIsidro Henoch <imhenoch@protonmail.com>2022-01-12 18:10:01 -0600
committerIsidro Henoch <imhenoch@protonmail.com>2022-01-12 18:10:01 -0600
commit9a125dd2ca5144ae49761b73564871bb0b38c0b7 (patch)
tree2f64529e1be83c896a47774876ea1bd514f1c719 /androidApp
parentb9a9eeeb9f104b6fe11a5bc523cad189b293160c (diff)
parent270e54f2d83a962a33646c47917d8ea00a282bd9 (diff)
downloadetbsa-trackermap-mobile-9a125dd2ca5144ae49761b73564871bb0b38c0b7.tar.gz
etbsa-trackermap-mobile-9a125dd2ca5144ae49761b73564871bb0b38c0b7.tar.bz2
etbsa-trackermap-mobile-9a125dd2ca5144ae49761b73564871bb0b38c0b7.zip
Merge branch 'user_information'
Diffstat (limited to 'androidApp')
-rw-r--r--androidApp/src/main/AndroidManifest.xml3
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt20
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt21
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt28
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationActivity.kt78
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationViewModel.kt44
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitFragment.kt8
-rw-r--r--androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt39
-rw-r--r--androidApp/src/main/res/layout/units_activity.xml135
-rw-r--r--androidApp/src/main/res/layout/user_information_activity.xml156
-rw-r--r--androidApp/src/main/res/menu/navigation_menu.xml26
-rw-r--r--androidApp/src/main/res/values/dimen.xml3
-rw-r--r--androidApp/src/main/res/values/strings.xml8
13 files changed, 424 insertions, 145 deletions
diff --git a/androidApp/src/main/AndroidManifest.xml b/androidApp/src/main/AndroidManifest.xml
index 5d56847..6501532 100644
--- a/androidApp/src/main/AndroidManifest.xml
+++ b/androidApp/src/main/AndroidManifest.xml
@@ -26,5 +26,8 @@
<activity
android:name=".details.DetailsActivity"
android:exported="false"/>
+ <activity
+ android:name=".session.UserInformationActivity"
+ android:exported="false"/>
</application>
</manifest> \ No newline at end of file
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt
index 1563534..cdb7102 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/TrackerApp.kt
@@ -6,6 +6,7 @@ import mx.trackermap.TrackerMap.android.details.commands.UnitCommandsViewModel
import mx.trackermap.TrackerMap.android.details.information.UnitInformationViewModel
import mx.trackermap.TrackerMap.android.details.reports.UnitReportsViewModel
import mx.trackermap.TrackerMap.android.session.LoginViewModel
+import mx.trackermap.TrackerMap.android.session.UserInformationViewModel
import mx.trackermap.TrackerMap.android.units.UnitsViewModel
import mx.trackermap.TrackerMap.client.apis.*
import mx.trackermap.TrackerMap.controllers.GeofencesController
@@ -25,21 +26,22 @@ class TrackerApp : Application() {
val appModule = module {
single { "https://etbsa.net/api" }
- single { SessionApi(get()) }
- single { DevicesApi(get()) }
- single { PositionsApi(get()) }
- single { CommandsApi(get()) }
- single { ReportsApi(get()) }
- single { GeofencesApi(get()) }
+ factory { SessionApi(get()) }
+ factory { DevicesApi(get()) }
+ factory { PositionsApi(get()) }
+ factory { CommandsApi(get()) }
+ factory { ReportsApi(get()) }
+ factory { GeofencesApi(get()) }
- single { UnitsController(get(), get()) }
- single { GeofencesController(get()) }
+ factory { UnitsController(get(), get()) }
+ factory { GeofencesController(get()) }
viewModel { LoginViewModel(get(), get()) }
viewModel { UnitInformationViewModel(get()) }
viewModel { UnitCommandsViewModel(get()) }
- single { UnitsViewModel(get()) }
+ viewModel { UnitsViewModel(get()) }
viewModel { UnitReportsViewModel(get(), get()) }
+ viewModel { UserInformationViewModel(get()) }
}
startKoin {
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt
index bd3ab67..6bee413 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesFragment.kt
@@ -11,18 +11,17 @@ import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.DelicateCoroutinesApi
import mx.trackermap.TrackerMap.android.databinding.DevicesFragmentBinding
import mx.trackermap.TrackerMap.android.details.DetailsActivity
+import mx.trackermap.TrackerMap.android.units.UnitFragment
import mx.trackermap.TrackerMap.android.units.UnitsViewModel
import mx.trackermap.TrackerMap.client.models.UnitInformation
import org.koin.androidx.viewmodel.ext.android.viewModel
@DelicateCoroutinesApi
-class DevicesFragment : Fragment() {
+class DevicesFragment(private val unitsViewModel: UnitsViewModel) : UnitFragment(unitsViewModel) {
private var _binding: DevicesFragmentBinding? = null
private val binding get() = _binding!!
- private val unitsViewModel: UnitsViewModel by viewModel()
-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -42,9 +41,20 @@ class DevicesFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
setupList()
+ }
+
+ override fun onResume() {
+ super.onResume()
+
setupObservers()
}
+ override fun onPause() {
+ super.onPause()
+
+ removeObservers()
+ }
+
private fun setupList() {
binding.devicesList.layoutManager = LinearLayoutManager(
context, LinearLayoutManager.VERTICAL,
@@ -65,6 +75,11 @@ class DevicesFragment : Fragment() {
}
}
+ private fun removeObservers() {
+ Log.d("DevicesFragment", "removeObservers()")
+ unitsViewModel.units.removeObservers(viewLifecycleOwner)
+ }
+
private fun itemAction(unit: UnitInformation, action: Action) {
when (action) {
Action.DETAILS, Action.REPORTS, Action.COMMANDS -> {
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt
index fc417a0..30e3cea 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/UnitMapFragment.kt
@@ -1,29 +1,23 @@
package mx.trackermap.TrackerMap.android.map
import android.content.Intent
-import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.fragment.app.Fragment
import kotlinx.coroutines.DelicateCoroutinesApi
import mx.trackermap.TrackerMap.android.R
import mx.trackermap.TrackerMap.android.databinding.UnitMapFragmentBinding
import mx.trackermap.TrackerMap.android.details.DetailsActivity
import mx.trackermap.TrackerMap.android.devices.Action
import mx.trackermap.TrackerMap.android.devices.UnitRenderData
+import mx.trackermap.TrackerMap.android.units.UnitFragment
import mx.trackermap.TrackerMap.android.units.UnitsViewModel
import mx.trackermap.TrackerMap.client.models.UnitInformation
-import mx.trackermap.TrackerMap.utils.Formatter
-import mx.trackermap.TrackerMap.utils.SpeedUnit
-import org.koin.androidx.viewmodel.ext.android.viewModel
@DelicateCoroutinesApi
-class UnitMapFragment : Fragment() {
-
- private val unitsViewModel: UnitsViewModel by viewModel()
+class UnitMapFragment(private val unitsViewModel: UnitsViewModel) : UnitFragment(unitsViewModel) {
private var _binding: UnitMapFragmentBinding? = null
private val binding get() = _binding!!
@@ -42,9 +36,20 @@ class UnitMapFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
initializeMap()
+ }
+
+ override fun onResume() {
+ super.onResume()
+
setupObservers()
}
+ override fun onPause() {
+ super.onPause()
+
+ removeObservers()
+ }
+
private fun initializeMap() {
unitsMapFragment = childFragmentManager.findFragmentById(R.id.unitsMap) as MapFragment
unitsMapFragment.markerCallback = unitsViewModel::selectUnitWith
@@ -93,6 +98,13 @@ class UnitMapFragment : Fragment() {
}
}
+ private fun removeObservers() {
+ Log.d("MapFragment", "removeObservers()")
+ unitsViewModel.units.removeObservers(viewLifecycleOwner)
+ unitsViewModel.selectedUnit.removeObservers(viewLifecycleOwner)
+ unitsViewModel.geofences.removeObservers(viewLifecycleOwner)
+ }
+
private fun itemAction(unit: UnitInformation, action: Action) {
when (action) {
Action.DETAILS, Action.REPORTS, Action.COMMANDS -> {
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationActivity.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationActivity.kt
new file mode 100644
index 0000000..da1c0d5
--- /dev/null
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationActivity.kt
@@ -0,0 +1,78 @@
+package mx.trackermap.TrackerMap.android.session
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import mx.trackermap.TrackerMap.android.databinding.UserInformationActivityBinding
+import mx.trackermap.TrackerMap.client.models.User
+import org.koin.androidx.viewmodel.ext.android.viewModel
+
+class UserInformationActivity : AppCompatActivity() {
+
+ private var _binding: UserInformationActivityBinding? = null
+ private val binding get() = _binding!!
+ private val userInformationViewModel: UserInformationViewModel by viewModel()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ _binding = UserInformationActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ initialize()
+ }
+
+ private fun initialize() {
+ setupObservers()
+ setupEvents()
+
+ userInformationViewModel.fetchUserInfo()
+ }
+
+ private fun setupObservers() {
+ userInformationViewModel.userInformation.observe(this) { userInformation ->
+ when (userInformation) {
+ UserInformationViewModel.InformationState.Loading -> setLoading(true)
+ UserInformationViewModel.InformationState.Failure -> failure()
+ is UserInformationViewModel.InformationState.Success -> display(userInformation.user)
+ UserInformationViewModel.InformationState.Signout -> signout()
+ }
+ }
+ }
+
+ private fun setupEvents() {
+ binding.signoutButton.setOnClickListener { userInformationViewModel.signout() }
+ }
+
+ private fun setLoading(isLoading: Boolean) {
+ binding.infoLoading.visibility = if (isLoading) View.VISIBLE else View.GONE
+ binding.userInfoCard.visibility = if (isLoading) View.GONE else View.VISIBLE
+ }
+
+ private fun failure() {
+ setLoading(false)
+
+ Toast.makeText(this, "Something went wrong...", Toast.LENGTH_LONG).show()
+ }
+
+ private fun display(user: User) {
+ setLoading(false)
+
+ binding.apply {
+ usernameInfo.text = user.name ?: ""
+ emailInfo.text = user.email ?: ""
+ idInfo.text = "${user.id ?: "--"}"
+ deviceLimitInfo.text = "${user.deviceLimit ?: "--"}"
+ adminInfo.text = "${user.administrator}"
+ }
+ }
+
+ private fun signout() {
+ val intent = Intent(applicationContext, LoginActivity::class.java)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ startActivity(intent)
+ finish()
+ }
+
+} \ No newline at end of file
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationViewModel.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationViewModel.kt
new file mode 100644
index 0000000..b2379fc
--- /dev/null
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationViewModel.kt
@@ -0,0 +1,44 @@
+package mx.trackermap.TrackerMap.android.session
+
+import android.util.Log
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
+import mx.trackermap.TrackerMap.client.apis.SessionApi
+import mx.trackermap.TrackerMap.client.models.User
+
+class UserInformationViewModel(private val sessionApi: SessionApi) : ViewModel() {
+
+ sealed class InformationState {
+ object Loading: InformationState()
+ object Failure: InformationState()
+ class Success(val user: User) : InformationState()
+ object Signout: InformationState()
+ }
+
+ var userInformation = MutableLiveData<InformationState>(InformationState.Loading)
+
+ init {
+ Log.d("UserInformationVM", "Initializing User Information View Model")
+ }
+
+ fun fetchUserInfo() {
+ viewModelScope.launch {
+ userInformation.postValue(InformationState.Loading)
+ try {
+ userInformation.postValue(InformationState.Success(sessionApi.sessionGet()))
+ } catch (e: Exception) {
+ userInformation.postValue(InformationState.Failure)
+ }
+ }
+ }
+
+ fun signout() {
+ viewModelScope.launch {
+ userInformation.postValue(InformationState.Loading)
+ sessionApi.sessionDelete()
+ userInformation.postValue(InformationState.Signout)
+ }
+ }
+} \ No newline at end of file
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitFragment.kt
new file mode 100644
index 0000000..ab3afc1
--- /dev/null
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitFragment.kt
@@ -0,0 +1,8 @@
+package mx.trackermap.TrackerMap.android.units
+
+import androidx.fragment.app.Fragment
+import kotlinx.coroutines.DelicateCoroutinesApi
+
+open class UnitFragment @DelicateCoroutinesApi constructor(
+ private val unitsViewModel: UnitsViewModel
+) : Fragment() \ No newline at end of file
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt
index 409919a..e198ce0 100644
--- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt
+++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/units/UnitsActivity.kt
@@ -1,5 +1,6 @@
package mx.trackermap.TrackerMap.android.units
+import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.Gravity
@@ -12,6 +13,8 @@ import mx.trackermap.TrackerMap.android.R
import mx.trackermap.TrackerMap.android.databinding.UnitsActivityBinding
import mx.trackermap.TrackerMap.android.devices.DevicesFragment
import mx.trackermap.TrackerMap.android.map.UnitMapFragment
+import mx.trackermap.TrackerMap.android.session.LoginActivity
+import mx.trackermap.TrackerMap.android.session.UserInformationActivity
import org.koin.androidx.viewmodel.ext.android.viewModel
@DelicateCoroutinesApi
@@ -21,6 +24,12 @@ class UnitsActivity : AppCompatActivity() {
private val binding get() = _binding!!
private val unitsViewModel: UnitsViewModel by viewModel()
+ private val mapFragment: UnitMapFragment by lazy {
+ UnitMapFragment(unitsViewModel)
+ }
+ private val devicesFragment: DevicesFragment by lazy {
+ DevicesFragment(unitsViewModel)
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -38,28 +47,9 @@ class UnitsActivity : AppCompatActivity() {
}
private fun setupEvents() {
- binding.drawerButton.setOnClickListener {
- binding.drawerLayout.openDrawer(binding.navigationView)
- }
- binding.navigationView.setNavigationItemSelectedListener {
- when (it.itemId) {
- R.id.nav_account -> {
- Toast.makeText(this, "Account button tapped!", Toast.LENGTH_SHORT).show()
- binding.drawerLayout.closeDrawers()
- false
- }
- R.id.nav_about -> {
- Toast.makeText(this, "About button tapped!", Toast.LENGTH_SHORT).show()
- binding.drawerLayout.closeDrawers()
- false
- }
- R.id.nav_logout -> {
- Toast.makeText(this, "Logout button tapped!", Toast.LENGTH_SHORT).show()
- binding.drawerLayout.closeDrawers()
- false
- }
- else -> false
- }
+ binding.userButton.setOnClickListener {
+ val intent = Intent(applicationContext, UserInformationActivity::class.java)
+ startActivity(intent)
}
binding.displayModeToggle.setOnClickListener {
unitsViewModel.toggleDisplayMode()
@@ -89,9 +79,8 @@ class UnitsActivity : AppCompatActivity() {
val newFragment =
when (displayMode) {
- UnitsViewModel.UnitsDisplayMode.LIST -> DevicesFragment()
- UnitsViewModel.UnitsDisplayMode.MAP -> UnitMapFragment()
- else -> DevicesFragment()
+ UnitsViewModel.UnitsDisplayMode.LIST -> devicesFragment
+ UnitsViewModel.UnitsDisplayMode.MAP -> mapFragment
}
supportFragmentManager.commit {
replace(R.id.displayContainer, newFragment)
diff --git a/androidApp/src/main/res/layout/units_activity.xml b/androidApp/src/main/res/layout/units_activity.xml
index fb39ebe..bc8d94a 100644
--- a/androidApp/src/main/res/layout/units_activity.xml
+++ b/androidApp/src/main/res/layout/units_activity.xml
@@ -1,87 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.drawerlayout.widget.DrawerLayout
+<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:openDrawer="start">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <FrameLayout
- android:id="@+id/displayContainer"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_marginTop="@dimen/fab_margin"
- app:layout_constraintTop_toBottomOf="@id/displayModeToggle"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"/>
+ android:layout_height="match_parent">
- <com.google.android.material.floatingactionbutton.FloatingActionButton
- android:id="@+id/drawerButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- android:backgroundTint="@android:color/white"
- app:borderWidth="0dp"
- app:fabSize="mini"
- android:layout_marginStart="@dimen/fab_margin"
- android:layout_marginTop="@dimen/fab_margin"
- app:elevation="@dimen/fab_elevation"
- android:src="@drawable/icon_menu"
- android:contentDescription="@string/open_drawer"/>
+ <FrameLayout
+ android:id="@+id/displayContainer"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginTop="@dimen/fab_margin"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/displayModeToggle" />
- <com.google.android.material.card.MaterialCardView
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintTop_toTopOf="@id/displayModeToggle"
- app:layout_constraintStart_toEndOf="@id/drawerButton"
- app:layout_constraintEnd_toStartOf="@id/displayModeToggle"
- app:layout_constraintBottom_toBottomOf="@id/displayModeToggle"
- android:layout_marginVertical="@dimen/search_vertical_margin"
- android:layout_marginHorizontal="@dimen/search_horizontal_margin"
- app:cardCornerRadius="@dimen/card_border_radius"
- app:cardElevation="@dimen/card_elevation">
-
- <com.google.android.material.textfield.TextInputEditText
- android:id="@+id/searchInput"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:hint="@string/units_search"
- android:paddingHorizontal="16dp"
- android:background="@null"
- android:inputType="text"
- android:lines="1"
- android:imeOptions="actionSearch" />
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/userButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/fab_margin"
+ android:layout_marginTop="@dimen/fab_margin"
+ android:backgroundTint="@android:color/white"
+ android:contentDescription="@string/open_drawer"
+ android:src="@drawable/device_contact"
+ app:borderWidth="0dp"
+ app:elevation="@dimen/fab_elevation"
+ app:fabSize="mini"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
- </com.google.android.material.card.MaterialCardView>
+ <com.google.android.material.card.MaterialCardView
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginHorizontal="@dimen/search_horizontal_margin"
+ android:layout_marginVertical="@dimen/search_vertical_margin"
+ app:cardCornerRadius="@dimen/card_border_radius"
+ app:cardElevation="@dimen/card_elevation"
+ app:layout_constraintBottom_toBottomOf="@id/displayModeToggle"
+ app:layout_constraintEnd_toStartOf="@id/displayModeToggle"
+ app:layout_constraintStart_toEndOf="@id/userButton"
+ app:layout_constraintTop_toTopOf="@id/displayModeToggle">
- <com.google.android.material.floatingactionbutton.FloatingActionButton
- android:id="@+id/displayModeToggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- android:backgroundTint="@android:color/white"
- app:borderWidth="0dp"
- app:fabSize="mini"
- android:layout_marginEnd="@dimen/fab_margin"
- android:layout_marginTop="@dimen/fab_margin"
- app:elevation="@dimen/fab_elevation"
- tools:ignore="ContentDescription" />
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/searchInput"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@null"
+ android:hint="@string/units_search"
+ android:imeOptions="actionSearch"
+ android:inputType="text"
+ android:lines="1"
+ android:paddingHorizontal="16dp" />
- </androidx.constraintlayout.widget.ConstraintLayout>
+ </com.google.android.material.card.MaterialCardView>
- <com.google.android.material.navigation.NavigationView
- android:id="@+id/navigationView"
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/displayModeToggle"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="start"
- app:menu="@menu/navigation_menu" />
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/fab_margin"
+ android:layout_marginEnd="@dimen/fab_margin"
+ android:backgroundTint="@android:color/white"
+ app:borderWidth="0dp"
+ app:elevation="@dimen/fab_elevation"
+ app:fabSize="mini"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:ignore="ContentDescription" />
-</androidx.drawerlayout.widget.DrawerLayout> \ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/androidApp/src/main/res/layout/user_information_activity.xml b/androidApp/src/main/res/layout/user_information_activity.xml
new file mode 100644
index 0000000..8bb994a
--- /dev/null
+++ b/androidApp/src/main/res/layout/user_information_activity.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ProgressBar
+ android:id="@+id/infoLoading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:visibility="gone"/>
+
+ <androidx.cardview.widget.CardView
+ android:id="@+id/userInfoCard"
+ android:layout_margin="@dimen/card_margin"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:contentPadding="@dimen/card_padding"
+ app:cardCornerRadius="@dimen/card_border_radius"
+ app:cardElevation="@dimen/card_elevation">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/usernameLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/username"
+ app:layout_constraintBottom_toTopOf="@id/usernameInfo"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_chainStyle="spread_inside" />
+
+ <TextView
+ android:id="@+id/usernameInfo"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toTopOf="@id/emailLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/usernameLabel"
+ tools:text="Username" />
+
+ <TextView
+ android:id="@+id/emailLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/fields_spacing"
+ android:text="@string/email"
+ app:layout_constraintBottom_toTopOf="@id/emailInfo"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/usernameInfo" />
+
+ <TextView
+ android:id="@+id/emailInfo"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toTopOf="@id/idLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/emailLabel"
+ tools:text="Email" />
+
+ <TextView
+ android:id="@+id/idLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/fields_spacing"
+ android:text="@string/unique_id"
+ app:layout_constraintBottom_toTopOf="@id/idInfo"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/emailInfo" />
+
+ <TextView
+ android:id="@+id/idInfo"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toTopOf="@id/deviceLimitLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/idLabel"
+ tools:text="Unique ID" />
+
+ <TextView
+ android:id="@+id/deviceLimitLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/fields_spacing"
+ android:text="@string/device_limit"
+ app:layout_constraintBottom_toTopOf="@id/deviceLimitInfo"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/idInfo" />
+
+ <TextView
+ android:id="@+id/deviceLimitInfo"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toTopOf="@id/adminLabel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/deviceLimitLabel"
+ tools:text="Device Limit" />
+
+ <TextView
+ android:id="@+id/adminLabel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/fields_spacing"
+ android:text="@string/admin"
+ app:layout_constraintBottom_toTopOf="@id/adminInfo"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/deviceLimitInfo" />
+
+ <TextView
+ android:id="@+id/adminInfo"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toTopOf="@id/signoutButton"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/adminLabel"
+ tools:text="Admin" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/signoutButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/fields_spacing"
+ android:text="@string/sign_out"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/adminInfo" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ </androidx.cardview.widget.CardView>
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/androidApp/src/main/res/menu/navigation_menu.xml b/androidApp/src/main/res/menu/navigation_menu.xml
deleted file mode 100644
index 2713776..0000000
--- a/androidApp/src/main/res/menu/navigation_menu.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-
- <group
- android:id="@+id/group_1"
- android:checkableBehavior="single">
- <item
- android:id="@+id/nav_account"
- android:icon="@drawable/device_contact"
- android:title="@string/menu_account" />
- <item
- android:id="@+id/nav_about"
- android:icon="@drawable/icon_about"
- android:title="@string/menu_about" />
- </group>
-
- <group
- android:id="@+id/group_2"
- android:checkableBehavior="single">
- <item
- android:id="@+id/nav_logout"
- android:icon="@drawable/icon_logout"
- android:title="@string/menu_logout" />
- </group>
-
-</menu> \ No newline at end of file
diff --git a/androidApp/src/main/res/values/dimen.xml b/androidApp/src/main/res/values/dimen.xml
index 8acc9a3..25d0e98 100644
--- a/androidApp/src/main/res/values/dimen.xml
+++ b/androidApp/src/main/res/values/dimen.xml
@@ -20,4 +20,7 @@
<!-- Floating Button -->
<dimen name="fab_margin">12dp</dimen>
<dimen name="fab_elevation">8dp</dimen>
+
+ <!-- User Information -->
+ <dimen name="fields_spacing">8dp</dimen>
</resources> \ No newline at end of file
diff --git a/androidApp/src/main/res/values/strings.xml b/androidApp/src/main/res/values/strings.xml
index 13ac79d..6901a37 100644
--- a/androidApp/src/main/res/values/strings.xml
+++ b/androidApp/src/main/res/values/strings.xml
@@ -86,4 +86,12 @@
<string name="event_text_message">Text message received</string>
<string name="event_driver_changed">Driver changed</string>
<string name="event_unknown">Unknown event</string>
+
+ <!-- User Information -->
+ <string name="username">Username</string>
+ <string name="email">Email</string>
+ <string name="unique_id">Unique ID</string>
+ <string name="device_limit">Device Limit</string>
+ <string name="admin">Administrator</string>
+ <string name="sign_out">Sign out</string>
</resources>