diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomInitializerForRoute.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomInitializerForRoute.kt new file mode 100644 index 0000000..4326c80 --- /dev/null +++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomInitializerForRoute.kt @@ -0,0 +1,64 @@ +package pl.marianjureczko.poszukiwacz.activity.main + +import android.content.res.AssetManager +import pl.marianjureczko.poszukiwacz.shared.StorageHelper +import java.io.File +import java.io.FileOutputStream +import java.io.InputStream + +class CustomInitializerForRoute( + val storageHelper: StorageHelper, + val assetManager: AssetManager +) { + companion object { + const val routeName = "custom" + } + private val markerFile = "copied_marker.txt" + private val pathToDestination = storageHelper.pathToRoutesDir() + File.separator + fun copyRouteToLocalStorage() { + if (!isAlreadyCopied()) { + copyRouteDefinition() + copyPhotosAndSounds() + markIsCopied() + } + } + + private fun copyRouteDefinition() { + val inputStream = assetManager.open("$routeName.xml") + copy(inputStream, storageHelper.getRouteFile(routeName)) + } + + private fun copyPhotosAndSounds() { + val route = storageHelper.loadRoute(routeName) + route.treasures.forEach { td -> + td.photoFileName?.let { photoFileName -> + val inputToPhoto = assetManager.open(photoFileName) + copy(inputToPhoto, File(pathToDestination + photoFileName)) + td.photoFileName = pathToDestination + photoFileName + } + td.tipFileName?.let { soundFileName -> + val inputToSound = assetManager.open(soundFileName) + copy(inputToSound, File(pathToDestination + soundFileName)) + td.tipFileName = pathToDestination + soundFileName + } + } + storageHelper.save(route) + } + + private fun isAlreadyCopied(): Boolean { + return File(pathToDestination + markerFile).exists() + } + + private fun markIsCopied() { + File(pathToDestination + markerFile).createNewFile() + } + + private fun copy(inputStream: InputStream, outputFile: File) { + val outputStream = FileOutputStream(outputFile) + inputStream.use { input -> + outputStream.use { output -> + input.copyTo(output) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModel.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModel.kt index daa2930..eff1c63 100644 --- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModel.kt +++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModel.kt @@ -4,15 +4,26 @@ import android.content.res.Resources import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class CustomMainViewModel @Inject constructor( - resources: Resources + resources: Resources, + dispatcher: CoroutineDispatcher, + customInitializerForRoute: CustomInitializerForRoute ) : ViewModel() { private var _state = mutableStateOf(CustomMainState(resources)) + init { + viewModelScope.launch(dispatcher) { + customInitializerForRoute.copyRouteToLocalStorage() + } + } + val state: State get() = _state diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomScreenBody.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomScreenBody.kt index de27486..0773e0b 100644 --- a/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomScreenBody.kt +++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/activity/main/CustomScreenBody.kt @@ -81,7 +81,7 @@ fun CustomScreenBody(resources: Resources, goToSearching: (String) -> Unit) { .background(PrimaryBackground) ) LargeButton(R.string.custom_lets_start) { - goToSearching.invoke("1") //TODO use real name + goToSearching.invoke(CustomInitializerForRoute.routeName) } AdvertBanner() } diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/Treasure.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/Treasure.kt index 8f60e59..7ab2209 100644 --- a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/Treasure.kt +++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/Treasure.kt @@ -24,6 +24,7 @@ enum class TreasureType { "g" -> GOLD "r" -> RUBY "d" -> DIAMOND + "k" -> KNOWLEDGE else -> throw IllegalArgumentException("$code is not valid treasure type") } @@ -40,12 +41,13 @@ data class Treasure(val id: String, val quantity: Int, val type: TreasureType) : } class TreasureParser { - fun parse(content: String): Treasure = - Treasure( - content.substring(3), - content.substring(1, 3).toInt(), - TreasureType.from( - content.substring(0, 1) - ) - ) + fun parse(content: String): Treasure { + val type = TreasureType.from(content.substring(0, 1)) + val quantity = if (type == TreasureType.KNOWLEDGE) { + 1 + } else { + content.substring(1, 3).toInt() + } + return Treasure(content.substring(3), quantity, type) + } } \ No newline at end of file diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasureDescription.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasureDescription.kt index f43fcd6..4ab339a 100644 --- a/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasureDescription.kt +++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/model/TreasureDescription.kt @@ -13,10 +13,11 @@ data class TreasureDescription( @field:Element var longitude: Double, @field:Element(required = false) var qrCode: String?, @field:Element(required = false) var tipFileName: String?, - @field:Element(required = false) var photoFileName: String? + @field:Element(required = false) var photoFileName: String?, + @field:Element(required = false) var movieFileName: String? ) : Serializable { - constructor(id: Int, latitude: Double, longitude: Double) : this(id, latitude, longitude, null, null, null) - constructor() : this(0, 0.0, 0.0, null, null, null) + constructor(id: Int, latitude: Double, longitude: Double) : this(id, latitude, longitude, null, null, null, null) + constructor() : this(0, 0.0, 0.0, null, null, null, null) fun prettyName(): String = "[$id] $latitude $longitude" 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 516523d..9c6ea4c 100644 --- a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/StorageHelper.kt +++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/StorageHelper.kt @@ -198,7 +198,7 @@ open class StorageHelper(val context: Context) { getRoutesDir().absolutePath + File.separator + prefix + UUID.randomUUID().toString() + extension //TODO: what about invalid characters in name? - private fun getRouteFile(routeName: String): File = getFile(getRoutesDir(), routeName) + fun getRouteFile(routeName: String): File = getFile(getRoutesDir(), routeName) private fun getProgressFile(routeName: String): File = getFile(getProgressDir(), routeName) diff --git a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/di/SingletonModule.kt b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/di/SingletonModule.kt index f5057a7..062f791 100644 --- a/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/di/SingletonModule.kt +++ b/app/src/main/java/pl/marianjureczko/poszukiwacz/shared/di/SingletonModule.kt @@ -1,6 +1,7 @@ package pl.marianjureczko.poszukiwacz.shared.di import android.content.Context +import android.content.res.AssetManager import android.content.res.Resources import dagger.Module import dagger.Provides @@ -9,6 +10,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import pl.marianjureczko.poszukiwacz.activity.main.CustomInitializerForRoute import pl.marianjureczko.poszukiwacz.activity.searching.LocationCalculator import pl.marianjureczko.poszukiwacz.activity.searching.n.LocationFetcher import pl.marianjureczko.poszukiwacz.shared.PhotoHelper @@ -20,8 +22,20 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) object SingletonModule { + @Singleton + @Provides + fun assetManager(@ApplicationContext appContext: Context): AssetManager { + return appContext.assets + } + + @Singleton + @Provides + fun customInitializerForRoute(storageHelper: StorageHelper, assetManager: AssetManager): CustomInitializerForRoute { + return CustomInitializerForRoute(storageHelper, assetManager) + } + @Provides - fun providesDispatcher(): CoroutineDispatcher = Dispatchers.IO + fun dispatcher(): CoroutineDispatcher = Dispatchers.IO @Singleton @Provides @@ -37,8 +51,8 @@ object SingletonModule { @Singleton @Provides - fun settings(@ApplicationContext appContext: Context): Settings { - return Settings(appContext.assets) + fun settings(assetManager: AssetManager): Settings { + return Settings(assetManager) } @Singleton diff --git a/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModelTest.kt b/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModelTest.kt index d1952ef..1503858 100644 --- a/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModelTest.kt +++ b/app/src/test/java/pl/marianjureczko/poszukiwacz/activity/main/CustomMainViewModelTest.kt @@ -2,6 +2,8 @@ package pl.marianjureczko.poszukiwacz.activity.main import android.content.res.Resources import com.ocadotechnology.gembus.test.someString +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestDispatcher import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -12,9 +14,15 @@ import org.mockito.junit.jupiter.MockitoExtension @ExtendWith(MockitoExtension::class) class CustomMainViewModelTest { + + private val dispatcher: TestDispatcher = StandardTestDispatcher() + @Mock private lateinit var resources: Resources + @Mock + private lateinit var customInitializerForRoute: CustomInitializerForRoute + @BeforeEach fun setupMock() { BDDMockito.given(resources.getString(BDDMockito.anyInt())) @@ -24,7 +32,7 @@ class CustomMainViewModelTest { @Test fun `SHOULD increase message index WHEN calling next message`() { //given - val viewModel = CustomMainViewModel(resources) + val viewModel = CustomMainViewModel(resources, dispatcher, customInitializerForRoute) assertThat(viewModel.state.value.messageIndex).isEqualTo(0) //when diff --git a/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasureParserTest.kt b/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasureParserTest.kt index ad1084a..5902ee7 100644 --- a/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasureParserTest.kt +++ b/app/src/test/java/pl/marianjureczko/poszukiwacz/model/TreasureParserTest.kt @@ -1,5 +1,6 @@ package pl.marianjureczko.poszukiwacz.model +import com.ocadotechnology.gembus.test.somePositiveInt import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @@ -54,6 +55,22 @@ class TreasureParserTest { assertEquals(id, actual.id) } + @Test + fun parseKnowledge() { + //given + val type = "k" + val quantity = somePositiveInt(9) + val id = "a11" + + //when + val actual = TreasureParser().parse("${type}9$quantity$id") + + //then + assertEquals(TreasureType.KNOWLEDGE, actual.type) + assertEquals(1, actual.quantity) + assertEquals(id, actual.id) + } + @Test fun parseInvalidTreasureType() { assertThatThrownBy { TreasureParser().parse("x01id") } diff --git a/assets/classic/config.properties b/assets/classic/assets/config.properties similarity index 100% rename from assets/classic/config.properties rename to assets/classic/assets/config.properties diff --git a/assets/kalinowice/assets/custom.xml b/assets/kalinowice/assets/custom.xml new file mode 100644 index 0000000..d701517 --- /dev/null +++ b/assets/kalinowice/assets/custom.xml @@ -0,0 +1,22 @@ + + custom + + + 1 + 50.501055 + 18.180191 + photo_3035c809-d834-4dc6-a7ef-c8a0b670b945.jpg + sound_ddaa89a4-2925-45a1-a5a1-93f72c04aeff.3gp + k01abc + kalinowice_01.mp4 + + + 2 + 50.505667 + 18.185020 + photo_2185c623-ef91-4e00-b1fc-3c6d4082d1be.jpg + sound_72686712-ceb1-40b6-a420-2d4016bf3872.3gp + kalinowice_01.mp4 + + + \ No newline at end of file diff --git a/assets/kalinowice/assets/kalinowice_01.mp4 b/assets/kalinowice/assets/kalinowice_01.mp4 new file mode 100644 index 0000000..4f87a8f Binary files /dev/null and b/assets/kalinowice/assets/kalinowice_01.mp4 differ diff --git a/assets/kalinowice/assets/photo_2185c623-ef91-4e00-b1fc-3c6d4082d1be.jpg b/assets/kalinowice/assets/photo_2185c623-ef91-4e00-b1fc-3c6d4082d1be.jpg new file mode 100644 index 0000000..785c1e2 Binary files /dev/null and b/assets/kalinowice/assets/photo_2185c623-ef91-4e00-b1fc-3c6d4082d1be.jpg differ diff --git a/assets/kalinowice/assets/photo_3035c809-d834-4dc6-a7ef-c8a0b670b945.jpg b/assets/kalinowice/assets/photo_3035c809-d834-4dc6-a7ef-c8a0b670b945.jpg new file mode 100644 index 0000000..994abee Binary files /dev/null and b/assets/kalinowice/assets/photo_3035c809-d834-4dc6-a7ef-c8a0b670b945.jpg differ diff --git a/assets/kalinowice/assets/sound_72686712-ceb1-40b6-a420-2d4016bf3872.3gp b/assets/kalinowice/assets/sound_72686712-ceb1-40b6-a420-2d4016bf3872.3gp new file mode 100644 index 0000000..c92cbb8 Binary files /dev/null and b/assets/kalinowice/assets/sound_72686712-ceb1-40b6-a420-2d4016bf3872.3gp differ diff --git a/assets/kalinowice/assets/sound_ddaa89a4-2925-45a1-a5a1-93f72c04aeff.3gp b/assets/kalinowice/assets/sound_ddaa89a4-2925-45a1-a5a1-93f72c04aeff.3gp new file mode 100644 index 0000000..6fd83e0 Binary files /dev/null and b/assets/kalinowice/assets/sound_ddaa89a4-2925-45a1-a5a1-93f72c04aeff.3gp differ diff --git a/build.gradle b/build.gradle index be7e412..0ad37d3 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,7 @@ tasks.register('copy_splash', Copy) { } tasks.register('copy_properties', Copy) { - from layout.getProjectDirectory().file("assets/${findProperty('config_src')}/config.properties") + from layout.getProjectDirectory().file("assets/${findProperty('config_src')}/assets") into layout.getProjectDirectory().dir("app/src/main/assets") } copy_config.finalizedBy copy_splash