forked from organicmaps/organicmaps
android: Find a way to have map pre-included in the app ✅
This commit is contained in:
parent
b34607bd04
commit
f592cb23dd
8 changed files with 114 additions and 12 deletions
17
README.md
17
README.md
|
@ -1,28 +1,36 @@
|
|||
# Tourism Map Tajikistan
|
||||
|
||||
This app is for Tajikistan tourists. It's based on open source app Organic map.
|
||||
|
||||
## Please Read all of this before continuing
|
||||
|
||||
Don't forget make changes to this file, when you make significant changes to navigation.
|
||||
version of Android Studio I used: android-studio-2024.1.1.13-mac_arm.dmg
|
||||
version of XCode I used: 16.1
|
||||
|
||||
## Navigation on Android
|
||||
|
||||
The first activity app starts is SplashActivity.java. There it navigates to MainActivity
|
||||
where all of the data about Tajikistan places are located,
|
||||
it has its own navigation system on Jetpack compose.
|
||||
There we navigateToMapToDownloadIfNotPresent() and navigateToAuthIfNotAuthed() being called.
|
||||
There we navigateToAuthIfNotAuthed() and then navigateToMapToDownloadIfNotPresent().
|
||||
In AuthActivity we move Tajikistan map to app's internal storage and if it is successful,
|
||||
it won't navigate to map to download.
|
||||
When map download is finished it will go to MainActivity.
|
||||
When you sign in or up, it will navigate to MainActivity
|
||||
When you sign in or up, it will navigate to MainActivity.
|
||||
|
||||
## Navigation on iOS
|
||||
|
||||
The first screen to be shown is Map screen (see MapsAppDelegate.mm). I (Emin) couldn't change it.
|
||||
There's such logic in MapsAppDelegate.mm:
|
||||
There's such logic in MapsAppDelegate.mm:
|
||||
|
||||
```
|
||||
if (Tajikistan is loaded) {
|
||||
if (token is nil) navigate to Auth (note: token is cleared when user signs out)
|
||||
else navigate to TourismMain (Home)
|
||||
}
|
||||
```
|
||||
|
||||
In Auth when user signs in or up, it navigates to TourismMain
|
||||
In TourismMain goes to auth if not authorized
|
||||
|
||||
|
@ -30,7 +38,8 @@ In TourismMain goes to auth if not authorized
|
|||
|
||||
Organic Maps is the ultimate companion app for travellers, tourists, hikers, and cyclists:
|
||||
|
||||
- Detailed offline maps with places that don't exist on other maps, thanks to [OpenStreetMap](https://openstreetmap.org)
|
||||
- Detailed offline maps with places that don't exist on other maps, thanks
|
||||
to [OpenStreetMap](https://openstreetmap.org)
|
||||
- Cycling routes, hiking trails, and walking paths
|
||||
- Contour lines, elevation profiles, peaks, and slopes
|
||||
- Turn-by-turn walking, cycling, and car navigation with voice guidance
|
||||
|
|
BIN
android/app/src/main/assets/tajikistan.mwm
Normal file
BIN
android/app/src/main/assets/tajikistan.mwm
Normal file
Binary file not shown.
|
@ -18,6 +18,7 @@ import app.tourism.data.repositories.PlacesRepository
|
|||
import app.tourism.ui.screens.auth.AuthNavigation
|
||||
import app.tourism.ui.theme.OrganicMapsTheme
|
||||
import app.tourism.utils.LocaleHelper
|
||||
import app.tourism.utils.MapFileMover
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
@ -27,6 +28,9 @@ class AuthActivity : ComponentActivity() {
|
|||
@Inject
|
||||
lateinit var placesRepository: PlacesRepository
|
||||
|
||||
@Inject
|
||||
lateinit var userPreferences: UserPreferences
|
||||
|
||||
override fun attachBaseContext(newBase: Context) {
|
||||
val languageCode = UserPreferences(newBase).getLanguage()?.code
|
||||
super.attachBaseContext(LocaleHelper.localeUpdateResources(newBase, languageCode ?: "ru"))
|
||||
|
@ -36,7 +40,10 @@ class AuthActivity : ComponentActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
lifecycleScope.launch {
|
||||
placesRepository.downloadAllData()
|
||||
if (!userPreferences.getIsEverythingSetup()) {
|
||||
if (!MapFileMover().main(this@AuthActivity)) return@launch
|
||||
userPreferences.setIsEverythingSetup(true)
|
||||
}
|
||||
}
|
||||
|
||||
val blackest = resources.getColor(R.color.button_text) // yes, I know
|
||||
|
|
|
@ -15,6 +15,7 @@ import app.tourism.ui.theme.getBorderColor
|
|||
|
||||
const val TAG = "GLOBAL_TAG"
|
||||
const val BASE_URL = "https://tourismmap.tj"
|
||||
const val DEBUG_BASE_URL = "https://test.tourismmap.tj/"
|
||||
|
||||
object Constants {
|
||||
// UI
|
||||
|
|
|
@ -51,8 +51,8 @@ class MainActivity : ComponentActivity() {
|
|||
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION)
|
||||
registerReceiver(wifiReceiver, intentFilter)
|
||||
|
||||
navigateToMapToDownloadIfNotPresent()
|
||||
navigateToAuthIfNotAuthed()
|
||||
navigateToMapToDownloadIfNotPresent()
|
||||
|
||||
val blackest = resources.getColor(R.color.button_text) // yes, I know
|
||||
enableEdgeToEdge(
|
||||
|
@ -70,10 +70,12 @@ class MainActivity : ComponentActivity() {
|
|||
}
|
||||
|
||||
private fun navigateToMapToDownloadIfNotPresent() {
|
||||
val mCurrentCountry = CountryItem.fill("Tajikistan")
|
||||
if (!mCurrentCountry.present) {
|
||||
val intent = Intent(this, DownloadResourcesLegacyActivity::class.java)
|
||||
startActivity(this, intent, null)
|
||||
if (userPreferences.getIsEverythingSetup()) {
|
||||
val mCurrentCountry = CountryItem.fill("Tajikistan")
|
||||
if (!mCurrentCountry.present) {
|
||||
val intent = Intent(this, DownloadResourcesLegacyActivity::class.java)
|
||||
startActivity(this, intent, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,10 @@ class UserPreferences(context: Context) {
|
|||
fun getUserId() = sharedPref.getString("user_id", "")
|
||||
fun setUserId(value: String?) = sharedPref.edit { putString("user_id", value) }
|
||||
|
||||
fun getIsEverythingSetup() = sharedPref.getBoolean("is_everything_setup", false)
|
||||
fun setIsEverythingSetup(value: Boolean) =
|
||||
sharedPref.edit { putBoolean("is_everything_setup", value) }
|
||||
|
||||
fun getShouldSyncLanguage() = sharedPref.getBoolean("should_sync_language", false)
|
||||
fun setShouldSyncLanguage(value: Boolean) =
|
||||
sharedPref.edit { putBoolean("should_sync_language", value) }
|
||||
|
|
|
@ -10,11 +10,14 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import app.organicmaps.downloader.CountryItem
|
||||
import app.tourism.MainActivity
|
||||
import app.tourism.data.prefs.UserPreferences
|
||||
import app.tourism.ui.screens.auth.sign_in.SignInScreen
|
||||
import app.tourism.ui.screens.auth.sign_up.SignUpScreen
|
||||
import app.tourism.ui.screens.auth.welcome.WelcomeScreen
|
||||
import app.tourism.ui.screens.language.LanguageScreen
|
||||
import com.jakewharton.processphoenix.ProcessPhoenix
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
// Routes
|
||||
|
@ -57,7 +60,7 @@ fun AuthNavigation() {
|
|||
composable<SignIn> {
|
||||
SignInScreen(
|
||||
onSignInComplete = {
|
||||
navigateToMainActivity(context)
|
||||
afterSuccessfulSignIn(context)
|
||||
},
|
||||
onBackClick = navigateUp
|
||||
)
|
||||
|
@ -65,7 +68,7 @@ fun AuthNavigation() {
|
|||
composable<SignUp> {
|
||||
SignUpScreen(
|
||||
onSignUpComplete = {
|
||||
navigateToMainActivity(context)
|
||||
afterSuccessfulSignIn(context)
|
||||
},
|
||||
onBackClick = navigateUp
|
||||
)
|
||||
|
@ -78,6 +81,18 @@ fun AuthNavigation() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun afterSuccessfulSignIn(context: Context) {
|
||||
val userPreferences = UserPreferences(context)
|
||||
val mCurrentCountry = CountryItem.fill("Tajikistan")
|
||||
|
||||
// well country should be there already, but mCurrentCountry.present will be false,
|
||||
// after rebirth it should be present
|
||||
if (!mCurrentCountry.present && userPreferences.getIsEverythingSetup())
|
||||
ProcessPhoenix.triggerRebirth(context)
|
||||
else
|
||||
navigateToMainActivity(context)
|
||||
}
|
||||
|
||||
fun navigateToMainActivity(context: Context) {
|
||||
val intent = Intent(context, MainActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
|
64
android/app/src/main/java/app/tourism/utils/MapFileMover.kt
Normal file
64
android/app/src/main/java/app/tourism/utils/MapFileMover.kt
Normal file
|
@ -0,0 +1,64 @@
|
|||
package app.tourism.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import app.organicmaps.BuildConfig
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
|
||||
private const val TAG = "MapFileMover"
|
||||
|
||||
private const val SOURCE_FILE_NAME = "tajikistan.mwm"
|
||||
private const val SOURCE_FILE_NEW_NAME = "Tajikistan.mwm"
|
||||
|
||||
class MapFileMover {
|
||||
|
||||
private fun moveFile(context: Context, destinationPath: String): Boolean {
|
||||
return try {
|
||||
val destinationFile = File(destinationPath, SOURCE_FILE_NEW_NAME)
|
||||
|
||||
val inputStream = BufferedInputStream(context.assets.open(SOURCE_FILE_NAME))
|
||||
val outputStream = BufferedOutputStream(FileOutputStream(destinationFile))
|
||||
|
||||
val buffer = ByteArray(1024)
|
||||
var read: Int
|
||||
while (inputStream.read(buffer).also { read = it } != -1) {
|
||||
outputStream.write(buffer, 0, read)
|
||||
}
|
||||
|
||||
inputStream.close()
|
||||
outputStream.flush()
|
||||
outputStream.close()
|
||||
|
||||
Log.d(TAG, "File moved successfully to: ${destinationFile.absolutePath}")
|
||||
|
||||
true
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
Log.e(TAG, "Error moving file: ${e.message}")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun main(context: Context): Boolean {
|
||||
val higherPath = "/storage/emulated/0/Android/data/tj.tourism.rebus"
|
||||
val lowerPath = "/files/240429/"
|
||||
var destinationPath = higherPath + lowerPath
|
||||
if (BuildConfig.BUILD_TYPE == "debug") {
|
||||
destinationPath = higherPath + ".debug" + lowerPath
|
||||
}
|
||||
|
||||
val destinationDir = File(destinationPath)
|
||||
if (!destinationDir.exists()) {
|
||||
if (!destinationDir.mkdirs()) {
|
||||
Log.e(TAG, "Failed to create destination directory.")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return moveFile(context, destinationPath)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue