Skip to content

Commit bd54613

Browse files
committed
Create tool for field guide
Signed-off-by: Kyle Corry <kylecorry31@gmail.com>
1 parent 2c2fec6 commit bd54613

File tree

18 files changed

+198
-158
lines changed

18 files changed

+198
-158
lines changed
Lines changed: 0 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,14 @@
11
package com.kylecorry.trail_sense.tools.experimentation
22

3-
import android.graphics.Bitmap
4-
import android.os.Bundle
5-
import android.util.Size
63
import android.view.LayoutInflater
7-
import android.view.View
84
import android.view.ViewGroup
9-
import android.widget.ImageView
10-
import com.kylecorry.andromeda.alerts.dialog
11-
import com.kylecorry.andromeda.core.coroutines.BackgroundMinimumState
12-
import com.kylecorry.andromeda.core.coroutines.onIO
13-
import com.kylecorry.andromeda.core.system.Resources
145
import com.kylecorry.andromeda.fragments.BoundFragment
15-
import com.kylecorry.andromeda.fragments.inBackground
16-
import com.kylecorry.andromeda.views.list.AsyncListIcon
17-
import com.kylecorry.andromeda.views.list.ListItem
186
import com.kylecorry.trail_sense.databinding.FragmentExperimentationBinding
19-
import com.kylecorry.trail_sense.shared.io.DeleteTempFilesCommand
20-
import com.kylecorry.trail_sense.shared.io.FileSubsystem
21-
import com.kylecorry.trail_sense.shared.views.Views
22-
import com.kylecorry.trail_sense.tools.species_catalog.BuiltInFieldGuide
23-
import com.kylecorry.trail_sense.tools.species_catalog.FieldGuidePage
24-
import com.kylecorry.trail_sense.tools.species_catalog.FieldGuidePageTag
257

268
class ExperimentationFragment : BoundFragment<FragmentExperimentationBinding>() {
27-
28-
private var species by state<List<FieldGuidePage>>(emptyList())
29-
private var filter by state("")
30-
private val importer by lazy { SpeciesImportService.create(this) }
31-
private val files by lazy { FileSubsystem.getInstance(requireContext()) }
32-
33-
private suspend fun loadFromAssets(): List<FieldGuidePage> {
34-
return BuiltInFieldGuide.getFieldGuide(requireContext())
35-
}
36-
379
override fun generateBinding(
3810
layoutInflater: LayoutInflater, container: ViewGroup?
3911
): FragmentExperimentationBinding {
4012
return FragmentExperimentationBinding.inflate(layoutInflater, container, false)
4113
}
42-
43-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
44-
super.onViewCreated(view, savedInstanceState)
45-
inBackground(BackgroundMinimumState.Created) {
46-
val tagOrder = listOf(
47-
FieldGuidePageTag.Plant,
48-
FieldGuidePageTag.Fungus,
49-
FieldGuidePageTag.Mammal,
50-
FieldGuidePageTag.Bird,
51-
FieldGuidePageTag.Reptile,
52-
FieldGuidePageTag.Amphibian,
53-
FieldGuidePageTag.Fish,
54-
FieldGuidePageTag.Insect,
55-
FieldGuidePageTag.Arachnid,
56-
FieldGuidePageTag.Crustacean,
57-
FieldGuidePageTag.Mollusk,
58-
)
59-
species = loadFromAssets().sortedWith(
60-
compareBy(
61-
{
62-
it.tags.minOfOrNull { tag ->
63-
val order = tagOrder.indexOf(tag)
64-
if (order == -1) tagOrder.size else order
65-
}
66-
},
67-
{ it.name })
68-
)
69-
}
70-
71-
binding.search.setOnSearchListener {
72-
filter = it
73-
}
74-
}
75-
76-
override fun onUpdate() {
77-
super.onUpdate()
78-
effect2(species, filter, lifecycleHookTrigger.onResume()) {
79-
val filteredSpecies = species.filter {
80-
it.name.lowercase().contains(filter.trim()) || it.tags.any { tag ->
81-
tag.name.lowercase().contains(filter.trim())
82-
}
83-
}
84-
85-
binding.list.setItems(filteredSpecies.map {
86-
val firstSentence = it.notes?.substringBefore(".")?.plus(".") ?: ""
87-
ListItem(
88-
it.id,
89-
it.name,
90-
it.tags.joinToString(", ") + "\n\n" + firstSentence.take(200),
91-
icon = AsyncListIcon(
92-
viewLifecycleOwner,
93-
{ loadThumbnail(it) },
94-
size = 48f,
95-
scaleType = ImageView.ScaleType.CENTER_CROP,
96-
clearOnPause = true
97-
),
98-
) {
99-
dialog(
100-
it.name,
101-
it.notes ?: "",
102-
allowLinks = true,
103-
contentView = Views.image(
104-
requireContext(),
105-
files.drawable(it.images.first()),
106-
width = ViewGroup.LayoutParams.MATCH_PARENT,
107-
height = Resources.dp(requireContext(), 200f).toInt()
108-
),
109-
scrollable = true
110-
)
111-
}
112-
})
113-
}
114-
}
115-
116-
private suspend fun loadThumbnail(species: FieldGuidePage): Bitmap = onIO {
117-
val size = Resources.dp(requireContext(), 48f).toInt()
118-
try {
119-
files.bitmap(species.images.first(), Size(size, size)) ?: getDefaultThumbnail()
120-
} catch (e: Exception) {
121-
getDefaultThumbnail()
122-
}
123-
}
124-
125-
private fun getDefaultThumbnail(): Bitmap {
126-
val size = Resources.dp(requireContext(), 48f).toInt()
127-
return Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
128-
}
129-
130-
override fun onDestroy() {
131-
super.onDestroy()
132-
inBackground {
133-
DeleteTempFilesCommand(requireContext()).execute()
134-
}
135-
}
13614
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.kylecorry.trail_sense.tools.field_guide
2+
3+
import android.content.Context
4+
import com.kylecorry.trail_sense.R
5+
import com.kylecorry.trail_sense.shared.debugging.isDebug
6+
import com.kylecorry.trail_sense.tools.tools.infrastructure.Tool
7+
import com.kylecorry.trail_sense.tools.tools.infrastructure.ToolCategory
8+
import com.kylecorry.trail_sense.tools.tools.infrastructure.ToolRegistration
9+
import com.kylecorry.trail_sense.tools.tools.infrastructure.Tools
10+
11+
object FieldGuideToolRegistration : ToolRegistration {
12+
override fun getTool(context: Context): Tool {
13+
return Tool(
14+
Tools.FIELD_GUIDE,
15+
context.getString(R.string.field_guide),
16+
R.drawable.survival_guide,
17+
R.id.fieldGuideFragment,
18+
ToolCategory.Books,
19+
isExperimental = true,
20+
isAvailable = { isDebug() }
21+
)
22+
}
23+
}

app/src/main/java/com/kylecorry/trail_sense/tools/species_catalog/FieldGuidePage.kt renamed to app/src/main/java/com/kylecorry/trail_sense/tools/field_guide/domain/FieldGuidePage.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.kylecorry.trail_sense.tools.species_catalog
1+
package com.kylecorry.trail_sense.tools.field_guide.domain
22

33
import com.kylecorry.trail_sense.shared.data.Identifiable
44

app/src/main/java/com/kylecorry/trail_sense/tools/species_catalog/FieldGuidePageTag.kt renamed to app/src/main/java/com/kylecorry/trail_sense/tools/field_guide/domain/FieldGuidePageTag.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.kylecorry.trail_sense.tools.species_catalog
1+
package com.kylecorry.trail_sense.tools.field_guide.domain
22

33
import com.kylecorry.trail_sense.shared.data.Identifiable
44

app/src/main/java/com/kylecorry/trail_sense/tools/species_catalog/Sighting.kt renamed to app/src/main/java/com/kylecorry/trail_sense/tools/field_guide/domain/Sighting.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.kylecorry.trail_sense.tools.species_catalog
1+
package com.kylecorry.trail_sense.tools.field_guide.domain
22

33
import com.kylecorry.sol.units.Coordinate
44
import java.time.ZonedDateTime

app/src/main/java/com/kylecorry/trail_sense/tools/species_catalog/BuiltInFieldGuide.kt renamed to app/src/main/java/com/kylecorry/trail_sense/tools/field_guide/infrastructure/BuiltInFieldGuide.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
package com.kylecorry.trail_sense.tools.species_catalog
1+
package com.kylecorry.trail_sense.tools.field_guide.infrastructure
22

33
import android.content.Context
44
import com.kylecorry.trail_sense.R
55
import com.kylecorry.trail_sense.shared.text.TextUtils
6+
import com.kylecorry.trail_sense.tools.field_guide.domain.FieldGuidePage
7+
import com.kylecorry.trail_sense.tools.field_guide.domain.FieldGuidePageTag
68

79
object BuiltInFieldGuide {
810

app/src/main/java/com/kylecorry/trail_sense/tools/experimentation/SpeciesImportService.kt renamed to app/src/main/java/com/kylecorry/trail_sense/tools/field_guide/infrastructure/SpeciesImportService.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.kylecorry.trail_sense.tools.experimentation
1+
package com.kylecorry.trail_sense.tools.field_guide.infrastructure
22

33
import com.kylecorry.andromeda.files.ZipUtils
44
import com.kylecorry.andromeda.fragments.AndromedaFragment
@@ -11,8 +11,8 @@ import com.kylecorry.trail_sense.shared.io.IntentUriPicker
1111
import com.kylecorry.trail_sense.shared.io.UriPicker
1212
import com.kylecorry.trail_sense.shared.io.UriService
1313
import com.kylecorry.trail_sense.shared.withId
14-
import com.kylecorry.trail_sense.tools.species_catalog.FieldGuidePage
15-
import com.kylecorry.trail_sense.tools.species_catalog.FieldGuidePageTag
14+
import com.kylecorry.trail_sense.tools.field_guide.domain.FieldGuidePage
15+
import com.kylecorry.trail_sense.tools.field_guide.domain.FieldGuidePageTag
1616
import java.io.InputStream
1717
import java.util.Base64
1818

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package com.kylecorry.trail_sense.tools.field_guide.ui
2+
3+
import android.graphics.Bitmap
4+
import android.os.Bundle
5+
import android.util.Size
6+
import android.view.LayoutInflater
7+
import android.view.View
8+
import android.view.ViewGroup
9+
import android.widget.ImageView
10+
import com.kylecorry.andromeda.alerts.dialog
11+
import com.kylecorry.andromeda.core.coroutines.BackgroundMinimumState
12+
import com.kylecorry.andromeda.core.coroutines.onIO
13+
import com.kylecorry.andromeda.core.system.Resources
14+
import com.kylecorry.andromeda.fragments.BoundFragment
15+
import com.kylecorry.andromeda.fragments.inBackground
16+
import com.kylecorry.andromeda.views.list.AsyncListIcon
17+
import com.kylecorry.andromeda.views.list.ListItem
18+
import com.kylecorry.trail_sense.databinding.FragmentFieldGuideBinding
19+
import com.kylecorry.trail_sense.shared.io.DeleteTempFilesCommand
20+
import com.kylecorry.trail_sense.shared.io.FileSubsystem
21+
import com.kylecorry.trail_sense.shared.views.Views
22+
import com.kylecorry.trail_sense.tools.field_guide.domain.FieldGuidePage
23+
import com.kylecorry.trail_sense.tools.field_guide.domain.FieldGuidePageTag
24+
import com.kylecorry.trail_sense.tools.field_guide.infrastructure.BuiltInFieldGuide
25+
26+
class FieldGuideFragment : BoundFragment<FragmentFieldGuideBinding>() {
27+
28+
private var species by state<List<FieldGuidePage>>(emptyList())
29+
private var filter by state("")
30+
private val files by lazy { FileSubsystem.getInstance(requireContext()) }
31+
32+
private fun loadFromAssets(): List<FieldGuidePage> {
33+
return BuiltInFieldGuide.getFieldGuide(requireContext())
34+
}
35+
36+
override fun generateBinding(
37+
layoutInflater: LayoutInflater, container: ViewGroup?
38+
): FragmentFieldGuideBinding {
39+
return FragmentFieldGuideBinding.inflate(layoutInflater, container, false)
40+
}
41+
42+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
43+
super.onViewCreated(view, savedInstanceState)
44+
inBackground(BackgroundMinimumState.Created) {
45+
val tagOrder = listOf(
46+
FieldGuidePageTag.Plant,
47+
FieldGuidePageTag.Fungus,
48+
FieldGuidePageTag.Mammal,
49+
FieldGuidePageTag.Bird,
50+
FieldGuidePageTag.Reptile,
51+
FieldGuidePageTag.Amphibian,
52+
FieldGuidePageTag.Fish,
53+
FieldGuidePageTag.Insect,
54+
FieldGuidePageTag.Arachnid,
55+
FieldGuidePageTag.Crustacean,
56+
FieldGuidePageTag.Mollusk,
57+
)
58+
species = loadFromAssets().sortedWith(
59+
compareBy(
60+
{
61+
it.tags.minOfOrNull { tag ->
62+
val order = tagOrder.indexOf(tag)
63+
if (order == -1) tagOrder.size else order
64+
}
65+
},
66+
{ it.name })
67+
)
68+
}
69+
70+
binding.search.setOnSearchListener {
71+
filter = it
72+
}
73+
}
74+
75+
override fun onUpdate() {
76+
super.onUpdate()
77+
effect2(species, filter, lifecycleHookTrigger.onResume()) {
78+
val filteredSpecies = species.filter {
79+
it.name.lowercase().contains(filter.trim()) || it.tags.any { tag ->
80+
tag.name.lowercase().contains(filter.trim())
81+
}
82+
}
83+
84+
binding.list.setItems(filteredSpecies.map {
85+
val firstSentence = it.notes?.substringBefore(".")?.plus(".") ?: ""
86+
ListItem(
87+
it.id,
88+
it.name,
89+
it.tags.joinToString(", ") + "\n\n" + firstSentence.take(200),
90+
icon = AsyncListIcon(
91+
viewLifecycleOwner,
92+
{ loadThumbnail(it) },
93+
size = 48f,
94+
scaleType = ImageView.ScaleType.CENTER_CROP,
95+
clearOnPause = true
96+
),
97+
) {
98+
dialog(
99+
it.name,
100+
it.notes ?: "",
101+
allowLinks = true,
102+
contentView = Views.image(
103+
requireContext(),
104+
files.drawable(it.images.first()),
105+
width = ViewGroup.LayoutParams.MATCH_PARENT,
106+
height = Resources.dp(requireContext(), 200f).toInt()
107+
),
108+
scrollable = true
109+
)
110+
}
111+
})
112+
}
113+
}
114+
115+
private suspend fun loadThumbnail(species: FieldGuidePage): Bitmap = onIO {
116+
val size = Resources.dp(requireContext(), 48f).toInt()
117+
try {
118+
files.bitmap(species.images.first(), Size(size, size)) ?: getDefaultThumbnail()
119+
} catch (e: Exception) {
120+
getDefaultThumbnail()
121+
}
122+
}
123+
124+
private fun getDefaultThumbnail(): Bitmap {
125+
val size = Resources.dp(requireContext(), 48f).toInt()
126+
return Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
127+
}
128+
129+
override fun onDestroy() {
130+
super.onDestroy()
131+
inBackground {
132+
DeleteTempFilesCommand(requireContext()).execute()
133+
}
134+
}
135+
}

app/src/main/java/com/kylecorry/trail_sense/tools/guide/UserGuideToolRegistration.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ object UserGuideToolRegistration : ToolRegistration {
1616
context.getString(R.string.tool_user_guide_title),
1717
R.drawable.ic_user_guide,
1818
R.id.guideListFragment,
19-
ToolCategory.Other,
19+
ToolCategory.Books,
2020
context.getString(R.string.tool_user_guide_summary),
2121
additionalNavigationIds = listOf(
2222
R.id.guideFragment

app/src/main/java/com/kylecorry/trail_sense/tools/species_catalog/Habitat.kt

Lines changed: 0 additions & 16 deletions
This file was deleted.

app/src/main/java/com/kylecorry/trail_sense/tools/survival_guide/SurvivalGuideToolRegistration.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ object SurvivalGuideToolRegistration : ToolRegistration {
1414
context.getString(R.string.survival_guide),
1515
R.drawable.survival_guide,
1616
R.id.fragmentToolSurvivalGuideList,
17-
ToolCategory.Other,
17+
ToolCategory.Books,
1818
guideId = R.raw.guide_tool_survival_guide,
1919
additionalNavigationIds = listOf(R.id.fragmentToolSurvivalGuideReader)
2020
)

app/src/main/java/com/kylecorry/trail_sense/tools/tools/infrastructure/ToolCategory.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ enum class ToolCategory {
99
Power,
1010
Weather,
1111
Communication,
12+
Books,
1213
Other
1314
}

0 commit comments

Comments
 (0)