2020-01-02 17:00:37 +00:00
|
|
|
/*
|
|
|
|
* TrackFragment.kt
|
|
|
|
* Implements the TrackFragment fragment
|
|
|
|
* A TrackFragment displays a previously recorded track
|
|
|
|
*
|
|
|
|
* This file is part of
|
|
|
|
* TRACKBOOK - Movement Recorder for Android
|
|
|
|
*
|
|
|
|
* Copyright (c) 2016-20 - Y20K.org
|
|
|
|
* Licensed under the MIT-License
|
|
|
|
* http://opensource.org/licenses/MIT
|
|
|
|
*
|
|
|
|
* Trackbook uses osmdroid - OpenStreetMap-Tools for Android
|
|
|
|
* https://github.com/osmdroid/osmdroid
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
package org.y20k.trackbook
|
|
|
|
|
|
|
|
|
|
|
|
import YesNoDialog
|
2020-02-13 16:12:34 +00:00
|
|
|
import android.app.Activity
|
2020-01-02 17:00:37 +00:00
|
|
|
import android.content.Context
|
|
|
|
import android.content.Intent
|
|
|
|
import android.content.pm.PackageManager
|
|
|
|
import android.net.Uri
|
2020-08-01 01:13:21 +00:00
|
|
|
import android.os.Build
|
2020-01-02 17:00:37 +00:00
|
|
|
import android.os.Bundle
|
2020-08-01 01:13:21 +00:00
|
|
|
import android.os.VibrationEffect
|
2020-02-13 16:12:34 +00:00
|
|
|
import android.os.Vibrator
|
2020-01-02 17:00:37 +00:00
|
|
|
import android.view.LayoutInflater
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
|
|
|
import android.widget.Toast
|
|
|
|
import androidx.core.content.FileProvider
|
|
|
|
import androidx.core.net.toFile
|
|
|
|
import androidx.core.os.bundleOf
|
|
|
|
import androidx.fragment.app.Fragment
|
|
|
|
import androidx.navigation.fragment.findNavController
|
|
|
|
import kotlinx.coroutines.GlobalScope
|
|
|
|
import kotlinx.coroutines.launch
|
2020-02-13 16:12:34 +00:00
|
|
|
import org.y20k.trackbook.core.Track
|
2020-01-02 17:00:37 +00:00
|
|
|
import org.y20k.trackbook.dialogs.RenameTrackDialog
|
|
|
|
import org.y20k.trackbook.helpers.FileHelper
|
|
|
|
import org.y20k.trackbook.helpers.LogHelper
|
2020-07-30 11:59:07 +00:00
|
|
|
import org.y20k.trackbook.helpers.MapOverlay
|
|
|
|
import org.y20k.trackbook.helpers.TrackHelper
|
2020-01-02 17:00:37 +00:00
|
|
|
import org.y20k.trackbook.ui.TrackFragmentLayoutHolder
|
|
|
|
|
2020-04-01 15:26:20 +00:00
|
|
|
|
2020-08-01 00:06:53 +00:00
|
|
|
class TrackFragment : Fragment(), RenameTrackDialog.RenameTrackListener,
|
|
|
|
YesNoDialog.YesNoDialogListener, MapOverlay.MarkerListener {
|
2020-01-02 17:00:37 +00:00
|
|
|
|
|
|
|
/* Define log tag */
|
|
|
|
private val TAG: String = LogHelper.makeLogTag(TrackFragment::class.java)
|
|
|
|
|
|
|
|
|
|
|
|
/* Main class variables */
|
2020-02-13 16:12:34 +00:00
|
|
|
private lateinit var layout: TrackFragmentLayoutHolder
|
|
|
|
private lateinit var track: Track
|
|
|
|
|
|
|
|
|
|
|
|
/* Overrides onCreate from Fragment */
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
// get track
|
2020-08-01 00:06:53 +00:00
|
|
|
val fileUriString: String =
|
|
|
|
arguments?.getString(Keys.ARG_TRACK_FILE_URI, String()) ?: String()
|
2020-08-01 01:04:52 +00:00
|
|
|
track = if (fileUriString.isNotBlank()) {
|
|
|
|
FileHelper.readTrack(Uri.parse(fileUriString))
|
2020-02-13 16:12:34 +00:00
|
|
|
} else {
|
2020-08-01 01:04:52 +00:00
|
|
|
Track()
|
2020-02-13 16:12:34 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-02 17:00:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Overrides onCreateView from Fragment */
|
2020-08-01 00:06:53 +00:00
|
|
|
override fun onCreateView(
|
|
|
|
inflater: LayoutInflater,
|
|
|
|
container: ViewGroup?,
|
|
|
|
savedInstanceState: Bundle?
|
|
|
|
): View? {
|
2020-01-02 17:00:37 +00:00
|
|
|
// initialize layout
|
2020-08-01 00:06:53 +00:00
|
|
|
layout = TrackFragmentLayoutHolder(
|
|
|
|
activity as Context,
|
|
|
|
this as MapOverlay.MarkerListener,
|
|
|
|
inflater,
|
|
|
|
container,
|
|
|
|
track
|
|
|
|
)
|
2020-01-02 17:00:37 +00:00
|
|
|
|
|
|
|
// set up share button
|
|
|
|
layout.shareButton.setOnClickListener {
|
2020-02-13 16:12:34 +00:00
|
|
|
openSaveGpxDialog()
|
|
|
|
}
|
|
|
|
layout.shareButton.setOnLongClickListener {
|
|
|
|
val v = (activity as Context).getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
2020-08-01 01:13:21 +00:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
v.vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE))
|
|
|
|
} else {
|
|
|
|
v.vibrate(50)
|
|
|
|
}
|
2020-02-13 16:12:34 +00:00
|
|
|
shareGpxTrack()
|
|
|
|
return@setOnLongClickListener true
|
2020-01-02 17:00:37 +00:00
|
|
|
}
|
|
|
|
// set up delete button
|
|
|
|
layout.deleteButton.setOnClickListener {
|
2020-08-01 01:04:52 +00:00
|
|
|
val dialogMessage =
|
2020-08-01 00:06:53 +00:00
|
|
|
"${getString(R.string.dialog_yes_no_message_delete_recording)}\n\n- ${layout.trackNameView.text}"
|
|
|
|
YesNoDialog(this@TrackFragment as YesNoDialog.YesNoDialogListener).show(
|
|
|
|
context = activity as Context,
|
|
|
|
type = Keys.DIALOG_DELETE_TRACK,
|
|
|
|
messageString = dialogMessage,
|
|
|
|
yesButton = R.string.dialog_yes_no_positive_button_delete_recording
|
|
|
|
)
|
2020-01-02 17:00:37 +00:00
|
|
|
}
|
|
|
|
// set up rename button
|
|
|
|
layout.editButton.setOnClickListener {
|
2020-08-01 00:06:53 +00:00
|
|
|
RenameTrackDialog(this as RenameTrackDialog.RenameTrackListener).show(
|
|
|
|
activity as Context,
|
|
|
|
layout.trackNameView.text.toString()
|
|
|
|
)
|
2020-01-02 17:00:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return layout.rootView
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Overrides onResume from Fragment */
|
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
// update zoom level and map center
|
|
|
|
layout.updateMapView()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Overrides onPause from Fragment */
|
|
|
|
override fun onPause() {
|
|
|
|
super.onPause()
|
|
|
|
// save zoom level and map center
|
|
|
|
layout.saveViewStateToTrack()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-13 16:12:34 +00:00
|
|
|
/* Overrides onActivityResult from Fragment */
|
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
|
|
when (requestCode) {
|
|
|
|
// save GPX file to result file location
|
|
|
|
Keys.REQUEST_SAVE_GPX -> {
|
|
|
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
|
|
|
val sourceUri: Uri = Uri.parse(track.gpxUriString)
|
|
|
|
val targetUri: Uri? = data.data
|
|
|
|
if (targetUri != null) {
|
|
|
|
// copy file async (= fire & forget - no return value needed)
|
2020-08-01 00:06:53 +00:00
|
|
|
GlobalScope.launch {
|
|
|
|
FileHelper.saveCopyOfFileSuspended(
|
|
|
|
activity as Context,
|
|
|
|
originalFileUri = sourceUri,
|
|
|
|
targetFileUri = targetUri
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Toast.makeText(
|
|
|
|
activity as Context,
|
|
|
|
R.string.toast_message_save_gpx,
|
|
|
|
Toast.LENGTH_LONG
|
|
|
|
).show()
|
2020-02-13 16:12:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// let activity handle result
|
|
|
|
else -> super.onActivityResult(requestCode, resultCode, data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-02 17:00:37 +00:00
|
|
|
/* Overrides onRenameTrackDialog from RenameTrackDialog */
|
|
|
|
override fun onRenameTrackDialog(textInput: String) {
|
|
|
|
// rename track async (= fire & forget - no return value needed)
|
2020-08-01 00:06:53 +00:00
|
|
|
GlobalScope.launch {
|
|
|
|
FileHelper.renameTrackSuspended(
|
|
|
|
activity as Context,
|
|
|
|
layout.track,
|
|
|
|
textInput
|
|
|
|
)
|
|
|
|
}
|
2020-01-02 17:00:37 +00:00
|
|
|
// update name in layout
|
|
|
|
layout.track.name = textInput
|
|
|
|
layout.trackNameView.text = textInput
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Overrides onYesNoDialog from YesNoDialogListener */
|
2020-08-01 00:06:53 +00:00
|
|
|
override fun onYesNoDialog(
|
|
|
|
type: Int,
|
|
|
|
dialogResult: Boolean,
|
|
|
|
payload: Int,
|
|
|
|
payloadString: String
|
|
|
|
) {
|
2020-01-02 17:00:37 +00:00
|
|
|
when (type) {
|
2020-03-09 14:39:48 +00:00
|
|
|
Keys.DIALOG_DELETE_TRACK -> {
|
2020-01-02 17:00:37 +00:00
|
|
|
when (dialogResult) {
|
|
|
|
// user tapped remove track
|
|
|
|
true -> {
|
|
|
|
// switch to TracklistFragment and remove track there
|
2020-04-01 15:26:20 +00:00
|
|
|
val trackId: Long = arguments?.getLong(Keys.ARG_TRACK_ID, -1L) ?: -1L
|
2020-01-02 17:00:37 +00:00
|
|
|
val bundle: Bundle = bundleOf(Keys.ARG_TRACK_ID to trackId)
|
|
|
|
findNavController().navigate(R.id.tracklist_fragment, bundle)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-30 11:59:07 +00:00
|
|
|
/* Overrides onMarkerTapped from MarkerListener */
|
|
|
|
override fun onMarkerTapped(latitude: Double, longitude: Double) {
|
|
|
|
super.onMarkerTapped(latitude, longitude)
|
|
|
|
// update track display
|
|
|
|
track = TrackHelper.toggleStarred(activity as Context, track, latitude, longitude)
|
|
|
|
layout.updateTrackOverlay(track)
|
|
|
|
// save track
|
|
|
|
GlobalScope.launch {
|
|
|
|
FileHelper.saveTrackSuspended(track, true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-02-13 16:12:34 +00:00
|
|
|
/* Opens up a file picker to select the save location */
|
|
|
|
private fun openSaveGpxDialog() {
|
|
|
|
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
|
|
|
|
addCategory(Intent.CATEGORY_OPENABLE)
|
|
|
|
type = Keys.MIME_TYPE_GPX
|
|
|
|
putExtra(Intent.EXTRA_TITLE, FileHelper.getGpxFileName(track))
|
|
|
|
}
|
|
|
|
// file gets saved in onActivityResult
|
2020-04-01 15:26:20 +00:00
|
|
|
val packageManager: PackageManager? = activity?.packageManager
|
|
|
|
if (packageManager != null && intent.resolveActivity(packageManager) != null) {
|
|
|
|
startActivityForResult(intent, Keys.REQUEST_SAVE_GPX)
|
|
|
|
} else {
|
2020-08-01 00:06:53 +00:00
|
|
|
Toast.makeText(
|
|
|
|
activity as Context,
|
|
|
|
R.string.toast_message_install_file_helper,
|
|
|
|
Toast.LENGTH_LONG
|
|
|
|
).show()
|
2020-04-01 15:26:20 +00:00
|
|
|
}
|
2020-02-13 16:12:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-02 17:00:37 +00:00
|
|
|
/* Share track as GPX via share sheet */
|
2020-02-13 16:12:34 +00:00
|
|
|
private fun shareGpxTrack() {
|
2020-01-02 17:00:37 +00:00
|
|
|
val gpxFile = Uri.parse(layout.track.gpxUriString).toFile()
|
2020-08-01 00:06:53 +00:00
|
|
|
val gpxShareUri = FileProvider.getUriForFile(
|
|
|
|
this.activity as Context,
|
|
|
|
"${requireActivity().applicationContext.packageName}.provider",
|
|
|
|
gpxFile
|
|
|
|
)
|
2020-01-02 17:00:37 +00:00
|
|
|
val shareIntent: Intent = Intent.createChooser(Intent().apply {
|
|
|
|
action = Intent.ACTION_SEND
|
|
|
|
data = gpxShareUri
|
2020-02-13 16:12:34 +00:00
|
|
|
type = Keys.MIME_TYPE_GPX
|
2020-01-02 17:00:37 +00:00
|
|
|
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
|
|
putExtra(Intent.EXTRA_STREAM, gpxShareUri)
|
|
|
|
}, null)
|
|
|
|
|
|
|
|
// show share sheet - if file helper is available
|
|
|
|
val packageManager: PackageManager? = activity?.packageManager
|
|
|
|
if (packageManager != null && shareIntent.resolveActivity(packageManager) != null) {
|
|
|
|
startActivity(shareIntent)
|
|
|
|
} else {
|
2020-08-01 00:06:53 +00:00
|
|
|
Toast.makeText(activity, R.string.toast_message_install_file_helper, Toast.LENGTH_LONG)
|
|
|
|
.show()
|
2020-01-02 17:00:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|