diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 545f375..9431e03 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -56,7 +56,9 @@
+ android:exported="false"
+ android:theme="@style/FullscreenTheme"
+ />
+ android:label="@string/photo_tip"
+ android:theme="@style/FullscreenTheme"
+ />
+ android:theme="@style/AppTheme" />
() {
- companion object {
- private val xmlHelper = XmlHelper()
- }
-
override fun createIntent(context: Context, input: FacebookInputData): Intent {
return Intent(context, FacebookActivity::class.java).apply {
- putExtra(FacebookActivity.TREASURE_PROGRESS, xmlHelper.writeToString(input.progress))
+ putExtra(FacebookActivity.INPUT, input)
}
}
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/FacebookViewModel.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/FacebookViewModel.kt
index 684d647..386068e 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/FacebookViewModel.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/FacebookViewModel.kt
@@ -4,6 +4,7 @@ import android.content.Context
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import pl.marianjureczko.poszukiwacz.R
+import pl.marianjureczko.poszukiwacz.model.HunterPath
import pl.marianjureczko.poszukiwacz.model.Route
import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
import pl.marianjureczko.poszukiwacz.shared.StorageHelper
@@ -12,13 +13,16 @@ class FacebookViewModel(private val state: SavedStateHandle) : ViewModel() {
private val TAG = javaClass.simpleName
lateinit var progress: TreasuresProgress
private set
+ var hunterPath: HunterPath? = null
+ private set
lateinit var elements: List
private set
lateinit var route: Route
- fun initialize(progress: TreasuresProgress, context: Context) {
+ fun initialize(context: Context, hunterPath: HunterPath?, progress: TreasuresProgress) {
this.progress = progress
+ this.hunterPath = hunterPath
val elements = mutableListOf()
elements.add(ElementDescription(Type.TREASURES_SUMMARY, true, context.getString(R.string.collected_treasures)))
val treasure = context.getString(R.string.treasure)
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMap.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMap.kt
index 43c2816..1810a1a 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMap.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMap.kt
@@ -62,19 +62,22 @@ class ReportMap(
}
private fun drawRoute(snapshot: MapSnapshotInterface, mapCanvas: Canvas) {
- val locations = model.progress.hunterPath.pathAsCoordinates().toList()
- if (locations.size > 1) {
- var previousXY = snapshot.screenCoordinate(Point.fromLngLat(locations[0].longitude, locations[0].latitude))
- locations.asSequence()
- .drop(1)
- .forEach {
- val xy = snapshot.screenCoordinate(Point.fromLngLat(it.longitude, it.latitude))
- mapCanvas.drawLine(
- previousXY.x.toFloat(), previousXY.y.toFloat(), xy.x.toFloat(), xy.y.toFloat(),
- Paint().apply { color = Color.RED }
- )
- previousXY = xy
- }
+ model.hunterPath?.let {
+ val locations = it.pathAsCoordinates().toList()
+ if (locations.size > 1) {
+ var previousXY =
+ snapshot.screenCoordinate(Point.fromLngLat(locations[0].longitude, locations[0].latitude))
+ locations.asSequence()
+ .drop(1)
+ .forEach {
+ val xy = snapshot.screenCoordinate(Point.fromLngLat(it.longitude, it.latitude))
+ mapCanvas.drawLine(
+ previousXY.x.toFloat(), previousXY.y.toFloat(), xy.x.toFloat(), xy.y.toFloat(),
+ Paint().apply { color = Color.RED }
+ )
+ previousXY = xy
+ }
+ }
}
}
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMapSummary.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMapSummary.kt
index 4eb7da5..ebb080b 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMapSummary.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/facebook/ReportMapSummary.kt
@@ -29,9 +29,9 @@ class ReportMapSummary(
val textPaint = ReportCommons.getTextPaint(font, Paint.Align.LEFT)
var textY = currentTop + 50
var x = ReportCommons.REPORT_MARGIN
- canvas.drawText(distanceText(context, model.progress.hunterPath), x, textY, textPaint)
+ canvas.drawText(distanceText(context, model.hunterPath), x, textY, textPaint)
textY += 40
- canvas.drawText(timeText(context, model.progress.hunterPath), x, textY, textPaint)
+ canvas.drawText(timeText(context, model.hunterPath), x, textY, textPaint)
}
}
@@ -42,17 +42,18 @@ class ReportMapSummary(
context.getResources().getConfiguration().locale
}
- private fun distanceText(context: Context, hunterPath: HunterPath): String {
- val formattedDistance = "%.2f".format(hunterPath.pathLengthInKm())
+ private fun distanceText(context: Context, hunterPath: HunterPath?): String {
+ val distance = hunterPath?.pathLengthInKm() ?: 0.0
+ val formattedDistance = "%.2f".format(distance)
return "${context.getString(R.string.walked_route)} $formattedDistance km."
}
- private fun timeText(context: Context, hunterPath: HunterPath): String {
+ private fun timeText(context: Context, hunterPath: HunterPath?): String {
val loc = Locale("en", "US")
val timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, loc)
val dateFormat: DateFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, loc)
- hunterPath.getStartTime()?.let { start ->
+ hunterPath?.getStartTime()?.let { start ->
val startDate = dateFormat.format(start)
val startTime = timeFormat.format(start)
hunterPath.getEndTime()?.let { end ->
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/MainActivity.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/MainActivity.kt
index 1c6e000..aaac273 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/MainActivity.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/MainActivity.kt
@@ -23,7 +23,7 @@ import pl.marianjureczko.poszukiwacz.shared.StorageHelper
class MainActivity : PermissionActivity() {
private val TAG = javaClass.simpleName
- override fun getCurrentTreasuresProgress(): TreasuresProgress? {
+ override fun getTreasureProgress(): TreasuresProgress? {
return null
}
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/map/MapActivity.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/map/MapActivity.kt
index 81ae7a3..b8263f8 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/map/MapActivity.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/map/MapActivity.kt
@@ -41,7 +41,7 @@ class MapActivity : ActivityWithAdsAndBackButton() {
setUpAds(binding.adView)
}
- override fun getCurrentTreasuresProgress(): TreasuresProgress? = model.progress
+ override fun getTreasureProgress(): TreasuresProgress? = model.progress
override fun onResume() {
super.onResume()
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/photo/PhotoActivity.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/photo/PhotoActivity.kt
index ff617ff..c299ed9 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/photo/PhotoActivity.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/photo/PhotoActivity.kt
@@ -33,7 +33,7 @@ class PhotoActivity : ActivityWithAdsAndBackButton() {
setUpAds(binding.adView)
}
- override fun getCurrentTreasuresProgress(): TreasuresProgress =
+ override fun getTreasureProgress(): TreasuresProgress =
model.progress
}
\ No newline at end of file
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivity.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivity.kt
index 2b1f02c..bed83bc 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivity.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivity.kt
@@ -2,20 +2,49 @@ package pl.marianjureczko.poszukiwacz.activity.result
import android.app.Activity
import android.content.pm.ActivityInfo
+import android.net.Uri
import android.os.Bundle
import android.view.View
+import android.widget.Toast
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.viewModels
+import androidx.core.view.isVisible
import pl.marianjureczko.poszukiwacz.R
+import pl.marianjureczko.poszukiwacz.activity.commemorative.CommemorativeContract
+import pl.marianjureczko.poszukiwacz.activity.commemorative.CommemorativeInputData
import pl.marianjureczko.poszukiwacz.databinding.ActivityResultBinding
import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
import pl.marianjureczko.poszukiwacz.shared.ActivityWithAdsAndBackButton
+import pl.marianjureczko.poszukiwacz.shared.PhotoHelper
+import pl.marianjureczko.poszukiwacz.shared.StorageHelper
class ResultActivity : ActivityWithAdsAndBackButton() {
companion object {
- const val RESULT = "pl.marianjureczko.poszukiwacz.activity.result";
+ const val RESULT_IN = "pl.marianjureczko.poszukiwacz.activity.result_in"
+ const val RESULT_OUT = "pl.marianjureczko.poszukiwacz.activity.result_out"
}
+ private val model: ResultActivityViewModel by viewModels()
private lateinit var binding: ActivityResultBinding
+ private val storageHelper = StorageHelper(this)
+ private val photoHelper = PhotoHelper(this, storageHelper)
+
+ private val showCommemorativeLauncher: ActivityResultLauncher =
+ registerForActivityResult(CommemorativeContract()) {}
+
+ //TODO t: copied from CommemorativeActivity
+ private val doPhotoLauncher: ActivityResultLauncher =
+ registerForActivityResult(ActivityResultContracts.TakePicture()) { result ->
+ if (result) {
+ model.addCommemorativePhoto(storageHelper, photoHelper.moveCommemorativePhotoToPermanentLocation())
+ configureDoPhotoButton()
+ Toast.makeText(this, R.string.photo_saved, Toast.LENGTH_SHORT).show()
+ } else {
+ Toast.makeText(this, R.string.photo_not_replaced, Toast.LENGTH_SHORT).show()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -24,24 +53,51 @@ class ResultActivity : ActivityWithAdsAndBackButton() {
binding = ActivityResultBinding.inflate(layoutInflater)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- val input = intent.getSerializableExtra(RESULT) as ResultActivityData
- if (input.isError()) {
- binding.resultDescription.text = input.error
+ val input = intent.getSerializableExtra(RESULT_IN) as ResultActivityInput
+ model.initialize(this, storageHelper, input.treasure, input.progress, input.treasureDescription)
+
+ configureView()
+ setContentView(binding.root)
+ setUpAds(binding.adView)
+ }
+
+ private fun configureView() {
+ if (model.isError()) {
+ binding.resultDescription.text = model.errorMsg
binding.resultImg.visibility = View.GONE
} else {
- binding.resultDescription.text = input.treasure!!.quantity.toString()
- binding.resultImg.setImageResource(input.treasure.type.image())
+ binding.resultDescription.text = model.treasure!!.quantity.toString()
+ binding.resultImg.setImageResource(model.treasure!!.type.image())
+ }
+
+ if (model.canMakeCommemorativePhoto()) {
+ configureDoPhotoButton()
+ } else {
+ binding.buttonsLayout.isVisible = false
+ }
+ }
+
+ private fun configureDoPhotoButton() {
+ binding.buttonsLayout.isVisible = true
+ if (model.currentTreasureHasCommemorativePhoto()) {
+ binding.doPhoto.setImageResource(R.drawable.camera_show_photo)
+ binding.doPhoto.setOnClickListener {
+ model.commemorativeInputData()?.let { showCommemorativeLauncher.launch(it) }
+ }
+ } else {
+ binding.doPhoto.setImageResource(R.drawable.camera_do_photo)
+ binding.doPhoto.setOnClickListener {
+ doPhotoLauncher.launch(photoHelper.createCommemorativePhotoTempUri())
+ }
}
- setContentView(binding.root)
- setUpAds(binding.adView)
}
- override fun getCurrentTreasuresProgress(): TreasuresProgress? {
+ override fun getTreasureProgress(): TreasuresProgress? {
return null
}
override fun onBackPressed() {
- setResult(Activity.RESULT_OK, intent)
+ setResult(Activity.RESULT_OK, model.activityResult())
super.onBackPressed()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityContract.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityContract.kt
index eba5630..6390380 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityContract.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityContract.kt
@@ -4,14 +4,14 @@ import android.content.Context
import android.content.Intent
import androidx.activity.result.contract.ActivityResultContract
-class ResultActivityContract : ActivityResultContract() {
- override fun createIntent(context: Context, input: ResultActivityData?): Intent {
+class ResultActivityContract : ActivityResultContract() {
+ override fun createIntent(context: Context, input: ResultActivityInput?): Intent {
return Intent(context, ResultActivity::class.java).apply {
- putExtra(ResultActivity.RESULT, input)
+ putExtra(ResultActivity.RESULT_IN, input)
}
}
- override fun parseResult(resultCode: Int, intent: Intent?): ResultActivityData? {
- return intent?.getSerializableExtra(ResultActivity.RESULT) as ResultActivityData?
+ override fun parseResult(resultCode: Int, intent: Intent?): ResultActivityOutput {
+ return intent?.getSerializableExtra(ResultActivity.RESULT_OUT) as ResultActivityOutput
}
}
\ No newline at end of file
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityData.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityData.kt
deleted file mode 100644
index d8b1da7..0000000
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityData.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.marianjureczko.poszukiwacz.activity.result
-
-import pl.marianjureczko.poszukiwacz.model.Treasure
-import java.io.Serializable
-
-data class ResultActivityData(val treasure: Treasure?, val error: String?) : Serializable {
- constructor(treasure: Treasure?) : this(treasure, null)
- constructor(error: String?) : this(null, error)
-
- fun isError(): Boolean = error != null
-}
\ No newline at end of file
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityInput.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityInput.kt
new file mode 100644
index 0000000..2e4d42b
--- /dev/null
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityInput.kt
@@ -0,0 +1,19 @@
+package pl.marianjureczko.poszukiwacz.activity.result
+
+import pl.marianjureczko.poszukiwacz.model.Treasure
+import pl.marianjureczko.poszukiwacz.model.TreasureDescription
+import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
+import java.io.Serializable
+
+//TODO t: remove ?
+data class ResultActivityInput(
+ val treasure: Treasure?,
+ val treasureDescription: TreasureDescription?,
+ val progress: TreasuresProgress?
+) : Serializable
+
+data class ResultActivityOutput(
+ val progress: TreasuresProgress?,
+ val justFoundTreasureDescription: TreasureDescription?,
+ val newTreasureCollected: Boolean
+) : Serializable
\ No newline at end of file
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityViewModel.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityViewModel.kt
new file mode 100644
index 0000000..2abbc81
--- /dev/null
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/result/ResultActivityViewModel.kt
@@ -0,0 +1,114 @@
+package pl.marianjureczko.poszukiwacz.activity.result
+
+import android.content.Intent
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import pl.marianjureczko.poszukiwacz.R
+import pl.marianjureczko.poszukiwacz.activity.commemorative.CommemorativeInputData
+import pl.marianjureczko.poszukiwacz.model.Treasure
+import pl.marianjureczko.poszukiwacz.model.TreasureDescription
+import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
+import pl.marianjureczko.poszukiwacz.shared.StorageHelper
+
+class ResultActivityViewModel(private val state: SavedStateHandle) : ViewModel() {
+
+ companion object {
+ const val ERROR_MSG = "errorMsg"
+ const val PROGRESS = "progress"
+ }
+
+ var treasure: Treasure? = null
+ private set
+ var progress: TreasuresProgress?
+ get() = state.get(PROGRESS)
+ private set(value) = state.set(PROGRESS, value)
+ private var currentTreasureDescription: TreasureDescription? = null
+ var errorMsg: String?
+ get() = state.get(ERROR_MSG)
+ private set(value) = state.set(ERROR_MSG, value)
+
+ /**
+ * Checks what kind of treasure was found and adds it to the progress if it's a mew one.
+ * If there nothing to add, sets an appropriate error message in errMsg.
+ */
+ fun initialize(
+ app: AppCompatActivity,
+ storageHelper: StorageHelper,
+ treasure: Treasure?,
+ progress: TreasuresProgress?,
+ currentTreasureDescription: TreasureDescription?
+ ) {
+ this.treasure = treasure
+ this.progress = progress
+ this.currentTreasureDescription = currentTreasureDescription
+
+ if (treasure == null) {
+ errorMsg = app.resources.getString(R.string.not_a_treasure_msg)
+ } else {
+ val p = this.progress
+ p?.let {
+ if (it.contains(treasure)) {
+ errorMsg = app.resources.getString(R.string.treasure_already_taken_msg)
+ } else {
+ it.collect(treasure)
+ if (currentTreasureDescription != null) {
+ it.collect(currentTreasureDescription)
+ }
+ // to save the updated progress in the quasi persistent state
+ this.progress = it
+ storageHelper.save(it)
+ }
+ }
+ }
+ }
+
+ fun addCommemorativePhoto(storageHelper: StorageHelper, commemorativePhotoAbsolutePath: String) {
+ currentTreasureDescription?.let {
+ progress?.let {
+ it.addCommemorativePhoto(currentTreasureDescription!!, commemorativePhotoAbsolutePath)
+ storageHelper.save(it)
+ // to save the updated progress in the quasi persistent state
+ progress = it
+ }
+ }
+ }
+
+ fun isError(): Boolean = this.errorMsg != null
+
+ fun canMakeCommemorativePhoto(): Boolean = !isError() && currentTreasureDescription != null
+
+ fun currentTreasureHasCommemorativePhoto(): Boolean =
+ if (progress != null && currentTreasureDescription != null) {
+ progress!!.getCommemorativePhoto(currentTreasureDescription!!) != null
+ } else {
+ false
+ }
+
+ fun commemorativeInputData(): CommemorativeInputData? {
+ if (!currentTreasureHasCommemorativePhoto()) {
+ return null
+ }
+ return CommemorativeInputData(
+ progress!!.getCommemorativePhoto(currentTreasureDescription!!)!!,
+ progress!!
+ )
+
+ }
+
+ fun activityResult(): Intent {
+ val data = Intent()
+ progress?.let {
+ data.putExtra(
+ ResultActivity.RESULT_OUT,
+ ResultActivityOutput(progress, currentTreasureDescription, !isError())
+ )
+ }
+ return data
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/ChangeTreasureButtonListener.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/ChangeTreasureButtonListener.kt
index 4ae778f..e8564b8 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/ChangeTreasureButtonListener.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/ChangeTreasureButtonListener.kt
@@ -4,9 +4,10 @@ import android.view.View
import androidx.activity.result.ActivityResultLauncher
import pl.marianjureczko.poszukiwacz.activity.treasureselector.SelectTreasureInputData
import pl.marianjureczko.poszukiwacz.model.Treasure
+import pl.marianjureczko.poszukiwacz.model.TreasureDescription
interface TreasuresStorage {
- fun getTreasureSelectorActivityInputData(justFoundTreasure: Treasure?): SelectTreasureInputData
+ fun getTreasureSelectorActivityInputData(justFoundTreasureDesc: TreasureDescription?): SelectTreasureInputData
}
class ChangeTreasureButtonListener (
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/JustFoundFinder.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/JustFoundFinder.kt
new file mode 100644
index 0000000..378fde0
--- /dev/null
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/JustFoundFinder.kt
@@ -0,0 +1,34 @@
+package pl.marianjureczko.poszukiwacz.activity.searching
+
+import android.util.Log
+import pl.marianjureczko.poszukiwacz.activity.treasureselector.Coordinates
+import pl.marianjureczko.poszukiwacz.model.Treasure
+import pl.marianjureczko.poszukiwacz.model.TreasureDescription
+
+/**
+ * To find data about the "just found" by user treasure
+ */
+class JustFoundFinder(
+ /**justFoundTreasure shall be used for app version with fixed treasures locations*/
+ val justFoundTreasure: Treasure?,
+ val selectedTreasureDescription: TreasureDescription?,
+ val userLocation: Coordinates?,
+ val locationCalculator: LocationCalculator = LocationCalculator()
+) {
+ private val TAG = javaClass.simpleName
+
+ fun findTreasureDescription(): TreasureDescription? {
+ return if (justFoundTreasure != null && selectedTreasureDescription != null && userLocation != null) {
+ val distance = locationCalculator.distanceInSteps(selectedTreasureDescription, userLocation)
+ Log.i(TAG, "Distance is $distance")
+ if (distance < 60) {
+ selectedTreasureDescription
+ } else {
+ null
+ }
+ } else {
+ null
+ }
+ }
+}
+
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivity.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivity.kt
index 2d97a54..9925409 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivity.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivity.kt
@@ -14,7 +14,8 @@ import pl.marianjureczko.poszukiwacz.R
import pl.marianjureczko.poszukiwacz.activity.map.MapActivityContract
import pl.marianjureczko.poszukiwacz.activity.map.MapInputData
import pl.marianjureczko.poszukiwacz.activity.result.ResultActivityContract
-import pl.marianjureczko.poszukiwacz.activity.result.ResultActivityData
+import pl.marianjureczko.poszukiwacz.activity.result.ResultActivityInput
+import pl.marianjureczko.poszukiwacz.activity.result.ResultActivityOutput
import pl.marianjureczko.poszukiwacz.activity.treasureselector.SelectTreasureContract
import pl.marianjureczko.poszukiwacz.activity.treasureselector.SelectTreasureInputData
import pl.marianjureczko.poszukiwacz.activity.treasureselector.SelectTreasureOutputData
@@ -46,7 +47,7 @@ class SearchingActivity : ActivityWithAdsAndBackButton() {
private val model: SearchingActivityViewModel by viewModels()
private lateinit var binding: ActivitySearchingBinding
private lateinit var treasureSelectorLauncher: ActivityResultLauncher
- private lateinit var showResultLauncher: ActivityResultLauncher
+ private lateinit var showResultLauncher: ActivityResultLauncher
private lateinit var showMapLauncher: ActivityResultLauncher
@SuppressLint("SourceLockedOrientationActivity")
@@ -57,7 +58,12 @@ class SearchingActivity : ActivityWithAdsAndBackButton() {
setContentView(R.layout.activity_searching)
restoreState()
- binding.scanBtn.setOnClickListener(ScanButtonListener(createScanTreasureLauncher(), resources.getString(R.string.qr_scanner_msg)))
+ binding.scanBtn.setOnClickListener(
+ ScanButtonListener(
+ createScanTreasureLauncher(),
+ resources.getString(R.string.qr_scanner_msg)
+ )
+ )
treasureSelectorLauncher = createSelectTreasureLauncher()
showResultLauncher = createShowResultLauncher()
showMapLauncher = createShowMapLauncher()
@@ -72,15 +78,16 @@ class SearchingActivity : ActivityWithAdsAndBackButton() {
storageHelper
)
val handler = Handler()
- val locationRequester = LocationRequester(this, locationListener, handler, getSystemService(LOCATION_SERVICE) as LocationManager)
+ val locationRequester =
+ LocationRequester(this, locationListener, handler, getSystemService(LOCATION_SERVICE) as LocationManager)
handler.post(locationRequester)
setContentView(binding.root)
setUpAds(binding.adView)
}
- override fun getCurrentTreasuresProgress(): TreasuresProgress? {
- return model.getTreasureBag()
+ override fun getTreasureProgress(): TreasuresProgress? {
+ return model.getProgress()
}
override fun onPostResume() {
@@ -100,25 +107,15 @@ class SearchingActivity : ActivityWithAdsAndBackButton() {
showCollectedTreasures()
}
- private fun processSearchingResult(result: String): ResultActivityData {
- try {
+ private fun processSearchingResult(result: String): ResultActivityInput {
+ return try {
val treasure: Treasure = treasureParser.parse(result)
- return if (model.treasureIsAlreadyCollected(treasure)) {
- ResultActivityData(resources.getString(R.string.treasure_already_taken_msg))
- } else {
- add(treasure)
- ResultActivityData(treasure)
- }
+ ResultActivityInput(treasure, model.tryToFindTreasureDescription(treasure), model.getTreasuresProgress())
} catch (ex: IllegalArgumentException) {
- return ResultActivityData(resources.getString(R.string.not_a_treasure_msg))
+ ResultActivityInput(null, null, model.getTreasuresProgress())
}
}
- private fun add(treasure: Treasure) {
- model.collectTreasure(treasure, storageHelper)
- showCollectedTreasures()
- }
-
private fun showCollectedTreasures() {
binding.goldTxt.text = model.getGolds()
binding.rubyTxt.text = model.getRubies()
@@ -129,21 +126,24 @@ class SearchingActivity : ActivityWithAdsAndBackButton() {
registerForActivityResult(ScanContract()) { scanResult ->
if (scanResult != null && scanResult.contents != null) {
showResultLauncher.launch(processSearchingResult(scanResult.contents))
+ //TODO t: treasure progress need to be reloaded when receiving activity result
}
}
private fun createSelectTreasureLauncher(): ActivityResultLauncher =
registerForActivityResult(SelectTreasureContract()) { result: SelectTreasureOutputData? ->
if (result != null) {
- model.replaceTreasureBag(result.progress, storageHelper)
+ model.replaceProgress(result.progress, storageHelper)
}
}
- private fun createShowResultLauncher(): ActivityResultLauncher =
- registerForActivityResult(ResultActivityContract()) { result: ResultActivityData? ->
+ private fun createShowResultLauncher(): ActivityResultLauncher =
+ registerForActivityResult(ResultActivityContract()) { result: ResultActivityOutput? ->
result?.let {
- if (!it.isError()) {
- treasureSelectorLauncher.launch(model.getTreasureSelectorActivityInputData(it.treasure))
+ model.loadProgressFromStorage(storageHelper)
+ showCollectedTreasures()
+ if (it.newTreasureCollected) {
+ treasureSelectorLauncher.launch(model.getTreasureSelectorActivityInputData(it.justFoundTreasureDescription))
}
}
}
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModel.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModel.kt
index 1b57699..edeb08d 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModel.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModel.kt
@@ -25,6 +25,7 @@ class SearchingActivityViewModel(private val state: SavedStateHandle) : ViewMode
private val TAG = javaClass.simpleName
private val xmlHelper = XmlHelper()
private lateinit var route: Route
+ //TODO: state should be employed as property is mutable
private lateinit var treasuresProgress: TreasuresProgress
private var currentLocation: Location? = null
private var currentCoordinates: Coordinates? = state.get(CURRENT_COORDINATES)
@@ -33,46 +34,50 @@ class SearchingActivityViewModel(private val state: SavedStateHandle) : ViewMode
field = value
state[TREASURE_SELECTION_INITIALIZED] = value
}
+ //TODO t: how it corresponds with reloading progress?
private var hunterPath: HunterPath? = deserializeHunterPath(state.get(PATH))
private set(value) {
if (value != null) {
field = value
state[PATH] = xmlHelper.writeToString(value)
- treasuresProgress.hunterPath = value
}
}
private var mediaPlayer: MediaPlayer? = null
+ fun initialize(routeXml: String, storageHelper: StorageHelper) {
+ route = xmlHelper.loadFromString(routeXml)
+ loadProgressFromStorage(storageHelper)
+ }
+
override fun getSelectedForHuntTreasure(): TreasureDescription? {
return treasuresProgress.selectedTreasure
}
- override fun getTreasureSelectorActivityInputData(justFoundTreasure: Treasure?): SelectTreasureInputData {
+ override fun getTreasureSelectorActivityInputData(justFoundTreasureDesc: TreasureDescription?): SelectTreasureInputData {
treasureSelectionInitialized = true
- return SelectTreasureInputData(route, treasuresProgress, currentCoordinates, justFoundTreasure)
+ return SelectTreasureInputData(route, treasuresProgress, currentCoordinates, justFoundTreasureDesc)
}
+ fun tryToFindTreasureDescription(justFoundTreasure: Treasure?) =
+ JustFoundFinder(justFoundTreasure, getSelectedForHuntTreasure(), currentCoordinates)
+ .findTreasureDescription()
+
override fun setCurrentLocation(location: Location?, storageHelper: StorageHelper) {
currentLocation = location
location?.let {
currentCoordinates = Coordinates(it.latitude, it.longitude)
state[CURRENT_COORDINATES] = currentCoordinates
- if (treasuresProgress.hunterPath!!.addLocation(currentCoordinates!!)) {
- storageHelper.save(this.treasuresProgress)
+ val hp = hunterPath!!
+ if (hp.addLocation(currentCoordinates!!)) {
+ storageHelper.save(hp)
}
//to call setter
- hunterPath = treasuresProgress.hunterPath
+ hunterPath = hp
}
}
override fun getTreasuresProgress(): TreasuresProgress = treasuresProgress
- fun initialize(routeXml: String, storageHelper: StorageHelper) {
- route = xmlHelper.loadFromString(routeXml)
- treasuresProgress = storageHelper.loadProgress(route.name) ?: TreasuresProgress(route.name)
- hunterPath = treasuresProgress.hunterPath
- }
-
override fun tipName(): String? =
treasuresProgress.selectedTreasure?.tipFileName
@@ -91,9 +96,6 @@ class SearchingActivityViewModel(private val state: SavedStateHandle) : ViewMode
fun treasureSelectionInitialized() =
treasureSelectionInitialized || treasuresProgress.selectedTreasure != null
- fun treasureIsAlreadyCollected(treasure: Treasure): Boolean =
- treasuresProgress.contains(treasure)
-
fun collectTreasure(treasure: Treasure, storageHelper: StorageHelper) {
treasuresProgress.collect(treasure)
storageHelper.save(this.treasuresProgress)
@@ -108,14 +110,28 @@ class SearchingActivityViewModel(private val state: SavedStateHandle) : ViewMode
fun getDiamonds(): String =
treasuresProgress.diamonds.toString()
- fun replaceTreasureBag(treasuresProgress: TreasuresProgress, storageHelper: StorageHelper) {
+ fun replaceProgress(treasuresProgress: TreasuresProgress, storageHelper: StorageHelper) {
this.treasuresProgress = treasuresProgress
storageHelper.save(this.treasuresProgress)
}
+ fun loadProgressFromStorage(storageHelper: StorageHelper) {
+ var loadedProgress = storageHelper.loadProgress(route.name)
+ if (loadedProgress == null) {
+ loadedProgress = TreasuresProgress(route.name)
+ storageHelper.save(loadedProgress)
+ }
+ treasuresProgress = loadedProgress
+ hunterPath = storageHelper.loadHunterPath(route.name)
+ if(hunterPath == null) {
+ hunterPath = HunterPath(route.name)
+ storageHelper.save(hunterPath!!)
+ }
+ }
+
//visibility for tests
internal fun getRoute() = route
- internal fun getTreasureBag() = treasuresProgress
+ internal fun getProgress() = treasuresProgress
private fun handleMediaPlayerError(what: Int, extra: Int): Boolean {
when (what) {
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureseditor/TreasuresEditorActivity.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureseditor/TreasuresEditorActivity.kt
index e15ed10..b2cc446 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureseditor/TreasuresEditorActivity.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureseditor/TreasuresEditorActivity.kt
@@ -45,7 +45,7 @@ class TreasuresEditorActivity : PermissionActivity(), RouteNameDialog.Callback,
}
private val TAG = javaClass.simpleName
- override fun getCurrentTreasuresProgress(): TreasuresProgress? {
+ override fun getTreasureProgress(): TreasuresProgress? {
return null
}
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectTreasureContract.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectTreasureContract.kt
index 35ef664..0da28d2 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectTreasureContract.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectTreasureContract.kt
@@ -6,6 +6,7 @@ import android.content.Intent
import androidx.activity.result.contract.ActivityResultContract
import pl.marianjureczko.poszukiwacz.model.Route
import pl.marianjureczko.poszukiwacz.model.Treasure
+import pl.marianjureczko.poszukiwacz.model.TreasureDescription
import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
import pl.marianjureczko.poszukiwacz.shared.XmlHelper
import java.io.Serializable
@@ -14,7 +15,7 @@ data class SelectTreasureInputData(
val route: Route,
val progress: TreasuresProgress,
val currentCoordinates: Coordinates?,
- val justFoundTreasure: Treasure?
+ val justFoundTreasureDescription: TreasureDescription?
) : Serializable
data class SelectTreasureOutputData(
@@ -28,8 +29,8 @@ class SelectTreasureContract : ActivityResultContract>(IDS_OF_COLLECTED)?.let {
this.progress.collectedTreasuresDescriptionId.clear()
this.progress.collectedTreasuresDescriptionId.addAll(it)
@@ -110,18 +113,6 @@ class SelectorViewModel(private val state: SavedStateHandle) : ViewModel() {
}
}
- fun getUserLocation(): Coordinates? =
- userLocation?.copy()
-
- fun getJustFound(): Treasure? =
- justFoundTreasure
+ fun treasureDescriptionHasBeenIdentified(): Boolean = this.justFoundTreasureDescription != null
- fun treasureIsNotFarAwayFromUser(): Boolean =
- if (getSelectedTreasure() != null && getUserLocation() != null) {
- val distance = LocationCalculator().distanceInSteps(getSelectedTreasure()!!, getUserLocation()!!)
- Log.i(TAG, "Distance is $distance")
- distance < 60;
- } else {
- false
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureProgressHolder.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureProgressHolder.kt
index 75d0c9e..34d58a3 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureProgressHolder.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureProgressHolder.kt
@@ -35,7 +35,7 @@ class TreasureProgressHolder(
private val photoHelper = PhotoHelper(context, storageHelper)
fun setup(treasure: TreasureDescription, commemorativePhoto: String?) {
- if (model.isCollected(treasure)) {
+ if (model.isCollected(treasure) && treasure != model.justFoundTreasureDescription) {
showCollected()
} else {
showNotCollected()
@@ -66,7 +66,6 @@ class TreasureProgressHolder(
doPhotoLauncher.launch(photoHelper.createCommemorativePhotoTempUri())
} else {
showCommemorativeLauncher.launch(CommemorativeInputData(commemorativePhoto, model.progress))
-// context.startActivity(CommemorativeActivity.intent(context, commemorativePhoto))
}
}
}
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureSelectorActivity.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureSelectorActivity.kt
index 5544850..b5ccdc4 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureSelectorActivity.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/TreasureSelectorActivity.kt
@@ -18,7 +18,7 @@ import pl.marianjureczko.poszukiwacz.activity.commemorative.CommemorativeContrac
import pl.marianjureczko.poszukiwacz.activity.commemorative.CommemorativeInputData
import pl.marianjureczko.poszukiwacz.databinding.ActivityTreasureSelectorBinding
import pl.marianjureczko.poszukiwacz.model.Route
-import pl.marianjureczko.poszukiwacz.model.Treasure
+import pl.marianjureczko.poszukiwacz.model.TreasureDescription
import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
import pl.marianjureczko.poszukiwacz.permissions.ActivityRequirements
import pl.marianjureczko.poszukiwacz.permissions.PermissionActivity
@@ -34,33 +34,35 @@ import pl.marianjureczko.poszukiwacz.shared.XmlHelper
class TreasureSelectorActivity : PermissionActivity(), ActivityTerminator {
private val TAG = javaClass.simpleName
- override fun getCurrentTreasuresProgress(): TreasuresProgress? {
+ override fun getTreasureProgress(): TreasuresProgress? {
return model.progress
}
private lateinit var binding: ActivityTreasureSelectorBinding
private val model: SelectorViewModel by viewModels()
private lateinit var adapter: TreasureProgressAdapter
- private val storageHelper = StorageHelper(this)
- private val photoHelper = PhotoHelper(this, storageHelper)
- private val doPhotoLauncher: ActivityResultLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) { result ->
- if (result) {
- val newPhotoLocation = photoHelper.moveCommemorativePhotoToPermanentLocation()
- model.setCommemorativePhotoOnSelectedTreasureDescription(newPhotoLocation)
- adapter.notifyDataSetChanged()
- Toast.makeText(this, R.string.photo_saved, Toast.LENGTH_SHORT).show()
- } else {
- Toast.makeText(this, R.string.photo_not_saved, Toast.LENGTH_SHORT).show()
+ private val photoHelper = PhotoHelper(this, StorageHelper(this))
+ private val doPhotoLauncher: ActivityResultLauncher =
+ registerForActivityResult(ActivityResultContracts.TakePicture()) { result ->
+ if (result) {
+ val newPhotoLocation = photoHelper.moveCommemorativePhotoToPermanentLocation()
+ model.setCommemorativePhotoOnSelectedTreasureDescription(newPhotoLocation)
+ adapter.notifyDataSetChanged()
+ Toast.makeText(this, R.string.photo_saved, Toast.LENGTH_SHORT).show()
+ } else {
+ Toast.makeText(this, R.string.photo_not_saved, Toast.LENGTH_SHORT).show()
+ }
}
- }
- private val commemorativeLauncher: ActivityResultLauncher = registerForActivityResult(CommemorativeContract()) {}
+ private val commemorativeLauncher: ActivityResultLauncher =
+ registerForActivityResult(CommemorativeContract()) {}
companion object {
const val RESULT_PROGRESS = "pl.marianjureczko.poszukiwacz.activity.treasure_selector_result_progress"
internal const val ROUTE = "pl.marianjureczko.poszukiwacz.activity.route_to_select_from"
internal const val PROGRESS = "pl.marianjureczko.poszukiwacz.activity.route_progress"
internal const val LOCATION = "pl.marianjureczko.poszukiwacz.activity.user_coordinates"
- internal const val TREASURE = "pl.marianjureczko.poszukiwacz.activity.treasure_selector_treasure"
+ internal const val TREASURE_DESCRIPTION =
+ "pl.marianjureczko.poszukiwacz.activity.treasure_selector_treasure_description"
private val xmlHelper = XmlHelper()
}
@@ -79,7 +81,7 @@ class TreasureSelectorActivity : PermissionActivity(), ActivityTerminator {
route = xmlHelper.loadFromString(intent.getStringExtra(ROUTE)!!),
progress = xmlHelper.loadFromString(intent.getStringExtra(PROGRESS)!!),
userLocation = intent.getSerializableExtra(LOCATION) as Coordinates?,
- justFound = intent.getSerializableExtra(TREASURE) as Treasure?
+ justFoundTreasureDescription = intent.getSerializableExtra(TREASURE_DESCRIPTION) as TreasureDescription?
)
adapter = TreasureProgressAdapter(this, model, this, doPhotoLauncher, commemorativeLauncher)
binding.treasuresToSelect.adapter = adapter
@@ -106,16 +108,14 @@ class TreasureSelectorActivity : PermissionActivity(), ActivityTerminator {
}
private fun markTreasureIfFound() =
- model.getJustFound()?.let {
- if (model.treasureIsNotFarAwayFromUser()) {
- model.collect(model.getSelectedTreasure()!!)
- adapter.notifyDataSetChanged()
- val id = model.getSelectedTreasure()!!.id.toString()
- Toast.makeText(this, this.getString(R.string.treasure_marked_as_collected, id), Toast.LENGTH_LONG).show()
- } else {
- //TODO: in case the toast is too quick - https://www.geeksforgeeks.org/display-toast-for-a-specific-time-in-android/
- Toast.makeText(this, R.string.treasure_nor_marked, Toast.LENGTH_LONG).show()
- }
+ if (model.treasureDescriptionHasBeenIdentified()) {
+ val id = model.justFoundTreasureDescription!!.id.toString()
+ Toast.makeText(this, this.getString(R.string.treasure_marked_as_collected, id), Toast.LENGTH_LONG).show()
+ model.justFoundTreasureDescription = null
+ adapter.notifyDataSetChanged()
+ } else {
+ //TODO: in case the toast is too quick - https://www.geeksforgeeks.org/display-toast-for-a-specific-time-in-android/
+ Toast.makeText(this, R.string.treasure_nor_marked, Toast.LENGTH_LONG).show()
}
private fun intentResultWithProgress(): Intent {
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/HunterPath.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/HunterPath.kt
index bcd84be..b9f9bed 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/HunterPath.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/HunterPath.kt
@@ -3,12 +3,21 @@ package pl.marianjureczko.poszukiwacz.model
import org.apache.commons.math3.stat.StatUtils
import org.simpleframework.xml.Element
import org.simpleframework.xml.ElementList
+import org.simpleframework.xml.Root
import pl.marianjureczko.poszukiwacz.activity.searching.LocationCalculator
import pl.marianjureczko.poszukiwacz.activity.treasureselector.Coordinates
import java.io.Serializable
import java.util.Date
-class HunterPath : Serializable {
+@Root
+class HunterPath() : Serializable {
+
+ constructor(routeName: String) : this() {
+ this.routeName = routeName
+ }
+
+ @field:Element
+ lateinit var routeName: String
/**
* Measurements for the next chunk. When te chunk creation criteria are met, the measurements are used to produce the chunk and are remove.
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgress.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgress.kt
index dbed2fa..a3494a2 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgress.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgress.kt
@@ -44,10 +44,6 @@ class TreasuresProgress() : Serializable {
@field:Element(required = false)
var selectedTreasure: TreasureDescription? = null
- /** set is required for restoring state */
- @field:Element
- var hunterPath = HunterPath()
-
fun contains(treasure: Treasure): Boolean =
collectedQrCodes.contains(treasure.id)
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/ActivityWithAdsAndBackButton.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/ActivityWithAdsAndBackButton.kt
index cb31243..d1fce12 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/ActivityWithAdsAndBackButton.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/ActivityWithAdsAndBackButton.kt
@@ -58,8 +58,8 @@ abstract class ActivityWithAdsAndBackButton : AppCompatActivity(), SelectTreasur
val url = this.getString(R.string.help_path)
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
} else if (id == R.id.facebook) {
- if (getCurrentTreasuresProgress() != null) {
- facebookLauncher.launch(FacebookInputData(getCurrentTreasuresProgress()!!))
+ if (getTreasureProgress() != null) {
+ facebookLauncher.launch(createFacebookInputData(getTreasureProgress()!!))
} else {
val progresses = storageHelper.loadAll()
.mapNotNull { route -> storageHelper.loadProgress(route.name) }
@@ -68,7 +68,7 @@ abstract class ActivityWithAdsAndBackButton : AppCompatActivity(), SelectTreasur
Toast.makeText(this, R.string.facebook_nothing_to_share, Toast.LENGTH_SHORT).show()
} else {
if (progresses.size == 1) {
- facebookLauncher.launch(FacebookInputData(progresses[0]))
+ facebookLauncher.launch(createFacebookInputData(progresses[0]))
} else {
SelectTreasureProgressDialog.newInstance(progresses).apply {
show(supportFragmentManager, "SelectTreasureProgressDialog")
@@ -80,16 +80,20 @@ abstract class ActivityWithAdsAndBackButton : AppCompatActivity(), SelectTreasur
return super.onOptionsItemSelected(item)
}
+ private fun createFacebookInputData(treasureProgress: TreasuresProgress): FacebookInputData {
+ return FacebookInputData(storageHelper.loadHunterPath(treasureProgress.routeName), treasureProgress)
+ }
+
override fun onTreasureProgressSelected(routeName: String) {
val progresses = storageHelper.loadProgress(routeName)
if (progresses == null) {
Toast.makeText(this, R.string.facebook_invalid_roote, Toast.LENGTH_SHORT).show()
} else {
- facebookLauncher.launch(FacebookInputData(progresses))
+ facebookLauncher.launch(createFacebookInputData(progresses))
}
}
- protected abstract fun getCurrentTreasuresProgress(): TreasuresProgress?
+ protected abstract fun getTreasureProgress(): TreasuresProgress?
private fun createShareOnFacebookLauncher(): ActivityResultLauncher =
registerForActivityResult(FacebookContract()) { result: FacebookOutputData? ->
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/StorageHelper.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/StorageHelper.kt
index adba42d..2acbbbf 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/StorageHelper.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/StorageHelper.kt
@@ -3,6 +3,7 @@ package pl.marianjureczko.poszukiwacz.shared
import android.content.Context
import android.util.Log
import org.apache.commons.io.IOUtils
+import pl.marianjureczko.poszukiwacz.model.HunterPath
import pl.marianjureczko.poszukiwacz.model.Route
import pl.marianjureczko.poszukiwacz.model.TreasureDescription
import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
@@ -26,6 +27,7 @@ open class StorageHelper(val context: Context) {
companion object {
const val routesDirectory = "/treasures_lists"
const val progressDirectory = "/progress"
+ const val hunterPathsDirectory = "/huner_paths"
}
fun newSoundFile(): String = newFile("sound_", ".3gp")
@@ -34,9 +36,14 @@ open class StorageHelper(val context: Context) {
fun newCommemorativePhotoFile(): String = newFile("commemorativephoto_", ".jpg")
- fun save(bag: TreasuresProgress) {
- val file = getProgressFile(bag.routeName)
- xmlHelper.writeToFile(bag, file)
+ fun save(progress: TreasuresProgress) {
+ val file = getProgressFile(progress.routeName)
+ xmlHelper.writeToFile(progress, file)
+ }
+
+ fun save(hunterPath: HunterPath) {
+ val file = getHunterPathFile(hunterPath.routeName)
+ xmlHelper.writeToFile(hunterPath, file)
}
fun loadProgress(routeName: String): TreasuresProgress? {
@@ -53,6 +60,20 @@ open class StorageHelper(val context: Context) {
}
}
+ fun loadHunterPath(routeName: String): HunterPath? {
+ val file = getHunterPathFile(routeName)
+ return if (file.exists()) {
+ try {
+ xmlHelper.loadHunterPathFromFile(file)
+ } catch (e: Exception) {
+ Log.e(TAG, e.message, e)
+ null
+ }
+ } else {
+ null
+ }
+ }
+
fun save(route: Route) {
val xmlFile = getRouteFile(route.fileName())
xmlHelper.writeToFile(route, xmlFile)
@@ -192,7 +213,14 @@ open class StorageHelper(val context: Context) {
return File("${dir.absolutePath}/$routeName.xml")
}
+ //TODO t: code duplication with getProgressFile (possibly also in save)
+ private fun getHunterPathFile(routeName: String): File {
+ val dir = getHunterPathsDir()
+ return File("${dir.absolutePath}/$routeName.xml")
+ }
+
private fun getProgressDir(): File = getDir(progressDirectory)
+ private fun getHunterPathsDir(): File = getDir(hunterPathsDirectory)
private fun getDir(dirName: String): File {
val dir = File(context.filesDir.absolutePath + dirName)
diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/XmlHelper.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/XmlHelper.kt
index 14cbcc3..54a8763 100644
--- a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/XmlHelper.kt
+++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/XmlHelper.kt
@@ -2,6 +2,7 @@ package pl.marianjureczko.poszukiwacz.shared
import org.simpleframework.xml.Serializer
import org.simpleframework.xml.core.Persister
+import pl.marianjureczko.poszukiwacz.model.HunterPath
import pl.marianjureczko.poszukiwacz.model.Route
import pl.marianjureczko.poszukiwacz.model.TreasuresProgress
import java.io.File
@@ -29,11 +30,18 @@ class XmlHelper {
return serializer.read(T::class.java, xml)
}
- fun writeToFile(bag: TreasuresProgress, outputFile: File) =
- serializer.write(bag, outputFile)
+ fun writeToFile(progress: TreasuresProgress, outputFile: File) =
+ serializer.write(progress, outputFile)
+
+ fun writeToFile(hunterPath: HunterPath, outputFile: File) =
+ serializer.write(hunterPath, outputFile)
fun loadProgressFromFile(xmlFile: File): TreasuresProgress {
val xml = xmlFile.readText()
return serializer.read(TreasuresProgress::class.java, xml)
}
+ fun loadHunterPathFromFile(xmlFile: File): HunterPath {
+ val xml = xmlFile.readText()
+ return serializer.read(HunterPath::class.java, xml)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_result.xml b/app/src/main/res/layout/activity_result.xml
index 1949f5c..c723d98 100644
--- a/app/src/main/res/layout/activity_result.xml
+++ b/app/src/main/res/layout/activity_result.xml
@@ -1,9 +1,10 @@
@@ -11,62 +12,41 @@
android:id="@+id/resultImg"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1.0"
+ android:layout_weight="10.0"
android:gravity="top"
- android:padding="4dp" />
+ android:layout_marginTop="50dp" />
-
-
-
+ android:autoSizeTextType="uniform"
+ android:gravity="center"
+ android:textSize="60dp"
+ android:fontFamily="@font/akaya_telivigala" />
+ android:orientation="horizontal">
-
-
-
-
{
+ val someDescription = some()
+ val someTreasure = some()
+ return listOf(
+ Arguments.of(
+ "SHOULD return null WHEN treasure is null",
+ null,
+ someDescription,
+ some(),
+ 0,
+ null
+ ),
+ Arguments.of(
+ "SHOULD return null WHEN description and coordinates are null",
+ someTreasure,
+ null,
+ null,
+ 0,
+ null
+ ),
+ Arguments.of(
+ "SHOULD return null WHEN only description is null",
+ someTreasure,
+ someDescription,
+ null,
+ 0,
+ null
+ ),
+ Arguments.of(
+ "SHOULD return null WHEN only coordinates is null",
+ someTreasure,
+ null,
+ some(),
+ 0,
+ null
+ ),
+ Arguments.of(
+ "SHOULD return null WHEN description is far away from coordinates",
+ someTreasure,
+ someDescription,
+ some(),
+ 60,
+ null
+ ),
+ Arguments.of(
+ "SHOULD return description WHEN description is close to coordinates",
+ someTreasure,
+ someDescription,
+ some(),
+ 59,
+ someDescription
+ ),
+ )
+ }
+ }
+
+ @Mock
+ lateinit var locationCalculator: LocationCalculator
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("data")
+ fun findTreasureDescription(
+ comment: String,
+ justFoundTreasure: Treasure?,
+ description: TreasureDescription?,
+ userCoordinates: Coordinates?,
+ coordinatesDistance: Int,
+ expected: TreasureDescription?
+ ) {
+ //given
+ justFoundTreasure?.let {
+ description?.let {
+ userCoordinates?.let {
+ BDDMockito.given(locationCalculator.distanceInSteps(description, userCoordinates))
+ .willReturn(coordinatesDistance)
+ }
+ }
+ }
+ val finder = JustFoundFinder(justFoundTreasure, description, userCoordinates, locationCalculator)
+
+ //when
+ val actual = finder.findTreasureDescription()
+
+ //then
+ assertThat(actual).isEqualTo(expected)
+ }
+}
\ No newline at end of file
diff --git a/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModelTest.kt b/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModelTest.kt
index fa6b8a4..fb86a7c 100644
--- a/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModelTest.kt
+++ b/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/searching/SearchingActivityViewModelTest.kt
@@ -6,9 +6,14 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.BDDMockito.given
+import org.mockito.BDDMockito.mockingDetails
+import org.mockito.BDDMockito.reset
import org.mockito.BDDMockito.then
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.junit.jupiter.MockitoExtension
+import org.mockito.verification.VerificationMode
+import pl.marianjureczko.poszukiwacz.model.HunterPath
import pl.marianjureczko.poszukiwacz.model.Route
import pl.marianjureczko.poszukiwacz.model.Treasure
import pl.marianjureczko.poszukiwacz.model.TreasureType
@@ -35,7 +40,7 @@ class SearchingActivityViewModelTest {
//then
assertThat(fixture.model.getRoute()).isEqualTo(fixture.route)
- assertThat(fixture.model.getTreasureBag()).usingRecursiveComparison().isEqualTo(TreasuresProgress(fixture.route.name))
+ assertThat(fixture.model.getProgress()).usingRecursiveComparison().isEqualTo(TreasuresProgress(fixture.route.name))
}
@Test
@@ -43,13 +48,13 @@ class SearchingActivityViewModelTest {
//given
val treasuresProgress = some()
val fixture = SearchingActivityViewModelFixture(state)
- fixture.setupMockForGivenTreasureBag(storageHelper, treasuresProgress)
+ fixture.setupMockForGivenTreasureProgress(storageHelper, treasuresProgress)
//when initialize model (in fixture)
//then
assertThat(fixture.model.getRoute()).isEqualTo(fixture.route)
- assertThat(fixture.model.getTreasureBag()).usingRecursiveComparison().isEqualTo(treasuresProgress)
+ assertThat(fixture.model.getProgress()).usingRecursiveComparison().isEqualTo(treasuresProgress)
}
@Test
@@ -59,25 +64,26 @@ class SearchingActivityViewModelTest {
val treasuresProgress = some()
//when
- model.replaceTreasureBag(treasuresProgress, storageHelper)
+ model.replaceProgress(treasuresProgress, storageHelper)
//then
then(storageHelper).should().save(treasuresProgress)
- assertThat(model.getTreasureBag()).usingRecursiveComparison().isEqualTo(treasuresProgress)
+ assertThat(model.getProgress()).usingRecursiveComparison().isEqualTo(treasuresProgress)
}
@Test
- fun `SHOULD save new treasure bag WHEN collecting next treasure`() {
+ fun `SHOULD save new treasure progress WHEN collecting next treasure`() {
//given
val fixture = SearchingActivityViewModelFixture(state)
fixture.setupMockForEmptyTreasureBag(storageHelper)
val treasure = some().copy(type = TreasureType.DIAMOND)
+ reset(storageHelper)
//when
fixture.model.collectTreasure(treasure, storageHelper)
//then
- then(storageHelper).should().save(fixture.model.getTreasureBag())
+ then(storageHelper).should().save(fixture.model.getProgress())
assertThat(fixture.model.getDiamonds()).isEqualTo(treasure.quantity.toString())
}
@@ -112,7 +118,7 @@ class SearchingActivityViewModelTest {
fun `SHOULD say initialized WHEN the flag is not set ie getTreasureSelectorActivityInputData was never called but selected is set`() {
//given
val fixture = SearchingActivityViewModelFixture(state)
- fixture.setupMockForGivenTreasureBag(storageHelper, some())
+ fixture.setupMockForGivenTreasureProgress(storageHelper, some())
assertThat(fixture.model.getSelectedForHuntTreasure()).isNotNull()
//when
@@ -135,7 +141,7 @@ class SearchingActivityViewModelTest {
fun `SHOULD persist state WHEN getting data from treasure selector launcher TO not reexecute the selection second time`() {
//given
val fixture = SearchingActivityViewModelFixture(state)
- fixture.setupMockForGivenTreasureBag(storageHelper, some())
+ fixture.setupMockForGivenTreasureProgress(storageHelper, some())
assertThat(fixture.model.getSelectedForHuntTreasure()).isNotNull()
//when
@@ -160,7 +166,7 @@ data class SearchingActivityViewModelFixture(
model.initialize(xml, storageHelper)
}
- fun setupMockForGivenTreasureBag(storageHelper: StorageHelper, treasuresProgress: TreasuresProgress) {
+ fun setupMockForGivenTreasureProgress(storageHelper: StorageHelper, treasuresProgress: TreasuresProgress) {
given(storageHelper.loadProgress(route.name))
.willReturn(treasuresProgress)
model.initialize(xml, storageHelper)
@@ -169,4 +175,6 @@ data class SearchingActivityViewModelFixture(
private fun initializeModel(storageHelper: StorageHelper) {
model.initialize(xml, storageHelper)
}
-}
\ No newline at end of file
+}
+
+private fun any(type: Class): T = Mockito.any(type)
\ No newline at end of file
diff --git a/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectorViewModelTest.kt b/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectorViewModelTest.kt
index 1d063b5..6341df8 100644
--- a/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectorViewModelTest.kt
+++ b/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/treasureselector/SelectorViewModelTest.kt
@@ -144,7 +144,7 @@ internal class SelectorViewModelTest {
//given
val model = some()
model.initialize(some(), some(), null, null)
- assertThat(model.getUserLocation()).isNull()
+ assertThat(model.userLocation).isNull()
val treasureDescription = some()
//when
@@ -170,7 +170,7 @@ internal class SelectorViewModelTest {
//then
assertThat(treasureId).isEqualTo(treasureDescription.id)
- assertThat(distanceInSteps).isEqualTo(calculator.distanceInSteps(treasureDescription, model.getUserLocation()!!))
+ assertThat(distanceInSteps).isEqualTo(calculator.distanceInSteps(treasureDescription, model.userLocation!!))
return expected
}
})
diff --git a/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgressArranger.kt b/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgressArranger.kt
index 9ada357..867d7f0 100644
--- a/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgressArranger.kt
+++ b/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasuresProgressArranger.kt
@@ -12,7 +12,7 @@ class TreasuresProgressArranger : CustomArranger() {
instance.collect(treasureDescription)
instance.collect(some())
instance.addCommemorativePhoto(treasureDescription, someString())
- instance.hunterPath.addLocation(Coordinates(some() % 180, some() % 90))
+// instance.hunterPath.addLocation(Coordinates(some() % 180, some() % 90))
return instance
}
}
\ No newline at end of file
diff --git a/docs/development.md b/docs/development.md
index ced74ba..4765008 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -35,6 +35,14 @@ When using gradle directly the token can be delivered as a parameter: `-PMAPBOX_
CapturePhotoIntent --> TreasuresEditorActivity
SearchingActivity --> MapActivity : show map
MapActivity --> SearchingActivity
+ ResultActivity --> CapturePhotoIntent : make commemorative photo
+ CapturePhotoIntent --> ResultActivity
+ ResultActivity --> CommemorativeActivity : show commemorative photo
+ CommemorativeActivity --> ResultActivity
+ TreasureSelectorActivity --> CommemorativeActivity : show commemorative photo
+ CommemorativeActivity --> CapturePhotoIntent : replace\n commemorative photo
+ CapturePhotoIntent --> CommemorativeActivity
+ CommemorativeActivity --> TreasureSelectorActivity
MainActivity --> FacebookActivity
FacebookActivity --> MainActivity
@@ -55,6 +63,7 @@ When using gradle directly the token can be delivered as a parameter: `-PMAPBOX_
MapActivity --> FacebookActivity
FacebookActivity --> MapActivity
+
note right of QrScanIntent: INTENT
note right of CapturePhotoIntent: INTENT
```
@@ -64,8 +73,7 @@ When using gradle directly the token can be delivered as a parameter: `-PMAPBOX_
There are three levels of state persistence.
1. **View Model level.** There is the ViewModel class that allows data to survive configuration changes such as screen rotations. Each stateful activity has a view model class (a
- class
- extending the `ViewModel`).
+ class extending the `ViewModel`).
2. **Saved instance state.** Data saved this way survives system initiated process death (e.g. removing the process due to lack of memory). Saving instance state should be done
through view model. The view model class aggregates an instance of the `SavedStateHandle`. When the data is changed, the view model should