diff options
author | Iván Ávalos <avalos@disroot.org> | 2022-01-16 18:21:12 -0600 |
---|---|---|
committer | Iván Ávalos <avalos@disroot.org> | 2022-01-16 18:21:12 -0600 |
commit | c7b28c25b032a1b82b782ef5ff8dd5e703d5a8ad (patch) | |
tree | 4095a6c4c64442277081e58fff72829ac01c7d11 | |
parent | f47c9f6b62dd1949cd2f926348a7e057c3ae221c (diff) | |
parent | 21e16e27f047053582d8b0c722feedf3c8badebe (diff) | |
download | etbsa-trackermap-mobile-c7b28c25b032a1b82b782ef5ff8dd5e703d5a8ad.tar.gz etbsa-trackermap-mobile-c7b28c25b032a1b82b782ef5ff8dd5e703d5a8ad.tar.bz2 etbsa-trackermap-mobile-c7b28c25b032a1b82b782ef5ff8dd5e703d5a8ad.zip |
Merge branch 'main' of https://git.sr.ht/~avalos/trackermap-mobile
26 files changed, 316 insertions, 102 deletions
diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/DetailsActivity.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/DetailsActivity.kt index f66a760..c6d260b 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/DetailsActivity.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/DetailsActivity.kt @@ -12,7 +12,7 @@ import com.google.android.material.tabs.TabLayoutMediator import kotlinx.coroutines.DelicateCoroutinesApi import mx.trackermap.TrackerMap.android.R import mx.trackermap.TrackerMap.android.databinding.DetailsActivityBinding -import mx.trackermap.TrackerMap.android.devices.Action +import mx.trackermap.TrackerMap.android.shared.UnitRenderData @DelicateCoroutinesApi class DetailsActivity : AppCompatActivity() { @@ -47,7 +47,7 @@ class DetailsActivity : AppCompatActivity() { private fun initialize() { deviceId = intent.getIntExtra(DEVICE_ID_EXTRA, 0) deviceName = intent.getStringExtra(DEVICE_NAME_EXTRA) ?: "" - val initialSection = intent.getSerializableExtra(ACTION_EXTRA) as Action + val initialSection = intent.getSerializableExtra(ACTION_EXTRA) as UnitRenderData.Action Log.d("DetailsActivity", "Device ID - $deviceId") Log.d("DetailsActivity", "Initial Section - $initialSection") @@ -62,14 +62,14 @@ class DetailsActivity : AppCompatActivity() { }.attach() binding.detailsPager.setCurrentItem( when (initialSection) { - Action.DETAILS -> 0 - Action.REPORTS -> 1 + UnitRenderData.Action.DETAILS -> 0 + UnitRenderData.Action.REPORTS -> 1 else -> 2 }, false ) binding.detailsPager.isUserInputEnabled = when (initialSection) { - Action.DETAILS -> true - Action.REPORTS -> false + UnitRenderData.Action.DETAILS -> true + UnitRenderData.Action.REPORTS -> false else -> true } binding.detailsTabs.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener { @@ -84,6 +84,9 @@ class DetailsActivity : AppCompatActivity() { override fun onTabUnselected(tab: TabLayout.Tab?) {} override fun onTabReselected(tab: TabLayout.Tab?) {} }) + binding.closeButton.setOnClickListener { + finish() + } requestPermission {} } diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsFragment.kt index b56a403..822d351 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsFragment.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/commands/UnitCommandsFragment.kt @@ -75,7 +75,7 @@ class UnitCommandsFragment: Fragment() { setPositiveButton(R.string.shared_cancel) { dialogInterface, _ -> dialogInterface.dismiss() } - setNegativeButton(R.string.send_command) { dialogInterface, _ -> + setNegativeButton(R.string.shared_send) { dialogInterface, _ -> unitCommandsViewModel.sendCommand() dialogInterface.dismiss() } diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/information/UnitInformationFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/information/UnitInformationFragment.kt index 0c3577e..6c15ae4 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/information/UnitInformationFragment.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/information/UnitInformationFragment.kt @@ -13,6 +13,7 @@ import androidx.core.widget.TextViewCompat import androidx.fragment.app.Fragment import com.google.android.material.button.MaterialButton import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.serialization.json.longOrNull import mx.trackermap.TrackerMap.android.R import mx.trackermap.TrackerMap.android.databinding.UnitDetailsInformationBinding import mx.trackermap.TrackerMap.android.details.UnitDetailsAdapter @@ -94,6 +95,13 @@ class UnitInformationFragment : Fragment() { unit.position?.address?.let { address -> details.add(getString(R.string.unit_info_address) to address) } + unit.position?.attributes?.get("hours")?.longOrNull?.let { + if (it > 0) { + details.add( + getString(R.string.unit_hourmeter) to Formatter.formatHours(it) + ) + } + } unit.position?.protocol?.let { protocol -> details.add(getString(R.string.unit_info_protocol) to protocol) } diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt index 20d2a48..4c87b31 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsFragment.kt @@ -22,7 +22,7 @@ import mx.trackermap.TrackerMap.android.R import mx.trackermap.TrackerMap.android.databinding.UnitDetailsReportsBinding import mx.trackermap.TrackerMap.android.details.UnitDetailsAdapter import mx.trackermap.TrackerMap.android.map.MapFragment -import mx.trackermap.TrackerMap.android.map.MarkerTransformations +import mx.trackermap.TrackerMap.android.shared.MarkerTransformations import mx.trackermap.TrackerMap.client.models.EventInformation import mx.trackermap.TrackerMap.client.models.Position import mx.trackermap.TrackerMap.client.models.Stop @@ -205,26 +205,28 @@ class UnitReportsFragment : Fragment() { datetimeText.text = Formatter.formatDate(it) } event.event.type?.let { - eventText.text = getString(when (it) { - "deviceOnline" -> R.string.event_device_online - "deviceUnknown" -> R.string.event_device_unknown - "deviceOffline" -> R.string.event_device_offline - "deviceInactive" -> R.string.event_device_inactive - "deviceMoving" -> R.string.event_device_moving - "deviceStopped" -> R.string.event_device_stopped - "deviceOverspeed" -> R.string.event_device_overspeed - "deviceFuelDrop" -> R.string.event_device_fuel_drop - "commandResult" -> R.string.event_command_result - "geofenceEnter" -> R.string.event_geofence_enter - "geofenceExit" -> R.string.event_geofence_exit - "alarm" -> R.string.event_alarm - "ignitionOn" -> R.string.event_ignition_on - "ignitionOff" -> R.string.event_ignition_off - "maintenance" -> R.string.event_maintenance - "textMessage" -> R.string.event_text_message - "driverChanged" -> R.string.event_driver_changed - else -> R.string.event_unknown - }) + eventText.text = getString( + when (EventInformation.stringToReportType(it)) { + EventInformation.Type.DEVICE_ONLINE -> R.string.event_device_online + EventInformation.Type.DEVICE_UNKNOWN -> R.string.event_device_unknown + EventInformation.Type.DEVICE_OFFLINE -> R.string.event_device_offline + EventInformation.Type.DEVICE_INACTIVE -> R.string.event_device_inactive + EventInformation.Type.DEVICE_MOVING -> R.string.event_device_moving + EventInformation.Type.DEVICE_STOPPED -> R.string.event_device_stopped + EventInformation.Type.DEVICE_OVERSPEED -> R.string.event_device_overspeed + EventInformation.Type.DEVICE_FUEL_DROP -> R.string.event_device_fuel_drop + EventInformation.Type.COMMAND_RESULT -> R.string.event_command_result + EventInformation.Type.GEOFENCE_ENTER -> R.string.event_geofence_enter + EventInformation.Type.GEOFENCE_EXIT -> R.string.event_geofence_exit + EventInformation.Type.ALARM -> R.string.event_alarm + EventInformation.Type.IGNITION_ON -> R.string.event_ignition_on + EventInformation.Type.IGNITION_OFF -> R.string.event_ignition_off + EventInformation.Type.MAINTENANCE -> R.string.event_maintenance + EventInformation.Type.TEXT_MESSAGE -> R.string.event_text_message + EventInformation.Type.DRIVER_CHANGED -> R.string.event_driver_changed + EventInformation.Type.UNKNOWN -> R.string.event_unknown + else -> R.string.event_unknown + }) } event.geofence?.let { geofenceText.text = it.name diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsViewModel.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsViewModel.kt index 865f096..62ac4f2 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsViewModel.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/details/reports/UnitReportsViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.* import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch +import mx.trackermap.TrackerMap.client.models.EventInformation import mx.trackermap.TrackerMap.controllers.ReportController import mx.trackermap.TrackerMap.utils.ReportDates import org.koin.core.component.KoinComponent @@ -84,7 +85,24 @@ class UnitReportsViewModel( deviceId = id, reportType = _reportType.value, reportPeriod = _reportPeriod.value, - xlsx = xlsx + xlsx = xlsx, + eventTypes = arrayOf( + EventInformation.Type.DEVICE_INACTIVE, + EventInformation.Type.DEVICE_MOVING, + EventInformation.Type.DEVICE_STOPPED, + EventInformation.Type.DEVICE_OVERSPEED, + EventInformation.Type.DEVICE_FUEL_DROP, + EventInformation.Type.COMMAND_RESULT, + EventInformation.Type.GEOFENCE_ENTER, + EventInformation.Type.GEOFENCE_EXIT, + EventInformation.Type.ALARM, + EventInformation.Type.IGNITION_ON, + EventInformation.Type.IGNITION_OFF, + EventInformation.Type.MAINTENANCE, + EventInformation.Type.TEXT_MESSAGE, + EventInformation.Type.DRIVER_CHANGED, + EventInformation.Type.UNKNOWN + ) ) } } diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt index 344907c..b1854a9 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/DevicesAdapter.kt @@ -1,19 +1,15 @@ package mx.trackermap.TrackerMap.android.devices -import android.util.TypedValue import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.FrameLayout import androidx.core.view.updateLayoutParams import androidx.recyclerview.widget.RecyclerView import mx.trackermap.TrackerMap.android.R import mx.trackermap.TrackerMap.android.databinding.UnitItemBinding +import mx.trackermap.TrackerMap.android.shared.ActionCallback +import mx.trackermap.TrackerMap.android.shared.UnitRenderData import mx.trackermap.TrackerMap.client.models.UnitInformation -enum class Action { - CLICK, DETAILS, REPORTS, COMMANDS -} - class DevicesAdapter( private val units: List<UnitInformation>, private val actionCallback: ActionCallback? 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 96d4696..b1a3663 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 @@ -6,12 +6,11 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.ViewTreeObserver -import android.widget.Toast 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.shared.UnitRenderData import mx.trackermap.TrackerMap.android.units.UnitFragment import mx.trackermap.TrackerMap.android.units.UnitsViewModel import mx.trackermap.TrackerMap.client.models.UnitInformation @@ -82,9 +81,11 @@ class DevicesFragment(private val unitsViewModel: UnitsViewModel) : UnitFragment unitsViewModel.units.removeObservers(viewLifecycleOwner) } - private fun itemAction(unit: UnitInformation, action: Action) { + private fun itemAction(unit: UnitInformation, action: UnitRenderData.Action) { when (action) { - Action.DETAILS, Action.REPORTS, Action.COMMANDS -> { + UnitRenderData.Action.DETAILS, + UnitRenderData.Action.REPORTS, + UnitRenderData.Action.COMMANDS -> { Log.d("DevicesFragment", "Action: $action - Unit: $unit") val activity = requireActivity() val intent = Intent(activity.applicationContext, DetailsActivity::class.java) @@ -93,7 +94,7 @@ class DevicesFragment(private val unitsViewModel: UnitsViewModel) : UnitFragment intent.putExtra(DetailsActivity.ACTION_EXTRA, action) startActivity(intent) } - Action.CLICK -> { + UnitRenderData.Action.CLICK -> { unitsViewModel.selectUnit(unit) } } diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt index f577613..6a80f95 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MapFragment.kt @@ -17,6 +17,7 @@ import mil.nga.sf.util.SFException import mil.nga.sf.wkt.GeometryReader import java.io.File import mx.trackermap.TrackerMap.android.R +import mx.trackermap.TrackerMap.android.shared.MarkerTransformations import mx.trackermap.TrackerMap.client.models.Geofence import mx.trackermap.TrackerMap.client.models.MapLayer import mx.trackermap.TrackerMap.utils.MapCalculus @@ -65,7 +66,7 @@ class MapFragment : GlobeMapFragment() { val tmpInfo = RemoteTileInfoNew(layer[0], layer[1].toInt(), layer[2].toInt()) tileInfo = tileInfoSetCacheDir(layer[0], tmpInfo) tileInfo?.let { - setZoomLimits(it.minZoom, it.maxZoom) + setZoomLimits(layer[1].toInt(), layer[2].toInt()) } } @@ -81,9 +82,9 @@ class MapFragment : GlobeMapFragment() { loader = QuadImageLoader(params, tileInfo, baseControl) loader?.setImageFormat(RenderController.ImageFormat.MaplyImageUShort565) - val latitude = 23.191 - val longitude = -100.36 - focusOn(latitude, longitude, height = 0.4, animated = false) + val latitude = 23.191 * Math.PI / 180 + val longitude = -100.36 * Math.PI / 180 + mapControl.setPositionGeo(latitude, longitude, 0.4) } override fun mapDidStopMoving( @@ -92,7 +93,7 @@ class MapFragment : GlobeMapFragment() { userMotion: Boolean ) { super.mapDidStopMoving(mapControl, corners, userMotion) - Log.d("MapFragment", "Height: ${mapControl?.height}") + Log.d("MapFragment", "Height: %7.7f".format(mapControl?.height)) } override fun userDidSelect( @@ -235,9 +236,9 @@ class MapFragment : GlobeMapFragment() { } mbr.expandByFraction(0.1) - mapControl.addPostSurfaceRunnable { - val zoom = mapControl.zoomLimitMax.coerceAtLeast( - mapControl.findHeightToViewBounds(mbr, mbr.middle())) + mapControl?.addPostSurfaceRunnable { + val zoom = mapControl.findHeightToViewBounds(mbr, mbr.middle()) + .coerceAtLeast(mapControl.zoomLimitMin) mapControl.setPositionGeo(mbr.middle(), zoom) } } @@ -320,17 +321,22 @@ class MapFragment : GlobeMapFragment() { fun focusOn( latitude: Double, longitude: Double, - height: Double? = 0.00001, + height: Double = 0.00001, animated: Boolean = true ) { - val lat = latitude * Math.PI / 180 - val lon = longitude * Math.PI / 180 - // Ensure height is equal or higher than bottom limit - val z = mapControl.zoomLimitMin.coerceAtLeast(height ?: 0.0) - if (animated) { - mapControl.animatePositionGeo(lon, lat, z, 0.2) - } else { - mapControl.setPositionGeo(lon, lat, z) + mapControl?.addPostSurfaceRunnable { + val lat = latitude * Math.PI / 180 + val lon = longitude * Math.PI / 180 + // Ensure height is equal or higher than bottom limit + Log.d("MapFragment", "Target: %7.7f".format(height)) + Log.d("MapFragment", "Min: %7.7f".format(mapControl.zoomLimitMin)) + val z = height.coerceAtLeast(mapControl.zoomLimitMin) + Log.d("MapFragment", "Final: %7.7f".format(z)) + if (animated) { + mapControl.animatePositionGeo(lon, lat, z, 0.2) + } else { + mapControl.setPositionGeo(lon, lat, z) + } } } 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 6f6596f..6ea5f82 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 @@ -11,8 +11,8 @@ 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.shared.MarkerTransformations +import mx.trackermap.TrackerMap.android.shared.UnitRenderData import mx.trackermap.TrackerMap.android.units.UnitFragment import mx.trackermap.TrackerMap.android.units.UnitsViewModel import mx.trackermap.TrackerMap.client.models.UnitInformation @@ -117,10 +117,12 @@ class UnitMapFragment(private val unitsViewModel: UnitsViewModel) : UnitFragment unitsViewModel.geofences.removeObservers(viewLifecycleOwner) } - private fun itemAction(unit: UnitInformation, action: Action) { + private fun itemAction(unit: UnitInformation, action: UnitRenderData.Action) { when (action) { - Action.DETAILS, Action.REPORTS, Action.COMMANDS -> { - Log.d("DevicesFragment", "Action: $action - Unit: $unit") + UnitRenderData.Action.DETAILS, + UnitRenderData.Action.REPORTS, + UnitRenderData.Action.COMMANDS -> { + Log.d("UnitMapFragment", "Action: $action - Unit: $unit") val activity = requireActivity() val intent = Intent(activity.applicationContext, DetailsActivity::class.java) intent.putExtra(DetailsActivity.DEVICE_ID_EXTRA, unit.device.id) @@ -128,7 +130,7 @@ class UnitMapFragment(private val unitsViewModel: UnitsViewModel) : UnitFragment intent.putExtra(DetailsActivity.ACTION_EXTRA, action) startActivity(intent) } - Action.CLICK -> { + UnitRenderData.Action.CLICK -> { unitsViewModel.selectUnit(unit) } } 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 index b0a4482..13deed0 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationActivity.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/session/UserInformationActivity.kt @@ -69,7 +69,7 @@ class UserInformationActivity : AppCompatActivity() { } private fun setupEvents() { - binding.backButton.setOnClickListener { onBackPressed() } + binding.closeButton.setOnClickListener { onBackPressed() } binding.signoutButton.setOnClickListener { userInformationViewModel.signOut(PreferenceManager .getDefaultSharedPreferences(this) diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MarkerTransformations.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/MarkerTransformations.kt index 63dd9ed..f684a10 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/map/MarkerTransformations.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/MarkerTransformations.kt @@ -1,7 +1,8 @@ -package mx.trackermap.TrackerMap.android.map +package mx.trackermap.TrackerMap.android.shared import android.util.Log import mx.trackermap.TrackerMap.android.R +import mx.trackermap.TrackerMap.android.map.MapFragment import mx.trackermap.TrackerMap.client.models.Position import mx.trackermap.TrackerMap.client.models.Stop import mx.trackermap.TrackerMap.client.models.UnitInformation diff --git a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/UnitRenderData.kt b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/UnitRenderData.kt index beeba6f..e8a4bd6 100644 --- a/androidApp/src/main/java/mx/trackermap/TrackerMap/android/devices/UnitRenderData.kt +++ b/androidApp/src/main/java/mx/trackermap/TrackerMap/android/shared/UnitRenderData.kt @@ -1,4 +1,4 @@ -package mx.trackermap.TrackerMap.android.devices +package mx.trackermap.TrackerMap.android.shared import android.content.Context import android.graphics.Color @@ -12,13 +12,13 @@ import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.content.ContextCompat import com.zerobranch.layout.SwipeLayout +import kotlinx.serialization.json.longOrNull import mx.trackermap.TrackerMap.android.R -import mx.trackermap.TrackerMap.android.map.MarkerTransformations import mx.trackermap.TrackerMap.client.models.UnitInformation import mx.trackermap.TrackerMap.utils.Formatter import mx.trackermap.TrackerMap.utils.SpeedUnit -typealias ActionCallback = (unit: UnitInformation, action: Action) -> Unit +typealias ActionCallback = (unit: UnitInformation, action: UnitRenderData.Action) -> Unit class UnitRenderData { data class UnitRenderViewHolder( @@ -34,6 +34,10 @@ class UnitRenderData { val swipeLayout: SwipeLayout? = null ) + enum class Action { + CLICK, DETAILS, REPORTS, COMMANDS + } + companion object { fun render( viewHolder: UnitRenderViewHolder, @@ -128,6 +132,19 @@ class UnitRenderData { ) } + /* Hourmeter */ + position.attributes["hours"]?.longOrNull?.let { + if (it > 0) { + details.add( + Triple( + R.drawable.position_hourmeter, + Formatter.formatHours(it), + context.getString(R.string.unit_hourmeter) + ) + ) + } + } + /* Date time */ position.fixTime?.let { fixTime -> details.add( diff --git a/androidApp/src/main/res/drawable/icon_close.xml b/androidApp/src/main/res/drawable/icon_close.xml new file mode 100644 index 0000000..16d6d37 --- /dev/null +++ b/androidApp/src/main/res/drawable/icon_close.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> +</vector> diff --git a/androidApp/src/main/res/drawable/position_hourmeter.xml b/androidApp/src/main/res/drawable/position_hourmeter.xml new file mode 100644 index 0000000..52ff427 --- /dev/null +++ b/androidApp/src/main/res/drawable/position_hourmeter.xml @@ -0,0 +1,10 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14sp" + android:height="14sp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M15,1L9,1v2h6L15,1zM11,14h2L13,8h-2v6zM19.03,7.39l1.42,-1.42c-0.43,-0.51 -0.9,-0.99 -1.41,-1.41l-1.42,1.42C16.07,4.74 14.12,4 12,4c-4.97,0 -9,4.03 -9,9s4.02,9 9,9 9,-4.03 9,-9c0,-2.12 -0.74,-4.07 -1.97,-5.61zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/> +</vector> diff --git a/androidApp/src/main/res/layout/details_activity.xml b/androidApp/src/main/res/layout/details_activity.xml index f79ea69..37d3b15 100644 --- a/androidApp/src/main/res/layout/details_activity.xml +++ b/androidApp/src/main/res/layout/details_activity.xml @@ -5,13 +5,28 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/closeButton" + android:layout_width="wrap_content" + android:layout_height="0dp" + android:contentDescription="@string/shared_close" + android:src="@drawable/icon_close" + app:fabSize="mini" + app:backgroundTint="@android:color/white" + android:layout_margin="@dimen/fab_margin" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/detailsTabs"/> + <com.google.android.material.tabs.TabLayout android:id="@+id/detailsTabs" - android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_width="0dp" + android:layout_height="0dp" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toEndOf="@id/closeButton" + app:layout_constraintBottom_toTopOf="@id/detailsPager" + app:tabTextAppearance="@style/SmallTabText" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/detailsPager" @@ -20,6 +35,7 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/detailsTabs" /> + android:layout_marginTop="@dimen/fab_margin" + app:layout_constraintTop_toBottomOf="@id/closeButton" /> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/androidApp/src/main/res/layout/login.xml b/androidApp/src/main/res/layout/login.xml index 35c9410..7c79e5c 100644 --- a/androidApp/src/main/res/layout/login.xml +++ b/androidApp/src/main/res/layout/login.xml @@ -91,7 +91,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.5" - android:layout_marginTop="40dp" + android:layout_marginTop="24dp" android:text="@string/login_login"/> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/androidApp/src/main/res/layout/unit_map_fragment.xml b/androidApp/src/main/res/layout/unit_map_fragment.xml index 8395013..e2bee95 100644 --- a/androidApp/src/main/res/layout/unit_map_fragment.xml +++ b/androidApp/src/main/res/layout/unit_map_fragment.xml @@ -30,20 +30,25 @@ app:contentPaddingTop="@dimen/card_padding" app:contentPaddingLeft="@dimen/card_padding" app:contentPaddingRight="@dimen/card_padding" - android:visibility="gone"> + android:animateLayoutChanges="true" + android:visibility="gone" + tools:visibility="visible"> - <LinearLayout + <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/mainContent" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:animateLayoutChanges="true"> + android:orientation="vertical"> <LinearLayout - android:layout_width="match_parent" + android:id="@+id/titleLayout" + android:layout_width="0dp" android:layout_height="wrap_content" android:gravity="center_vertical" - android:orientation="horizontal"> + android:orientation="horizontal" + app:layout_constraintEnd_toStartOf="@+id/closeButton" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> <ImageView android:id="@+id/statusIcon" @@ -58,24 +63,36 @@ android:id="@+id/engineStopIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:visibility="gone" android:layout_marginEnd="5dp" android:src="@drawable/device_unlocked" + android:visibility="gone" tools:ignore="ContentDescription" /> <TextView android:id="@+id/unitName" + style="@style/TextAppearance.AppCompat.Body2" android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/TextAppearance.AppCompat.Body2" tools:text="1AAUTO" /> </LinearLayout> + <ImageView + android:id="@+id/closeButton" + android:layout_width="14sp" + android:layout_height="14sp" + android:contentDescription="@string/shared_close" + android:src="@drawable/icon_close" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + <GridLayout android:id="@+id/gridLayout" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_width="0dp" + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/titleLayout" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> <LinearLayout android:id="@+id/itemOptions" @@ -84,7 +101,11 @@ android:layout_marginVertical="@dimen/padding" android:gravity="center" android:orientation="horizontal" - android:visibility="visible"> + android:visibility="visible" + app:layout_constraintTop_toBottomOf="@id/gridLayout" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent"> <com.google.android.material.button.MaterialButton android:id="@+id/detailsButton" @@ -118,7 +139,7 @@ </LinearLayout> - </LinearLayout> + </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> diff --git a/androidApp/src/main/res/layout/user_information_activity.xml b/androidApp/src/main/res/layout/user_information_activity.xml index df0a59f..7dae0d5 100644 --- a/androidApp/src/main/res/layout/user_information_activity.xml +++ b/androidApp/src/main/res/layout/user_information_activity.xml @@ -7,13 +7,13 @@ android:layout_height="match_parent"> <com.google.android.material.floatingactionbutton.FloatingActionButton - android:id="@+id/backButton" + android:id="@+id/closeButton" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_margin="@dimen/fab_margin" android:backgroundTint="@android:color/white" - android:contentDescription="@string/open_profile" - android:src="@drawable/icon_back" + android:contentDescription="@string/shared_close" + android:src="@drawable/icon_close" app:borderWidth="0dp" app:elevation="@dimen/fab_elevation" app:fabSize="mini" @@ -24,7 +24,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:layout_marginTop="@dimen/fab_margin" - app:layout_constraintTop_toBottomOf="@id/backButton" + app:layout_constraintTop_toBottomOf="@id/closeButton" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent"> diff --git a/androidApp/src/main/res/values-es-rMX/strings.xml b/androidApp/src/main/res/values-es-rMX/strings.xml index 0806870..182656b 100644 --- a/androidApp/src/main/res/values-es-rMX/strings.xml +++ b/androidApp/src/main/res/values-es-rMX/strings.xml @@ -2,7 +2,9 @@ <resources> <!-- Shared strings --> <string name="shared_ok">OK</string> - <string name="shared_cancel">Cancel</string> + <string name="shared_cancel">Cancelar</string> + <string name="shared_close">Cerrar</string> + <string name="shared_send">Enviar</string> <!-- LoginActivity --> <string name="login_username">Nombre de usuario</string> @@ -31,6 +33,7 @@ <string name="unit_driver_name">Nombre del conductor</string> <string name="unit_speed">Velocidad</string> <string name="unit_last_address">Dirección de la última posición</string> + <string name="unit_hourmeter">Horómetro</string> <string name="unit_last_date">Fecha y hora de la última posición</string> <string name="unit_category_animal">Animal</string> @@ -75,7 +78,7 @@ <!-- Commands --> <string name="send_command">Enviar comando</string> <string name="send_command_confirmation_text"> - ¿Está seguro de que desea enviar el comando a la unidad %1$s? + El comando se enviará a la unidad %1$s. ¿Continuar? </string> <!-- Reports --> diff --git a/androidApp/src/main/res/values/strings.xml b/androidApp/src/main/res/values/strings.xml index 1cc1f10..1969a35 100644 --- a/androidApp/src/main/res/values/strings.xml +++ b/androidApp/src/main/res/values/strings.xml @@ -16,6 +16,8 @@ <!-- Shared strings --> <string name="shared_ok">OK</string> <string name="shared_cancel">Cancel</string> + <string name="shared_close">Close</string> + <string name="shared_send">Send</string> <!-- LoginActivity --> <string name="login_username">Username</string> @@ -44,6 +46,7 @@ <string name="unit_driver_name">Driver name</string> <string name="unit_speed">Speed</string> <string name="unit_last_address">Last position address</string> + <string name="unit_hourmeter">Hourmeter</string> <string name="unit_last_date">Last position datetime</string> <string name="unit_category_animal">Animal</string> @@ -88,7 +91,7 @@ <!-- Commands --> <string name="send_command">Send Command</string> <string name="send_command_confirmation_text"> - Are you sure you want to send the command to device %1$s? + Command will be sent to device %1$s. Continue? </string> <!-- Reports --> diff --git a/androidApp/src/main/res/values/styles.xml b/androidApp/src/main/res/values/styles.xml index 4a51239..dc40450 100644 --- a/androidApp/src/main/res/values/styles.xml +++ b/androidApp/src/main/res/values/styles.xml @@ -6,4 +6,10 @@ <item name="colorAccent">@color/colorAccent</item> </style> + <style name="SmallTabText" parent="Widget.MaterialComponents.TabLayout"> + <item name="textAllCaps">true</item> + <item name="android:textSize">11sp</item> + <item name="android:textStyle">bold</item> + </style> + </resources>
\ No newline at end of file diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt index b4d6f74..3765207 100644 --- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt +++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/apis/ReportsApi.kt @@ -36,12 +36,14 @@ class ReportsApi(basePath: String = "https://demo.traccar.org/api") : ApiClient( from: String, to: String, deviceId: Int, + type: String = "%", xlsx: Boolean = false ): Any { val localVariableQuery: MultiValueMap = mapOf( "deviceId" to toMultiValue(listOf(deviceId), "multi"), "from" to listOf(from), - "to" to listOf(to) + "to" to listOf(to), + "type" to listOf(type) ) val localVariableHeaders = mutableMapOf<String, String>() if (xlsx) { @@ -79,18 +81,20 @@ class ReportsApi(basePath: String = "https://demo.traccar.org/api") : ApiClient( suspend fun reportsEventsGet( from: String, to: String, + type: String = "%", deviceId: Int, ): Array<Event> { - return reportsEventsGetBase(from, to, deviceId, false) as Array<Event> + return reportsEventsGetBase(from, to, deviceId, type, false) as Array<Event> } @Suppress("UNCHECKED_CAST") suspend fun reportsEventsGetXlsx( from: String, to: String, + type: String = "%", deviceId: Int, ): ByteArray { - return reportsEventsGetBase(from, to, deviceId, true) as ByteArray + return reportsEventsGetBase(from, to, deviceId, type, true) as ByteArray } /** diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt index c4f91fe..befd8f1 100644 --- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt +++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/client/models/EventInformation.kt @@ -4,4 +4,81 @@ data class EventInformation( val event: Event, val position: Position?, val geofence: Geofence? -) +) { + enum class Type { + ALL, + DEVICE_ONLINE, + DEVICE_UNKNOWN, + DEVICE_OFFLINE, + DEVICE_INACTIVE, + DEVICE_MOVING, + DEVICE_STOPPED, + DEVICE_OVERSPEED, + DEVICE_FUEL_DROP, + COMMAND_RESULT, + GEOFENCE_ENTER, + GEOFENCE_EXIT, + ALARM, + IGNITION_ON, + IGNITION_OFF, + MAINTENANCE, + TEXT_MESSAGE, + DRIVER_CHANGED, + UNKNOWN + } + + companion object { + fun reportTypeToString(t: Type) = + when (t) { + Type.ALL -> "%" + Type.DEVICE_ONLINE -> "deviceOnline" + Type.DEVICE_UNKNOWN -> "deviceUnknown" + Type.DEVICE_OFFLINE -> "deviceOffline" + Type.DEVICE_INACTIVE -> "deviceInactive" + Type.DEVICE_MOVING -> "deviceMoving" + Type.DEVICE_STOPPED -> "deviceStopped" + Type.DEVICE_OVERSPEED -> "deviceOverspeed" + Type.DEVICE_FUEL_DROP -> "deviceFuelDrop" + Type.COMMAND_RESULT -> "commandResult" + Type.GEOFENCE_ENTER -> "geofenceEnter" + Type.GEOFENCE_EXIT -> "geofenceExit" + Type.ALARM -> "alarm" + Type.IGNITION_ON -> "ignitionOn" + Type.IGNITION_OFF -> "ignitionOff" + Type.MAINTENANCE -> "maintenance" + Type.TEXT_MESSAGE -> "textMessage" + Type.DRIVER_CHANGED -> "driverChanged" + Type.UNKNOWN -> "unknown" + } + + fun reportTypesToString(t: Array<Type>) = + if (t.isEmpty() || t.contains(Type.ALL)) { + reportTypeToString(Type.ALL) + } else { + t.joinToString(",", transform = this::reportTypeToString) + } + + fun stringToReportType(s: String) = + when (s) { + "deviceOnline" -> Type.DEVICE_ONLINE + "deviceUnknown" -> Type.DEVICE_UNKNOWN + "deviceOffline" -> Type.DEVICE_OFFLINE + "deviceInactive" -> Type.DEVICE_INACTIVE + "deviceMoving" -> Type.DEVICE_MOVING + "deviceStopped" -> Type.DEVICE_STOPPED + "deviceOverspeed" -> Type.DEVICE_OVERSPEED + "deviceFuelDrop" -> Type.DEVICE_FUEL_DROP + "commandResult" -> Type.COMMAND_RESULT + "geofenceEnter" -> Type.GEOFENCE_ENTER + "geofenceExit" -> Type.GEOFENCE_EXIT + "alarm" -> Type.ALARM + "ignitionOn" -> Type.IGNITION_ON + "ignitionOff" -> Type.IGNITION_OFF + "maintenance" -> Type.MAINTENANCE + "textMessage" -> Type.TEXT_MESSAGE + "driverChanged" -> Type.DRIVER_CHANGED + "unknown" -> Type.UNKNOWN + else -> Type.UNKNOWN + } + } +} diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt index 2151331..8a7f527 100644 --- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt +++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/controllers/ReportController.kt @@ -36,7 +36,8 @@ class ReportController( deviceId: Int, reportType: ReportType?, reportPeriod: ReportDates.ReportPeriod?, - xlsx: Boolean = false + xlsx: Boolean = false, + eventTypes: Array<EventInformation.Type> = arrayOf() ) { if (reportType == null || reportPeriod == null) { return @@ -54,7 +55,7 @@ class ReportController( GlobalScope.launch { when (reportType) { ReportType.POSITIONS -> fetchPositions(deviceId, previousDate, currentDate, xlsx) - ReportType.EVENTS -> fetchEvents(deviceId, previousDate, currentDate, xlsx) + ReportType.EVENTS -> fetchEvents(deviceId, previousDate, currentDate, eventTypes, xlsx) ReportType.STOPS -> fetchStops(deviceId, previousDate, currentDate, xlsx) } } @@ -84,13 +85,16 @@ class ReportController( deviceId: Int, from: String, to: String, + types: Array<EventInformation.Type>, xlsx: Boolean ) { Log.d("UnitReportsVM", "Fetching events") if (!xlsx) { val positionsResult = reportsApi.reportsRouteGet(from, to, deviceId) - val eventsResult = reportsApi.reportsEventsGet(from, to, deviceId) + val eventsResult = reportsApi.reportsEventsGet( + from, to, EventInformation.reportTypesToString(types), deviceId + ) val geofencesResult = geofencesApi.geofencesGet(all = true) val result = mutableListOf<EventInformation>() @@ -105,7 +109,9 @@ class ReportController( Log.d("UnitReportsVM", "Events report: $result") reportFlow.value = Report.EventsReport(result.toTypedArray()) } else { - val result = reportsApi.reportsEventsGetXlsx(from, to, deviceId) + val result = reportsApi.reportsEventsGetXlsx( + from, to, EventInformation.reportTypesToString(types), deviceId + ) Log.d("UnitReportsVM", "Events report: $result") reportFlow.value = Report.XlsxReport(result) diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/Formatter.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/Formatter.kt index 878418e..c113bef 100644 --- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/Formatter.kt +++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/Formatter.kt @@ -1,7 +1,6 @@ package mx.trackermap.TrackerMap.utils import kotlinx.datetime.* -import kotlin.math.round class Formatter { companion object { @@ -25,5 +24,9 @@ class Formatter { } } } + + fun formatHours(millis: Long): String { + return "${millis / (1000 * 60 * 60)} hr" + } } }
\ No newline at end of file diff --git a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/MapCalculus.kt b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/MapCalculus.kt index 118c117..b1a6444 100644 --- a/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/MapCalculus.kt +++ b/shared/src/commonMain/kotlin/mx/trackermap/TrackerMap/utils/MapCalculus.kt @@ -31,6 +31,7 @@ class MapCalculus { 19 -> 1066.36479193 20 -> 533.182395965 21 -> 266.5911979825 + 22 -> 133.29559899125 else -> null } } |