set up themes, localization, auth UI

This commit is contained in:
Emin 2024-06-15 00:29:23 +05:00
parent 58b81266e8
commit c3c3736f07
49 changed files with 2120 additions and 492 deletions

View file

@ -55,6 +55,9 @@ apply plugin: 'com.github.triplet.play'
apply plugin: 'ru.cian.huawei-publish-gradle-plugin'
apply plugin: 'org.jetbrains.kotlin.android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'org.jetbrains.kotlin.plugin.serialization'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.dagger.hilt.android'
def run(cmd) {
def stdout = new ByteArrayOutputStream()
@ -354,7 +357,7 @@ android {
jvmTarget = '17'
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.1'
kotlinCompilerExtensionVersion '1.5.14'
}
packaging {
resources {
@ -365,18 +368,34 @@ android {
dependencies {
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.1'
implementation 'androidx.activity:activity-compose:1.8.0'
implementation platform('androidx.compose:compose-bom:2023.08.00')
implementation 'androidx.activity:activity-compose:1.9.0'
implementation platform('androidx.compose:compose-bom:2024.05.00')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
androidTestImplementation platform('androidx.compose:compose-bom:2023.08.00')
androidTestImplementation platform('androidx.compose:compose-bom:2024.05.00')
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
debugImplementation 'androidx.compose.ui:ui-tooling'
debugImplementation 'androidx.compose.ui:ui-test-manifest'
// hilt
def hilt = "2.47"
implementation "com.google.dagger:hilt-android:$hilt"
kapt "com.google.dagger:hilt-compiler:$hilt"
kapt "androidx.hilt:hilt-compiler:1.2.0"
implementation 'androidx.hilt:hilt-navigation-compose:1.2.0'
// navigation
implementation "androidx.navigation:navigation-compose:2.8.0-beta03"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
// blurriness
implementation "com.github.skydoves:cloudy:0.1.2"
// countries
implementation 'com.hbb20:ccp:2.7.3'
// Google Play Location Services
//
// Please add symlinks to google/java/app/organicmaps/location for each new gms-enabled flavor below:
@ -430,6 +449,10 @@ dependencies {
testImplementation 'org.mockito:mockito-inline:5.2.0'
}
kapt {
correctErrorTypes true
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}

View file

@ -1,30 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto">
<!-- Requiring "android.hardware.touchscreen" here breaks DeX mode -->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.location"
android:required="false" />
<uses-feature
android:name="android.hardware.location.network"
android:required="false" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="auto">
<!-- Requiring "android.hardware.touchscreen" here breaks DeX mode -->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.location"
android:required="false" />
<uses-feature
android:name="android.hardware.location.network"
android:required="false" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--
https://developer.android.com/reference/androidx/core/app/JobIntentService:
When running on Android O, the JobScheduler will take care of wake locks
for you (holding a wake lock from the time you enqueue work until the job
@ -34,446 +34,448 @@
the application must request the Manifest.permission.WAKE_LOCK permission.
//
-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!--
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<!--
Android 13 (API level 33) and higher supports a runtime permission for sending non-exempt (including Foreground
Services (FGS)) notifications from an app.
//
-->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES" />
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES" />
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>
<supports-screens
android:largeScreens="true"
android:xlargeScreens="true" />
<supports-screens
android:largeScreens="true"
android:xlargeScreens="true" />
<application
android:name=".MwmApplication"
android:allowBackup="true"
android:backupInForeground="true"
android:dataExtractionRules="@xml/backup_content_v31"
android:fullBackupContent="@xml/backup_content"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/network_security_config"
android:resizeableActivity="true"
android:supportsRtl="true"
android:theme="@style/MwmTheme"
tools:targetApi="33">
<!-- Allows for config and orientation change without killing/restarting main activity -->
<activity
android:name=".SplashActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<application
android:name=".MwmApplication"
android:allowBackup="true"
android:backupInForeground="true"
android:dataExtractionRules="@xml/backup_content_v31"
android:fullBackupContent="@xml/backup_content"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/network_security_config"
android:resizeableActivity="true"
android:supportsRtl="true"
android:theme="@style/MwmTheme"
tools:targetApi="33">
<activity
android:name="app.tourism.AuthActivity"
android:exported="false"
android:theme="@style/MwmTheme" />
<!-- Allows for config and orientation change without killing/restarting main activity -->
<activity
android:name=".SplashActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="geo" />
<data android:scheme="ge0" />
<data android:scheme="om" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="geo" />
<data android:scheme="ge0" />
<data android:scheme="om" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="ge0.me" />
</intent-filter>
<intent-filter android:autoVerify="@bool/autoVerify">
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="ge0.me" />
</intent-filter>
<intent-filter android:autoVerify="@bool/autoVerify">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="omaps.app" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="omaps.app" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="http" />
<data android:scheme="https" />
<!-- #map=$zoom/$lat/$lon -->
<data android:host="www.openstreetmap.org" />
<data android:path="/" />
<data android:path="/search" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<!-- #map=$zoom/$lat/$lon -->
<data android:host="www.openstreetmap.org" />
<data android:path="/" />
<data android:path="/search" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mapsme" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="mapsme" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:scheme="data" />
<data android:host="*" />
<data android:mimeType="application/vnd.google-earth.kml+xml" />
<data android:mimeType="application/vnd.google-earth.kmz" />
<data android:mimeType="application/gpx" />
<data android:mimeType="application/gpx+xml" />
<data android:mimeType="application/vnd.google-earth.kmz+xml" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:scheme="data" />
<data android:host="*" />
<data android:mimeType="application/vnd.google-earth.kml+xml" />
<data android:mimeType="application/vnd.google-earth.kmz" />
<data android:mimeType="application/gpx" />
<data android:mimeType="application/gpx+xml" />
<data android:mimeType="application/vnd.google-earth.kmz+xml" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/vnd.google-earth.kml+xml" />
<data android:mimeType="application/vnd.google-earth.kmz" />
<data android:mimeType="application/gpx" />
<data android:mimeType="application/gpx+xml" />
<data android:mimeType="application/vnd.google-earth.kmz+xml" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="application/vnd.google-earth.kml+xml" />
<data android:mimeType="application/vnd.google-earth.kmz" />
<data android:mimeType="application/gpx" />
<data android:mimeType="application/gpx+xml" />
<data android:mimeType="application/vnd.google-earth.kmz+xml" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:scheme="data" />
<data android:host="*" />
<data android:mimeType="*/*" />
<!-- See http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i -->
<data android:pathPattern="/.*\\.kmz" />
<data android:pathPattern="/.*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\.kml" />
<data android:pathPattern="/.*\\.KML" />
<data android:pathPattern="/.*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\.gpx" />
<data android:pathPattern="/.*\\.GPX" />
<data android:pathPattern="/.*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<!-- Old MAPS.ME binary format // -->
<data android:pathPattern="/.*\\.kmb" />
<data android:pathPattern="/.*\\.KMB" />
<data android:pathPattern="/.*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
</intent-filter>
<data android:scheme="content" />
<data android:scheme="file" />
<data android:scheme="data" />
<data android:host="*" />
<data android:mimeType="*/*" />
<!-- See http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i -->
<data android:pathPattern="/.*\\.kmz" />
<data android:pathPattern="/.*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\.kml" />
<data android:pathPattern="/.*\\.KML" />
<data android:pathPattern="/.*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\.gpx" />
<data android:pathPattern="/.*\\.GPX" />
<data android:pathPattern="/.*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<!-- Old MAPS.ME binary format // -->
<data android:pathPattern="/.*\\.kmb" />
<data android:pathPattern="/.*\\.KMB" />
<data android:pathPattern="/.*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
</intent-filter>
<!--
<!--
Duplicates the intent-filter above except it doesn't have mimeType, see
https://stackoverflow.com/questions/1733195/android-intent-filter-for-a-particular-file-extension/31028507#31028507
-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:scheme="data" />
<data android:host="*" />
<!-- See http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i -->
<data android:pathPattern="/.*\\.kmz" />
<data android:pathPattern="/.*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\.kml" />
<data android:pathPattern="/.*\\.KML" />
<data android:pathPattern="/.*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\.gpx" />
<data android:pathPattern="/.*\\.GPX" />
<data android:pathPattern="/.*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<!-- Old MAPS.ME binary format // -->
<data android:pathPattern="/.*\\.kmb" />
<data android:pathPattern="/.*\\.KMB" />
<data android:pathPattern="/.*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
</intent-filter>
<data android:scheme="content" />
<data android:scheme="file" />
<data android:scheme="data" />
<data android:host="*" />
<!-- See http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i -->
<data android:pathPattern="/.*\\.kmz" />
<data android:pathPattern="/.*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMZ" />
<data android:pathPattern="/.*\\.kml" />
<data android:pathPattern="/.*\\.KML" />
<data android:pathPattern="/.*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kml" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KML" />
<data android:pathPattern="/.*\\.gpx" />
<data android:pathPattern="/.*\\.GPX" />
<data android:pathPattern="/.*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.gpx" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.GPX" />
<!-- Old MAPS.ME binary format // -->
<data android:pathPattern="/.*\\.kmb" />
<data android:pathPattern="/.*\\.KMB" />
<data android:pathPattern="/.*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.kmb" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.KMB" />
</intent-filter>
<!-- Catches .gpx and .gpx.xml files opened from Google Files app -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<!-- Catches .gpx and .gpx.xml files opened from Google Files app -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:host="*" />
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/xml" />
<data android:mimeType="text/xml" />
</intent-filter>
</activity>
<data android:scheme="content" />
<data android:host="*" />
<data android:mimeType="application/octet-stream" />
<data android:mimeType="application/xml" />
<data android:mimeType="text/xml" />
</intent-filter>
</activity>
<activity
android:name="app.tourism.MainActivity"
android:exported="false"
android:label="@string/title_activity_main"
android:theme="@style/MwmTheme" />
<activity-alias
android:name=".DownloadResourcesActivity"
android:exported="true"
android:label="@string/app_name"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<activity-alias
android:name=".DownloadResourcesActivity"
android:exported="true"
android:label="@string/app_name"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity
android:name="app.tourism.MainActivity"
android:exported="false"
android:theme="@style/MwmTheme" />
<activity
android:name=".DownloadResourcesLegacyActivity"
android:configChanges="orientation|screenLayout|screenSize" />
<activity
android:name=".MwmActivity"
android:configChanges="uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" />
<activity
android:name=".downloader.DownloaderActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/download_maps"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".search.SearchActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/search_map"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="stateVisible|adjustResize" />
<activity
android:name=".settings.SettingsActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/settings"
android:parentActivityName=".MwmActivity" />
<activity
android:name=".help.HelpActivity"
android:exported="false"
android:label="@string/about_menu_title"
android:parentActivityName=".MwmActivity">
<intent-filter>
<action android:name="app.organicmaps.help.HelpActivity" />
<activity
android:name=".DownloadResourcesLegacyActivity"
android:configChanges="orientation|screenLayout|screenSize" />
<activity
android:name=".MwmActivity"
android:configChanges="uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" />
<activity
android:name=".downloader.DownloaderActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/download_maps"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".search.SearchActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/search_map"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="stateVisible|adjustResize" />
<activity
android:name=".settings.SettingsActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/settings"
android:parentActivityName=".MwmActivity" />
<activity
android:name=".help.HelpActivity"
android:exported="false"
android:label="@string/about_menu_title"
android:parentActivityName=".MwmActivity">
<intent-filter>
<action android:name="app.organicmaps.help.HelpActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".bookmarks.BookmarkCategoriesActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/bookmarks_and_tracks"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".bookmarks.BookmarkListActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/bookmarks"
android:parentActivityName=".bookmarks.BookmarkCategoriesActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".editor.EditorActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/edit_place"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".editor.ProfileActivity"
android:parentActivityName=".settings.SettingsActivity" />
<activity
android:name=".editor.FeatureCategoryActivity"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".editor.ReportActivity"
android:parentActivityName=".MwmActivity" />
<activity
android:name=".editor.OsmLoginActivity"
android:parentActivityName=".MwmActivity" />
<activity
android:name=".bookmarks.BookmarkCategorySettingsActivity"
android:label="@string/edit"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".widget.placepage.PlaceDescriptionActivity"
android:label="@string/place_description_title" />
<activity
android:name=".settings.DrivingOptionsActivity"
android:label="@string/driving_options_title" />
<activity android:name=".MapPlaceholderActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".bookmarks.BookmarkCategoriesActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/bookmarks_and_tracks"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".bookmarks.BookmarkListActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/bookmarks"
android:parentActivityName=".bookmarks.BookmarkCategoriesActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".editor.EditorActivity"
android:configChanges="orientation|screenLayout|screenSize"
android:label="@string/edit_place"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".editor.ProfileActivity"
android:parentActivityName=".settings.SettingsActivity" />
<activity
android:name=".editor.FeatureCategoryActivity"
android:parentActivityName=".MwmActivity"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".editor.ReportActivity"
android:parentActivityName=".MwmActivity" />
<activity
android:name=".editor.OsmLoginActivity"
android:parentActivityName=".MwmActivity" />
<activity
android:name=".bookmarks.BookmarkCategorySettingsActivity"
android:label="@string/edit"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".widget.placepage.PlaceDescriptionActivity"
android:label="@string/place_description_title" />
<activity
android:name=".settings.DrivingOptionsActivity"
android:label="@string/driving_options_title" />
<activity android:name=".MapPlaceholderActivity" />
<service
android:name=".car.CarAppService"
android:exported="true"
android:foregroundServiceType="location">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<service
android:name=".car.CarAppService"
android:exported="true"
android:foregroundServiceType="location">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.NAVIGATION" />
</intent-filter>
</service>
<service
android:name=".routing.NavigationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location"
android:stopWithTask="false" />
<category android:name="androidx.car.app.category.NAVIGATION" />
</intent-filter>
</service>
<service
android:name=".routing.NavigationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="location"
android:stopWithTask="false" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${FILE_PROVIDER_PLACEHOLDER}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider> <!-- Disable Google's checks for visited sites and loaded URLs in bookmarks description. -->
<meta-data
android:name="android.webkit.WebView.EnableSafeBrowsing"
android:value="false" /> <!-- Disable Google's anonymous stats collection -->
<meta-data
android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" />
<!--
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${FILE_PROVIDER_PLACEHOLDER}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider> <!-- Disable Google's checks for visited sites and loaded URLs in bookmarks description. -->
<meta-data
android:name="android.webkit.WebView.EnableSafeBrowsing"
android:value="false" /> <!-- Disable Google's anonymous stats collection -->
<meta-data
android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" />
<!--
Version >= 3.0. Dex Dual Mode support for compatible Samsung devices.
See the documentation: https://developer.samsung.com/samsung-dex/modify-optimizing.html //
-->
<meta-data
android:name="com.samsung.android.multidisplay.keep_process_alive"
android:value="true" />
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="5" />
</application>
<meta-data
android:name="com.samsung.android.multidisplay.keep_process_alive"
android:value="true" />
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="5" />
</application>
</manifest>

View file

@ -45,11 +45,13 @@ import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.util.log.Logger;
import app.organicmaps.util.log.LogsManager;
import dagger.hilt.android.HiltAndroidApp;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.List;
@HiltAndroidApp
public class MwmApplication extends Application implements Application.ActivityLifecycleCallbacks
{
@NonNull

View file

@ -0,0 +1,37 @@
package app.tourism
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.ui.Modifier
import app.organicmaps.R
import app.tourism.ui.screens.auth.AuthNavigation
import app.tourism.ui.theme.OrganicMapsTheme
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class AuthActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.dark(resources.getColor(R.color.black_primary)),
navigationBarStyle = SystemBarStyle.dark(resources.getColor(R.color.black_primary))
)
setContent {
OrganicMapsTheme() {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
AuthNavigation()
}
}
}
}
}
}

View file

@ -0,0 +1,20 @@
package app.tourism
import androidx.compose.ui.unit.dp
const val TAG = "GLOBAL_TAG"
object Constants {
// UI
val SCREEN_PADDING = 16.dp
// image loading<
const val IMAGE_LOCATION = "https://newgo.livo.tj/storage/" //todo change newgo to delivery
const val IMAGE_URL_EXAMPLE =
"https://img.freepik.com/free-photo/young-woman-hiker-taking-photo-with-smartphone-on-mountains-peak-in-winter_335224-427.jpg?w=2000"
const val THUMBNAIL_URL_EXAMPLE =
"https://cdn.pixabay.com/photo/2020/03/24/22/34/illustration-4965674_960_720.jpg"
const val LOGO_URL_EXAMPLE = "https://brandeps.com/logo-download/O/OSCE-logo-vector-01.svg"
}

View file

@ -2,7 +2,6 @@ package app.tourism
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@ -15,23 +14,21 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.content.ContextCompat.startActivity
import app.organicmaps.DownloadResourcesLegacyActivity
import app.organicmaps.downloader.CountryItem
import app.tourism.data.dto.SiteLocation
import app.tourism.ui.theme.OrganicMapsTheme
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val mCurrentCountry = CountryItem.fill("Tajikistan")
if(!mCurrentCountry.present) {
val intent = Intent(this, DownloadResourcesLegacyActivity::class.java)
startActivity(this, intent, null)
}
navigateToMapToDownloadIfNotPresent()
// navigateToAuthIfNotAuthed()
enableEdgeToEdge()
setContent {
OrganicMapsTheme {
@ -44,11 +41,25 @@ 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)
}
}
private fun navigateToAuthIfNotAuthed() {
val intent = Intent(this, AuthActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(this, intent, null)
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
val context = LocalContext.current;
val context = LocalContext.current
Column {
Text(
text = "Hello $name!",
@ -68,11 +79,3 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
OrganicMapsTheme {
Greeting("Android")
}
}

View file

@ -0,0 +1,42 @@
package app.tourism.data.prefs
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import app.organicmaps.R
class UserPreferences(context: Context) {
private var sharedPref: SharedPreferences =
context.getSharedPreferences("user", Context.MODE_PRIVATE)
val languages = listOf(
Language(code = "ru", name = "Русский"),
Language(code = "en", name = "English")
)
val themes = listOf(
Theme(code = "dark", name = context.getString(R.string.dark_theme)),
Theme(code = "light", name = context.getString(R.string.light_theme)),
)
fun getLanguage(): Language? {
val languageCode = sharedPref.getString("language", null)
return languages.firstOrNull() { it.code == languageCode }
}
fun setLanguage(value: String) = sharedPref.edit { putString("language", value) }
fun getTheme(): Theme? {
val themeCode = sharedPref.getString("theme", "")
return themes.firstOrNull() { it.code == themeCode }
}
fun setTheme(value: String?) = sharedPref.edit { putString("theme", value) }
fun getToken() = sharedPref.getString("token", "")
fun setToken(value: String?) = sharedPref.edit { putString("token", value) }
}
data class Language(val code: String, val name: String)
data class Theme(val code: String, val name: String)

View file

@ -0,0 +1,22 @@
package app.tourism.di
import android.content.Context
import app.tourism.data.prefs.UserPreferences
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object DataModule {
@Provides
@Singleton
fun provideUserPreferences(
@ApplicationContext context: Context
): UserPreferences {
return UserPreferences(context)
}
}

View file

@ -0,0 +1,51 @@
package app.tourism.ui.common
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import app.organicmaps.util.log.Logger
import com.skydoves.cloudy.Cloudy
@Composable
fun BlurryContainer(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
val localDensity = LocalDensity.current
Box(Modifier.then(modifier)) {
var height by remember { mutableStateOf(0.dp) }
Cloudy(
radius = 25,
modifier = Modifier
.fillMaxWidth()
.height(height)
.align(Alignment.Center)
.clip(RoundedCornerShape(16.dp))
.background(color = Color.White.copy(alpha = 0.25f))
) {}
Column(
Modifier
.align(Alignment.Center)
.onSizeChanged { newSize ->
height = with(localDensity) { newSize.height.toDp() }
}
) {
content()
}
}
}

View file

@ -0,0 +1,65 @@
package app.tourism.ui.common
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import app.organicmaps.R
import app.tourism.ui.theme.TextStyles
@Composable
fun SingleChoiceCheckBoxes(
modifier: Modifier = Modifier,
selectedItemName: String?,
itemNames: List<String>,
onItemChecked: (String) -> Unit
) {
Column(Modifier.then(modifier)) {
itemNames.forEach { name ->
CheckBoxItem(
name = name,
checked = if(selectedItemName != null) selectedItemName == name else false,
onItemChecked = { onItemChecked(name) },
)
}
}
}
@Composable
fun CheckBoxItem(
modifier: Modifier = Modifier,
name: String,
checked: Boolean,
onItemChecked: () -> Unit,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onItemChecked() }
.padding(16.dp)
.then(modifier),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = name,
style = TextStyles.h4,
color = MaterialTheme.colorScheme.onBackground
)
Icon(
painter = painterResource(id = if (checked) R.drawable.check_circle_fill else R.drawable.unchecked),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null,
)
}
}

View file

@ -0,0 +1,16 @@
package app.tourism.ui.common
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
@Composable
fun RowScope.HorizontalSpace(width: Dp) = Spacer(modifier = Modifier.width(width))
@Composable
fun ColumnScope.VerticalSpace(height: Dp) = Spacer(modifier = Modifier.height(height))

View file

@ -0,0 +1,52 @@
package app.tourism.ui.common.buttons
import ButtonLoading
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import app.tourism.ui.theme.TextStyles
@Composable
fun PrimaryButton(
modifier: Modifier = Modifier,
label: String,
onClick: () -> Unit,
isLoading: Boolean = false,
enabled: Boolean = true,
backgroundColor: Color = MaterialTheme.colorScheme.primary
) {
Button(
modifier = Modifier.fillMaxWidth().height(56.dp).then(modifier),
onClick = onClick,
enabled = enabled,
shape = RoundedCornerShape(16.dp),
colors = ButtonDefaults.buttonColors(containerColor = backgroundColor),
elevation = ButtonDefaults.buttonElevation(defaultElevation = 0.dp)
) {
Box(modifier = Modifier.padding(vertical = 3.dp)) {
if (isLoading)
ButtonLoading()
else
ButtonText(buttonLabel = label)
}
}
}
@Composable
fun ButtonText(buttonLabel: String) {
Text(
text = buttonLabel,
style = TextStyles.h4,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = MaterialTheme.colorScheme.onPrimary
)
}

View file

@ -0,0 +1,56 @@
package app.tourism.ui.common.nav
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import app.tourism.Constants
import app.tourism.ui.theme.TextStyles
@Composable
fun AppTopBar(
modifier: Modifier = Modifier,
title: String,
onBackClick: (() -> Boolean)? = null,
actions: List<TopBarActionData> = emptyList()
) {
Column(modifier = Modifier.then(modifier)) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
onBackClick?.let { BackButton(onBackClick = onBackClick) }
Row {
actions.forEach {
TopBarAction(iconDrawable = it.iconDrawable, onClick = it.onClick)
}
}
}
Column(Modifier.padding(horizontal = Constants.SCREEN_PADDING)) {
Text(text = title, style = TextStyles.h1, color = MaterialTheme.colorScheme.onBackground)
}
}
}
data class TopBarActionData(@DrawableRes val iconDrawable: Int, val onClick: () -> Unit)
@Composable
fun TopBarAction(@DrawableRes iconDrawable: Int, onClick: () -> Unit) {
IconButton(onClick = onClick) {
Icon(
modifier = Modifier.size(24.dp),
painter = painterResource(id = iconDrawable),
contentDescription = null,
)
}
}

View file

@ -0,0 +1,32 @@
package app.tourism.ui.common.nav
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import app.organicmaps.R
@Composable
fun BackButton(
modifier: Modifier = Modifier,
onBackClick: () -> Boolean,
tint: Color = MaterialTheme.colorScheme.onBackground
) {
IconButton(
modifier = Modifier.padding(12.dp).then(modifier),
onClick = { onBackClick() }
) {
Icon(
modifier = Modifier.size(28.dp),
painter = painterResource(id = R.drawable.back),
tint = tint,
contentDescription = null
)
}
}

View file

@ -0,0 +1,44 @@
package app.tourism.ui.common.textfields
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import app.tourism.ui.theme.TextStyles
@Composable
fun AppEditText(
value: MutableState<String>,
hint: String = "",
isError: () -> Boolean = { false },
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default
) {
EditText(
value = value,
hint = hint,
hintColor = Color.Gray,
isError = isError,
textFieldHeight = 50.dp,
textFieldPadding = PaddingValues(vertical = 8.dp),
hintFontSizeInt = 15,
textSize = 17.sp,
textStyle = TextStyles.h3.copy(
textAlign = TextAlign.Start,
color = MaterialTheme.colorScheme.onBackground,
),
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
focusedColor = MaterialTheme.colorScheme.onBackground,
unfocusedColor = Color.Gray,
errorColor = MaterialTheme.colorScheme.onError
)
}

View file

@ -0,0 +1,51 @@
package app.tourism.ui.common.textfields
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import app.tourism.ui.theme.TextStyles
@Composable
fun AuthEditText(
value: MutableState<String>,
hint: String = "",
isError: () -> Boolean = { false },
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
visualTransformation: VisualTransformation = VisualTransformation.None
) {
EditText(
value = value,
hint = hint,
hintColor = Color.White,
isError = isError,
textFieldHeight = 50.dp,
textFieldPadding = PaddingValues(vertical = 8.dp),
hintFontSizeInt = 16,
textSize = 16.sp,
textStyle = TextStyles.h3.copy(
textAlign = TextAlign.Start,
color = Color.White,
),
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
cursorBrush = SolidColor(Color.White),
focusedColor = Color.White,
unfocusedColor = Color.White,
errorColor = MaterialTheme.colorScheme.onError,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
visualTransformation = visualTransformation
)
}

View file

@ -0,0 +1,150 @@
package app.tourism.ui.common.textfields
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.animateOffsetAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlin.math.roundToInt
enum class EtState { Focused, Unfocused, Error }
@Composable
fun EditText(
value: MutableState<String>,
modifier: Modifier = Modifier,
hint: String = "",
hintColor: Color = Color.Gray,
isError: () -> Boolean = { false },
errorColor: Color = Color.Red,
textFieldHeight: Dp = 50.dp,
textFieldPadding: PaddingValues = PaddingValues(0.dp),
textSize: TextUnit = 18.sp,
hintFontSizeInt: Int = 18,
textStyle: TextStyle = TextStyle(
fontWeight = FontWeight.Normal,
color = MaterialTheme.colorScheme.onBackground
),
cursorBrush: Brush = SolidColor(MaterialTheme.colorScheme.primary),
maxLines: Int = 1,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
visualTransformation: VisualTransformation = VisualTransformation.None,
focusedColor: Color = Color.Green,
unfocusedColor: Color = Color.Black,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
) {
var etState by remember { mutableStateOf(EtState.Unfocused) }
val hintCondition = etState == EtState.Unfocused && value.value.isEmpty()
val hintOffset by animateOffsetAsState(
targetValue = if (hintCondition) Offset(0f, 0f)
else Offset(0f, -(hintFontSizeInt * 1.3f))
)
val hintSize by animateIntAsState(
targetValue = if (hintCondition) hintFontSizeInt else (hintFontSizeInt * 0.8).roundToInt()
)
Column(modifier) {
BasicTextField(
modifier = Modifier
.height(textFieldHeight)
.padding(textFieldPadding)
.onFocusChanged {
etState = if (it.hasFocus) EtState.Focused else EtState.Unfocused
}
.fillMaxWidth(),
value = value.value,
onValueChange = {
value.value = it
etState = if (isError()) EtState.Error else EtState.Focused
},
cursorBrush = cursorBrush,
maxLines = maxLines,
textStyle = textStyle.copy(
fontSize = textSize,
textAlign = TextAlign.Start
),
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
visualTransformation = visualTransformation,
decorationBox = {
Row {
leadingIcon?.invoke()
Box(
Modifier
.fillMaxSize(),
contentAlignment = Alignment.BottomStart
) {
Text(
modifier = Modifier.offset(hintOffset.x.dp, hintOffset.y.dp),
text = hint,
fontSize = hintSize.sp,
color = hintColor,
)
it()
Box(Modifier.align(Alignment.CenterEnd)) {
trailingIcon?.invoke()
}
}
}
}
)
EtLine(etState, focusedColor, unfocusedColor, errorColor)
}
}
@Composable
fun EtLine(etState: EtState, focusedColor: Color, unfocusedColor: Color, errorColor: Color) {
val etColor by animateColorAsState(
targetValue = when (etState) {
EtState.Focused -> focusedColor
EtState.Unfocused -> unfocusedColor
else -> errorColor
},
animationSpec = tween(durationMillis = 500), label = "",
)
Divider(
modifier = Modifier.fillMaxWidth(),
color = etColor,
thickness = 1.dp
)
}

View file

@ -0,0 +1,43 @@
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import app.organicmaps.R
import app.tourism.ui.common.textfields.AuthEditText
@Composable
fun PasswordEditText(
value: MutableState<String>,
hint: String,
keyboardActions: KeyboardActions = KeyboardActions.Default,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default
) {
var passwordVisible by remember { mutableStateOf(false) }
AuthEditText(
value = value,
hint = hint,
keyboardActions = keyboardActions,
keyboardOptions = keyboardOptions,
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = { passwordVisible = !passwordVisible }) {
Icon(
painter = painterResource(id = if (passwordVisible) R.drawable.baseline_visibility_24 else com.google.android.material.R.drawable.design_ic_visibility_off),
tint = Color.White,
contentDescription = null
)
}
}
)
}

View file

@ -0,0 +1,15 @@
import androidx.compose.foundation.layout.size
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun ButtonLoading() {
CircularProgressIndicator(
strokeWidth = 2.dp,
modifier = Modifier.size(25.dp),
color = MaterialTheme.colorScheme.background
)
}

View file

@ -0,0 +1,26 @@
package app.tourism.ui.common.ui_state
import androidx.compose.animation.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@Composable
fun Loading(modifier: Modifier = Modifier, status: Boolean = true, onEntireScreen: Boolean = true) {
AnimatedVisibility(
visible = status,
enter = fadeIn(),
exit = fadeOut()
) {
Box(
modifier = if (onEntireScreen) modifier.fillMaxSize() else modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
}
}
}

View file

@ -0,0 +1,82 @@
package app.tourism.ui.common.ui_state
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign.Companion.Center
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import app.organicmaps.R
import app.tourism.Constants
import app.tourism.ui.common.VerticalSpace
import app.tourism.ui.common.buttons.PrimaryButton
import app.tourism.ui.theme.TextStyles
@Composable
fun NetworkError(
modifier: Modifier = Modifier,
errorMessage: String? = null,
status: Boolean = true,
onEntireScreen: Boolean = true,
onRetry: (() -> Unit)? = null
) {
println("error message: $errorMessage")
if (status) {
Column(
modifier = if (onEntireScreen) modifier
.fillMaxSize()
.padding(Constants.SCREEN_PADDING) else modifier.padding(Constants.SCREEN_PADDING),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
if (onEntireScreen)
Icon(
modifier = Modifier
.size(64.dp),
painter = painterResource(id = R.drawable.error),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
Spacer(modifier = Modifier.size(16.dp))
Text(
text = errorMessage
?: stringResource(id = if (onEntireScreen) R.string.no_network else R.string.smth_went_wrong),
style = TextStyles.h1,
textAlign = Center
)
if (onRetry != null)
if (onEntireScreen) {
Spacer(modifier = Modifier.size(16.dp))
PrimaryButton(
label = stringResource(id = R.string.retry),
onClick = { onRetry.invoke() }
)
} else {
IconButton(onClick = { onRetry() }) {
Icon(
painter = painterResource(id = R.drawable.baseline_refresh_24),
tint = MaterialTheme.colorScheme.primary,
contentDescription = null
)
}
}
}
}
}
@Preview(showBackground = true)
@Composable
fun NetworkError_preview() {
Column {
NetworkError(status = true, onEntireScreen = false) {}
VerticalSpace(height = 16.dp)
NetworkError(status = true) {}
}
}

View file

@ -0,0 +1,73 @@
package app.tourism.ui.screens.auth
import android.content.Intent
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import app.tourism.MainActivity
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 kotlinx.serialization.Serializable
// Routes
@Serializable
object Welcome
@Serializable
object SignIn
@Serializable
object SignUp
@Serializable
object Language
@Composable
fun AuthNavigation() {
val context = LocalContext.current
val navController = rememberNavController()
val navigateUp = { navController.navigateUp() }
NavHost(navController = navController, startDestination = Welcome) {
composable<Welcome>() {
WelcomeScreen(
onLanguageClicked = { navController.navigate(route = Language) },
onSignInClicked = { navController.navigate(route = SignIn) },
onSignUpClicked = { navController.navigate(route = SignUp) },
)
}
composable<SignIn> {
SignInScreen(
onSignInClicked = {
// todo
val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
ContextCompat.startActivity(context, intent, null)
},
onBackClick = navigateUp
)
}
composable<SignUp> {
SignUpScreen(
onSignUpClicked = {
// todo
val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
ContextCompat.startActivity(context, intent, null)
},
onBackClick = navigateUp
)
}
composable<Language> {
LanguageScreen(
onBackClick = navigateUp
)
}
}
}

View file

@ -0,0 +1,100 @@
package app.tourism.ui.screens.auth.sign_in
import PasswordEditText
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import app.organicmaps.R
import app.tourism.Constants
import app.tourism.ui.common.BlurryContainer
import app.tourism.ui.common.VerticalSpace
import app.tourism.ui.common.buttons.PrimaryButton
import app.tourism.ui.common.nav.BackButton
import app.tourism.ui.common.textfields.AuthEditText
import app.tourism.ui.theme.TextStyles
@Composable
fun SignInScreen(
onSignInClicked: () -> Unit,
onBackClick: () -> Boolean,
) {
val focusManager = LocalFocusManager.current
val userName = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") }
Box(modifier = Modifier.fillMaxSize()) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.splash_background),
contentScale = ContentScale.Crop,
contentDescription = null
)
BackButton(
modifier = Modifier.align(Alignment.TopStart),
onBackClick = onBackClick,
tint = Color.White
)
BlurryContainer(
Modifier
.align(Alignment.Center)
.fillMaxWidth()
.padding(Constants.SCREEN_PADDING),
) {
Column(Modifier.padding(36.dp)) {
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = stringResource(id = R.string.sign_in_title),
style = TextStyles.h2,
color = Color.White
)
VerticalSpace(height = 32.dp)
AuthEditText(
value = userName,
hint = stringResource(id = R.string.username),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Next)
},
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
)
VerticalSpace(height = 32.dp)
PasswordEditText(
value = password,
hint = stringResource(id = R.string.password),
keyboardActions = KeyboardActions(onDone = { onSignInClicked() }),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
)
VerticalSpace(height = 48.dp)
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
label = stringResource(id = R.string.sign_in),
onClick = { onSignInClicked() },
)
}
}
}
}

View file

@ -0,0 +1,150 @@
package app.tourism.ui.screens.auth.sign_up
import PasswordEditText
import android.view.LayoutInflater
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import app.organicmaps.R
import app.tourism.Constants
import app.tourism.ui.common.BlurryContainer
import app.tourism.ui.common.VerticalSpace
import app.tourism.ui.common.buttons.PrimaryButton
import app.tourism.ui.common.nav.BackButton
import app.tourism.ui.common.textfields.AuthEditText
import app.tourism.ui.theme.TextStyles
import com.hbb20.CountryCodePicker
@Composable
fun SignUpScreen(
onSignUpClicked: () -> Unit,
onBackClick: () -> Boolean,
) {
val focusManager = LocalFocusManager.current
val fullName = remember { mutableStateOf("") }
var countryNameCode by remember { mutableStateOf("") }
val username = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") }
val confirmPassword = remember { mutableStateOf("") }
Box(modifier = Modifier.fillMaxSize()) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.splash_background),
contentScale = ContentScale.Crop,
contentDescription = null
)
BackButton(
modifier = Modifier.align(Alignment.TopStart),
onBackClick = onBackClick,
tint = Color.White
)
BlurryContainer(
Modifier
.align(Alignment.Center)
.fillMaxWidth()
.padding(Constants.SCREEN_PADDING),
) {
Column(
Modifier.padding(36.dp)
) {
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = stringResource(id = R.string.sign_up_title),
style = TextStyles.h2,
color = Color.White
)
VerticalSpace(height = 32.dp)
AuthEditText(
value = fullName,
hint = stringResource(id = R.string.full_name),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Next)
},
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
)
VerticalSpace(height = 32.dp)
AndroidView(
factory = { context ->
val view = LayoutInflater.from(context)
.inflate(R.layout.country_code_picker, null, false)
val ccp = view.findViewById<CountryCodePicker>(R.id.ccp)
ccp.setCountryForNameCode("TJ")
ccp.setOnCountryChangeListener {
countryNameCode = ccp.selectedCountryNameCode
}
view
})
HorizontalDivider(
modifier = Modifier.fillMaxWidth(),
color = Color.White,
thickness = 1.dp
)
VerticalSpace(height = 32.dp)
AuthEditText(
value = username,
hint = stringResource(id = R.string.username),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Next)
},
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
)
VerticalSpace(height = 32.dp)
PasswordEditText(
value = password,
hint = stringResource(id = R.string.password),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Next)
},
),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
)
VerticalSpace(height = 32.dp)
PasswordEditText(
value = confirmPassword,
hint = stringResource(id = R.string.confirm_password),
keyboardActions = KeyboardActions(onDone = { onSignUpClicked() }),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
)
VerticalSpace(height = 48.dp)
PrimaryButton(
modifier = Modifier.fillMaxWidth(),
label = stringResource(id = R.string.sign_up),
onClick = { onSignUpClicked() },
)
}
}
}
}

View file

@ -0,0 +1,116 @@
package app.tourism.ui.screens.auth.welcome
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.organicmaps.R
import app.tourism.Constants
import app.tourism.ui.common.HorizontalSpace
import app.tourism.ui.common.VerticalSpace
import app.tourism.ui.common.buttons.PrimaryButton
import app.tourism.ui.theme.TextStyles
@Composable
fun WelcomeScreen(
onLanguageClicked: () -> Unit,
onSignInClicked: () -> Unit,
onSignUpClicked: () -> Unit,
) {
Box(modifier = Modifier.fillMaxSize()) {
Image(
modifier = Modifier.fillMaxSize(),
painter = painterResource(id = R.drawable.splash_background),
contentScale = ContentScale.Crop,
contentDescription = null
)
Row(
Modifier
.align(Alignment.TopCenter)
.padding(top = 16.dp)
.clickable {
onLanguageClicked()
},
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = stringResource(id = R.string.current_language), color = Color.White)
HorizontalSpace(width = 8.dp)
Icon(
painter = painterResource(id = R.drawable.globe),
tint = Color.White,
contentDescription = null,
)
}
Column(
Modifier
.align(Alignment.BottomStart)
.drawBehind {
val colors = listOf(
Color.Black,
Color.Transparent
)
drawRect(
brush = Brush.verticalGradient(colors),
blendMode = BlendMode.DstIn
)
}
.padding(Constants.SCREEN_PADDING)
) {
Text(
text = stringResource(id = R.string.welcome_to_tjk),
color = Color.White,
style = TextStyles.humongous.copy()
)
VerticalSpace(height = 24.dp)
Row(Modifier.fillMaxWidth()) {
PrimaryButton(
modifier = Modifier.weight(1f),
label = stringResource(id = R.string.sign_in),
onClick = { onSignInClicked() },
)
HorizontalSpace(width = 16.dp)
PrimaryButton(
modifier = Modifier.weight(1f),
label = stringResource(id = R.string.sign_up),
onClick = { onSignUpClicked() },
)
}
VerticalSpace(height = 24.dp)
Row(
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "©",
color = Color.White,
style = TextStyles.h1.copy()
)
HorizontalSpace(width = 8.dp)
Text(
text = stringResource(id = R.string.organization_name),
color = Color.White,
style = TextStyles.h4.copy()
)
}
VerticalSpace(height = 36.dp)
}
}
}

View file

@ -0,0 +1,52 @@
package app.tourism.ui.screens.language
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import app.organicmaps.R
import app.tourism.ui.common.SingleChoiceCheckBoxes
import app.tourism.ui.common.VerticalSpace
import app.tourism.ui.common.nav.AppTopBar
import app.tourism.utils.changeSystemAppLanguage
@Composable
fun LanguageScreen(
onBackClick: () -> Boolean,
vm: LanguageViewModel = hiltViewModel()
) {
val context = LocalContext.current
val languages by vm.languages.collectAsState()
val selectedLanguage by vm.selectedLanguage.collectAsState()
Scaffold(
topBar = {
AppTopBar(
title = stringResource(id = R.string.chose_language),
onBackClick = onBackClick
)
},
containerColor = MaterialTheme.colorScheme.background,
) { paddingValues ->
Column(Modifier.padding(paddingValues)) {
VerticalSpace(height = 16.dp)
SingleChoiceCheckBoxes(
itemNames = languages.map { it.name },
selectedItemName = if(selectedLanguage != null) selectedLanguage?.name else null,
onItemChecked = { name ->
val language = languages.first { it.name == name }
vm.updateLanguage(language)
changeSystemAppLanguage(context, language.code)
}
)
}
}
}

View file

@ -0,0 +1,25 @@
package app.tourism.ui.screens.language
import androidx.lifecycle.ViewModel
import app.tourism.data.prefs.Language
import app.tourism.data.prefs.UserPreferences
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
@HiltViewModel
class LanguageViewModel @Inject constructor(
private val userPreferences: UserPreferences
) : ViewModel() {
private val _languages = MutableStateFlow(userPreferences.languages)
val languages = _languages.asStateFlow()
private val _selectedLanguage = MutableStateFlow(userPreferences.getLanguage())
val selectedLanguage = _selectedLanguage.asStateFlow()
fun updateLanguage(value: Language) {
_selectedLanguage.value = value
userPreferences.setLanguage(value.code)
}
}

View file

@ -2,10 +2,16 @@ package app.tourism.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
val Blue = Color(0xFF0688E7)
val LightBlue = Color(0xFF3FAAF8)
val LighterBlue = Color(0xFFCADCF9)
val LightestBlue = Color(0xFFEEF4FF)
val DarkerBlue = Color(0xFF272f46)
val DarkestBlue = Color(0xFF101832)
val HeartRed = Color(0xFFFF6C61)
val StarYellow= Color(0xFFF8D749)
val DarkGrayForText = Color(0xFF78787F)
val Gray = Color(0xFFD5D5D6)
val LightGray = Color(0xFFF4F4F4)
val DarkForText = Color(0xFF2B2D33)
val WhiteForText = Color(0xFFFFFFFF)

View file

@ -1,37 +1,35 @@
package app.tourism.ui.theme
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.graphics.Color
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
private val lightColors = lightColorScheme(
primary = Blue,
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
surface = LightestBlue,
onSurface = DarkForText,
background = Color.White,
onBackground = DarkForText,
error = Color.Transparent,
onError = Color.Red,
)
private val darkColors = darkColorScheme(
primary = Blue,
onPrimary = Color.White,
surface = DarkerBlue,
onSurface = WhiteForText,
background = DarkestBlue,
onBackground = WhiteForText,
error = Color.Transparent,
onError = Color.Red,
)
@Composable
fun OrganicMapsTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
@ -40,13 +38,8 @@ fun OrganicMapsTheme(
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
darkTheme -> darkColors
else -> lightColors
}
MaterialTheme(

View file

@ -2,9 +2,66 @@ package app.tourism.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import app.organicmaps.R
object Fonts {
val gilroy_regular = FontFamily(
Font(R.font.gilroy_regular)
)
}
object TextStyles {
private val genericStyle = TextStyle(
fontFamily = Fonts.gilroy_regular,
fontWeight = FontWeight.Normal,
)
val humongous = genericStyle.copy(
fontWeight = FontWeight.ExtraBold,
fontSize = 36.sp,
lineHeight = 40.sp,
)
val h1 = genericStyle.copy(
fontWeight = FontWeight.SemiBold,
fontSize = 32.sp,
lineHeight = 36.sp,
)
val h2 = genericStyle.copy(
fontWeight = FontWeight.SemiBold,
fontSize = 24.sp,
lineHeight = 36.sp,
)
val h3 = genericStyle.copy(
fontSize = 20.sp,
lineHeight = 22.sp,
fontWeight = FontWeight.SemiBold,
)
val h4 = genericStyle.copy(
fontSize = 16.sp,
fontWeight = FontWeight.Medium,
)
val b1 = genericStyle.copy(
fontSize = 14.sp
)
val b2 = genericStyle.copy(
fontSize = 12.sp
)
val b3 = genericStyle.copy(
fontSize = 10.sp
)
}
// Set of Material typography styles to start with
val Typography = Typography(

View file

@ -0,0 +1,19 @@
package app.tourism.utils
import android.app.LocaleManager
import android.content.Context
import android.os.Build
import android.os.LocaleList
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
fun changeSystemAppLanguage(context: Context, language: String) {
var locale = language
if (language == "tj") locale = "tg"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
context.getSystemService(LocaleManager::class.java).applicationLocales =
LocaleList.forLanguageTags(locale)
else
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(locale))
}

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="10dp"
android:height="18dp"
android:viewportWidth="10"
android:viewportHeight="18">
<path
android:pathData="M8.2828,0.5013L0.5098,8.4753C0.3733,8.6154 0.2969,8.8032 0.2969,8.9988C0.2969,9.1944 0.3733,9.3822 0.5098,9.5223L8.2828,17.4993C8.3464,17.5646 8.4224,17.6165 8.5064,17.652C8.5904,17.6874 8.6806,17.7057 8.7718,17.7057C8.863,17.7057 8.9532,17.6874 9.0372,17.652C9.1212,17.6165 9.1972,17.5646 9.2608,17.4993C9.3916,17.3654 9.4649,17.1855 9.4649,16.9983C9.4649,16.8111 9.3916,16.6313 9.2608,16.4973L1.9513,8.9988L9.2608,1.5018C9.3912,1.3679 9.4642,1.1884 9.4642,1.0016C9.4642,0.8147 9.3912,0.6352 9.2608,0.5013C9.1972,0.436 9.1212,0.3841 9.0372,0.3486C8.9532,0.3132 8.863,0.2949 8.7718,0.2949C8.6806,0.2949 8.5904,0.3132 8.5064,0.3486C8.4224,0.3841 8.3464,0.436 8.2828,0.5013Z"
android:strokeWidth="0.25"
android:fillColor="#A3A3A3"
android:strokeColor="#A3A3A3"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="18dp"
android:viewportWidth="20"
android:viewportHeight="18">
<path
android:pathData="M3.494,8L9.347,2.429L7.969,0.98L0.311,8.269C-0.103,8.663 -0.104,9.322 0.31,9.717L7.968,17.021L9.348,15.574L3.505,10L20,10.001L20,8.001L11.747,8.001L3.494,8Z"
android:fillColor="#2B2D33"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 108 KiB

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M128,24A104,104 0,1 0,232 128,104.11 104.11,0 0,0 128,24ZM173.66,109.66 L117.66,165.66a8,8 0,0 1,-11.32 0l-24,-24a8,8 0,0 1,11.32 -11.32L112,148.69l50.34,-50.35a8,8 0,0 1,11.32 11.32Z"
android:fillColor="#000000"/>
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="@color/dark_gray"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
</vector>

View file

@ -0,0 +1,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<group>
<clip-path
android:pathData="M0,0h20v20h-20z"/>
<path
android:pathData="M10,18.333C14.602,18.333 18.333,14.602 18.333,10C18.333,5.398 14.602,1.667 10,1.667C5.398,1.667 1.667,5.398 1.667,10C1.667,14.602 5.398,18.333 10,18.333Z"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M10,1.667C7.86,3.913 6.667,6.897 6.667,10C6.667,13.103 7.86,16.087 10,18.333C12.14,16.087 13.333,13.103 13.333,10C13.333,6.897 12.14,3.913 10,1.667Z"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M1.667,10H18.333"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</group>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M128,24A104,104 0,1 0,232 128,104.11 104.11,0 0,0 128,24ZM128,216a88,88 0,1 1,88 -88A88.1,88.1 0,0 1,128 216Z"
android:fillColor="#000000"/>
</vector>

Binary file not shown.

View file

@ -32,13 +32,13 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/brand_name"
android:text="@string/organization_name"
android:textColor="@color/white_primary"
android:textSize="20sp"
android:textAlignment="center"
android:textStyle="bold"
android:textStyle="bold|normal"
android:layout_marginTop="16dp"
android:layout_marginHorizontal="48dp"/>
android:layout_marginHorizontal="32dp"/>
</LinearLayout>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<com.hbb20.CountryCodePicker xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/ccp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="12dp"
app:ccp_autoDetectLanguage="true"
app:ccp_contentColor="@color/white_primary"
app:ccpDialog_backgroundColor="@color/transparent"
app:ccpDialog_textColor="@color/white_primary"
app:ccp_arrowColor="@color/white_primary"
app:ccp_flagBorderColor="@color/white_primary"
app:ccp_textGravity="LEFT"
app:ccp_padding="0dp"
app:ccpDialog_background="@color/transparent"
app:ccpDialog_cornerRadius="16dp"
app:ccp_showFullName="true"
app:ccp_showPhoneCode="false">
</com.hbb20.CountryCodePicker>

View file

@ -2160,7 +2160,54 @@
<string name="type.amenity.events_venue">Место проведения мероприятий</string>
<string name="type.shop.auction">Аукцион</string>
<string name="type.shop.collector">Коллекции</string>
<string name="brand_name"> Комитет по туризму при Правительстве Республики Таджикистан </string>
<string name="organization_name"> Комитет по развитию туризма при Правительстве Республики Таджикистан </string>
<string name="smth_went_wrong">Упс, что-то пошло не так</string>
<string name="wait_tjk_map_downloading">Пожалуйста, подождите, идет загрузка карты Таджикистана? Оставайтесь в приложении</string>
<string name="wait_tjk_map_downloading">Пожалуйста, подождите, идет загрузка карты Таджикистана. Оставайтесь в приложении</string>
<string name="welcome_to_tjk">Добро пожаловать в Таджикистан</string>
<string name="sign_in">Войти</string>
<string name="sign_up">Регистрация</string>
<string name="sign_in_title">Вход</string>
<string name="sign_up_title">Регистрация</string>
<string name="username">Логин</string>
<string name="full_name">Ф.И.О</string>
<string name="country">Страна</string>
<string name="confirm_password">Повторите пароль</string>
<string name="home">Главная</string>
<string name="favorites">Избранное</string>
<string name="account">Аккаунт</string>
<string name="change">Изменить</string>
<string name="found">Найдено</string>
<string name="popular_in_tjk">Популярное в Таджикистане</string>
<string name="popular_in">Популярное в</string>
<string name="description_tourism">Описание</string>
<string name="gallery">Фотогаллерея</string>
<string name="reviews">Отзывы</string>
<string name="compose_review">Оставить отзыв</string>
<string name="see_all">Посмотреть все</string>
<string name="more">Развернуть</string>
<string name="review_title">Отзыв</string>
<string name="tap_to_rate">Нажмите, чтобы оценить:</string>
<string name="text">Текст</string>
<string name="upload_photo">Загрузить фото</string>
<string name="send">Отправить</string>
<string name="profile_tourism">Профиль</string>
<string name="usd">USD</string>
<string name="eur">EUR</string>
<string name="rub">RUB</string>
<string name="personal_data">Персональные данные</string>
<string name="language">Язык</string>
<string name="current_language">Русский</string>
<string name="system_theme">Системная тема</string>
<string name="dark_theme">Темная тема</string>
<string name="light_theme">Светлая тема</string>
<string name="sign_out">Выход</string>
<string name="sign_out_title">Выход</string>
<string name="sign_out_warning">Вы уверенны что хотите выйти?</string>
<string name="update_data">Изменить данные</string>
<string name="phone">Номер телефона</string>
<string name="chose_language">Выберите язык</string>
<string name="russian">Русский</string>
<string name="english">English</string>
<string name="retry">Попробовать заново</string>
<string name="no_network">Не удается соединиться с сервером, проверьте интернет подключение</string>
</resources>

View file

@ -62,7 +62,7 @@
<color name="divider">#1E000000</color>
<color name="divider_night">#1EFFFFFF</color>
<color name="logo">#006C35</color>
<!-- Backgrounds -->

View file

@ -2201,8 +2201,51 @@
<string name="type.shop.auction">Auction</string>
<string name="type.shop.collector">Collectables</string>
//todo
<string name="brand_name"> Комитет по туризму при Правительстве Республики Таджикистан </string>
<string name="title_activity_main">MainActivity</string>
<string name="smth_went_wrong">Oops, something went wrong</string>
<string name="wait_tjk_map_downloading">Please, wait, The Tajikistan map is being downloaded, don\'t get out the of app</string>
<string name="organization_name"> Committee for Tourism Development under the Government of the Republic of Tajikistan </string>
<string name="smth_went_wrong">Error </string>
<string name="wait_tjk_map_downloading">Please wait, the map of Tajikistan is loading, stay in the app</string>
<string name="welcome_to_tjk">Welcome to Tajikistan</string>
<string name="sign_in">Log in</string>
<string name="sign_up">Registration</string>
<string name="sign_in_title">Entry</string>
<string name="sign_up_title">Registration</string>
<string name="username">Login</string>
<string name="full_name">Full name</string>
<string name="country">Country</string>
<string name="confirm_password">Repeat the password</string>
<string name="home">Home</string>
<string name="favorites">Favorites</string>
<string name="account">Account</string>
<string name="change">Edit</string>
<string name="found">Found it</string>
<string name="popular_in_tjk">Popular in Tajikistan</string>
<string name="popular_in">Popular in</string>
<string name="description_tourism">Description</string>
<string name="gallery">Photogallery</string>
<string name="reviews">Feedbacks</string>
<string name="compose_review">Leave feedback</string>
<string name="see_all">View all</string>
<string name="more">Unfold</string>
<string name="review_title">Feedback</string>
<string name="tap_to_rate">Click to rate:</string>
<string name="text">Text</string>
<string name="upload_photo">Upload photo</string>
<string name="send">Send</string>
<string name="profile_tourism">Profile</string>
<string name="usd">USD</string>
<string name="eur">EUR</string>
<string name="rub">RUB</string>
<string name="personal_data">Personal information</string>
<string name="language">Language</string>
<string name="current_language">English</string>
<string name="dark_theme">Dark theme</string>
<string name="light_theme">Light theme</string>
<string name="sign_out">Exit</string>
<string name="sign_out_title">Exit</string>
<string name="sign_out_warning">Are you sure you want to get out?</string>
<string name="update_data">Edit data</string>
<string name="phone">Phone number</string>
<string name="chose_language">Select a language</string>
<string name="retry">Try again</string>
<string name="no_network">Couldn\'t reach the server, please check connection</string>
</resources>

View file

@ -3,4 +3,6 @@ plugins {
id 'com.android.application' version '8.4.1' apply false
id 'com.android.library' version '8.4.1' apply false
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.24' apply false
id 'com.google.dagger.hilt.android' version '2.47' apply false
}

View file

@ -10,14 +10,14 @@
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
#Mon Jun 10 23:17:53 TJT 2024
#Wed Jun 12 17:11:31 TJT 2024
android.native.buildOutput=verbose
android.nonFinalResIds=false
android.nonTransitiveRClass=true
android.useAndroidX=true
enableVulkanDiagnostics=OFF
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx1536M" -Xms256m
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" -Xms256m
propCompileSdkVersion=34
propMinSdkVersion=21
propTargetSdkVersion=34