78 Commits

Author SHA1 Message Date
soraefir d78ef0b38b Update version name 2026-07-09 20:22:50 +02:00
soraefir 30eb5657ce Fix projection selection 2026-07-09 20:22:49 +02:00
soraefir 4085149e88 Improve settings and regional stats 2026-07-09 20:22:49 +02:00
bot 1788d734d2 Merge pull request 'Update dependency mapshaper to v0.7.41' (#548) from renovate/mapshaper-0.x-lockfile into main 2026-07-09 04:01:18 +02:00
Renovate Bot b53215e4ba Update dependency mapshaper to v0.7.41 2026-07-09 02:01:09 +00:00
bot df19f9640f Merge pull request 'Update dependency mapshaper to v0.7.40' (#547) from renovate/mapshaper-0.x-lockfile into main 2026-07-08 04:01:15 +02:00
Renovate Bot 31aa9630d0 Update dependency mapshaper to v0.7.40 2026-07-08 02:01:04 +00:00
bot b1019aeb0b Merge pull request 'Update dependency mapshaper to v0.7.39' (#546) from renovate/mapshaper-0.x-lockfile into main 2026-07-07 04:01:17 +02:00
Renovate Bot 63aa14e31a Update dependency mapshaper to v0.7.39 2026-07-07 02:01:05 +00:00
soraefir 2d87507fa4 Merge branch '9' 2026-07-06 21:52:27 +02:00
Ady bb8dc15554 fix app icon adapted to the user theme colors 2026-07-06 13:51:41 -04:00
Ady b3369f6390 fix StatsActivity title 2026-07-06 13:50:08 -04:00
bot 46df3b5dbe Merge pull request 'Update dependency mapshaper to v0.7.38' (#545) from renovate/mapshaper-0.x-lockfile into main 2026-07-06 04:01:48 +02:00
Renovate Bot 3ab93c7342 Update dependency mapshaper to v0.7.38 2026-07-06 02:01:35 +00:00
sora a8c4529ee8 Update app/build.gradle 2026-07-05 15:04:10 +02:00
bot e7a3f09547 Merge pull request 'Update dependency mapshaper to v0.7.37' (#544) from renovate/mapshaper-0.x-lockfile into main 2026-07-05 04:01:31 +02:00
Renovate Bot 579cf75ca2 Update dependency mapshaper to v0.7.37 2026-07-05 02:01:19 +00:00
bot 121b34c034 Merge pull request 'Lock file maintenance' (#543) from renovate/lock-file-maintenance into main 2026-07-04 04:01:37 +02:00
Renovate Bot 97014e9454 Lock file maintenance 2026-07-04 02:01:35 +00:00
bot 674106923f Merge pull request 'Update dependency mapshaper to v0.7.35' (#542) from renovate/mapshaper-0.x-lockfile into main 2026-07-03 04:01:22 +02:00
Renovate Bot e21dad8ed7 Update dependency mapshaper to v0.7.35 2026-07-03 02:01:13 +00:00
bot b2cca2332b Merge pull request 'Update dependency androidx.compose.ui:ui-tooling to v1.11.4' (#541) from renovate/androidx.compose.ui-ui-tooling-1.x into main 2026-07-03 04:01:00 +02:00
Renovate Bot 13ad82df95 Update dependency androidx.compose.ui:ui-tooling to v1.11.4 2026-07-03 02:00:56 +00:00
bot 2befea2325 Merge pull request 'Update dependency androidx.compose.material:material to v1.11.4' (#540) from renovate/androidx.compose.material-material-1.x into main 2026-07-02 04:00:59 +02:00
bot f45cc57049 Merge pull request 'Update dependency androidx.compose:compose-bom to v2026.06.01' (#539) from renovate/androidx.compose-compose-bom-2026.x into main 2026-07-02 04:00:57 +02:00
Renovate Bot a7f05d5d80 Update dependency androidx.compose.material:material to v1.11.4 2026-07-02 02:00:56 +00:00
Renovate Bot 269e844a4c Update dependency androidx.compose:compose-bom to v2026.06.01 2026-07-02 02:00:54 +00:00
bot 818fc49e3d Merge pull request 'Update plugin com.mikepenz.aboutlibraries.plugin to v15.0.3' (#538) from renovate/com.mikepenz.aboutlibraries.plugin-15.x into main 2026-07-01 04:01:06 +02:00
bot 8a3f7f7621 Merge pull request 'Update dependency com.mikepenz:aboutlibraries-core to v15.0.3' (#537) from renovate/com.mikepenz-aboutlibraries-core-15.x into main 2026-07-01 04:01:01 +02:00
Renovate Bot 8c50670a9d Update plugin com.mikepenz.aboutlibraries.plugin to v15.0.3 2026-07-01 02:01:00 +00:00
Renovate Bot 141ea67d2e Update dependency com.mikepenz:aboutlibraries-core to v15.0.3 2026-07-01 02:00:54 +00:00
soraefir 291fae7aec Fix hash 2026-06-30 07:48:24 +02:00
bot 7a04440eca Merge pull request 'Update dependency com.mikepenz:aboutlibraries-compose-m3 to v15.0.3' (#536) from renovate/com.mikepenz-aboutlibraries-compose-m3-15.x into main 2026-06-30 04:01:17 +02:00
Renovate Bot 691d2e4ea1 Update dependency com.mikepenz:aboutlibraries-compose-m3 to v15.0.3 2026-06-30 02:01:09 +00:00
bot dd5c9387f9 Merge pull request 'Lock file maintenance' (#535) from renovate/lock-file-maintenance into main 2026-06-28 04:01:16 +02:00
Renovate Bot 6038d132ec Lock file maintenance 2026-06-28 02:01:11 +00:00
bot 6a0ac3e5c7 Merge pull request 'Update plugin com.mikepenz.aboutlibraries.plugin to v15' (#534) from renovate/com.mikepenz.aboutlibraries.plugin-15.x into main 2026-06-27 04:01:17 +02:00
Renovate Bot 327a6550b4 Update plugin com.mikepenz.aboutlibraries.plugin to v15 2026-06-27 02:01:15 +00:00
bot 7027d0ffb1 Merge pull request 'Update dependency gradle to v9.6.1' (#533) from renovate/gradle-9.x into main 2026-06-27 04:01:07 +02:00
Renovate Bot 15b33b59ed Update dependency gradle to v9.6.1 2026-06-27 02:00:56 +00:00
bot 36787717ff Merge pull request 'Update dependency com.mikepenz:aboutlibraries-core to v15.0.2' (#532) from renovate/com.mikepenz-aboutlibraries-core-15.x into main 2026-06-27 04:00:54 +02:00
Renovate Bot c27aef23c0 Update dependency com.mikepenz:aboutlibraries-core to v15.0.2 2026-06-27 02:00:49 +00:00
bot a9e567d299 Merge pull request 'Update dependency com.mikepenz:aboutlibraries-compose-m3 to v15.0.2' (#531) from renovate/com.mikepenz-aboutlibraries-compose-m3-15.x into main 2026-06-26 04:00:52 +02:00
Renovate Bot 468fb4ab13 Update dependency com.mikepenz:aboutlibraries-compose-m3 to v15.0.2 2026-06-26 02:00:43 +00:00
bot e952de3c17 Merge pull request 'Update dependency mapshaper to v0.7.33' (#530) from renovate/mapshaper-0.x-lockfile into main 2026-06-24 04:01:11 +02:00
Renovate Bot da1793bc21 Update dependency mapshaper to v0.7.33 2026-06-24 02:01:02 +00:00
bot 650a59b1ac Merge pull request 'Update dependency mapshaper to v0.7.32' (#529) from renovate/mapshaper-0.x-lockfile into main 2026-06-23 04:01:22 +02:00
Renovate Bot 5a9284749c Update dependency mapshaper to v0.7.32 2026-06-23 02:01:11 +00:00
bot 981fc5ebf4 Merge pull request 'Update dependency com.mikepenz:aboutlibraries-core to v15' (#528) from renovate/com.mikepenz-aboutlibraries-core-15.x into main 2026-06-22 04:01:27 +02:00
Renovate Bot 78f5fe7c35 Update dependency com.mikepenz:aboutlibraries-core to v15 2026-06-22 02:01:18 +00:00
bot bdf2911a1c Merge pull request 'Update dependency com.mikepenz:aboutlibraries-compose-m3 to v15' (#527) from renovate/com.mikepenz-aboutlibraries-compose-m3-15.x into main 2026-06-21 04:01:41 +02:00
Renovate Bot 40b2040f25 Update dependency com.mikepenz:aboutlibraries-compose-m3 to v15 2026-06-21 02:01:35 +00:00
bot 48c88d85a4 Merge pull request 'Update actions/checkout action to v7' (#526) from renovate/actions-checkout-7.x into main 2026-06-21 04:01:27 +02:00
Renovate Bot 727c828128 Update actions/checkout action to v7 2026-06-21 02:01:23 +00:00
bot cce6719158 Merge pull request 'Update dependency gradle to v9.6.0' (#525) from renovate/gradle-9.x into main 2026-06-20 04:02:45 +02:00
Renovate Bot 13a79baa2b Update dependency gradle to v9.6.0 2026-06-20 02:02:30 +00:00
bot c956fb9876 Merge pull request 'Update dependency mapshaper to v0.7.29' (#524) from renovate/mapshaper-0.x-lockfile into main 2026-06-20 04:01:49 +02:00
Renovate Bot 339ac468f3 Update dependency mapshaper to v0.7.29 2026-06-20 02:01:40 +00:00
bot f1eacee394 Merge pull request 'Update dependency androidx.compose:compose-bom to v2026.06.00' (#523) from renovate/androidx.compose-compose-bom-2026.x into main 2026-06-19 04:02:06 +02:00
bot a000fb4a3d Merge pull request 'Update dependency mapshaper to v0.7.28' (#522) from renovate/mapshaper-0.x-lockfile into main 2026-06-19 04:02:03 +02:00
Renovate Bot 16ff2e1bc8 Update dependency androidx.compose:compose-bom to v2026.06.00 2026-06-19 02:02:03 +00:00
Renovate Bot 6ee16f02ab Update dependency mapshaper to v0.7.28 2026-06-19 02:01:54 +00:00
bot fd05d9b6f5 Merge pull request 'Update dependency androidx.compose.ui:ui-tooling to v1.11.3' (#521) from renovate/androidx.compose.ui-ui-tooling-1.x into main 2026-06-18 04:01:30 +02:00
bot eece41d0ba Merge pull request 'Update dependency androidx.compose.material:material to v1.11.3' (#520) from renovate/androidx.compose.material-material-1.x into main 2026-06-18 04:01:29 +02:00
Renovate Bot b609704cc1 Update dependency androidx.compose.ui:ui-tooling to v1.11.3 2026-06-18 02:01:27 +00:00
Renovate Bot 39436f473a Update dependency androidx.compose.material:material to v1.11.3 2026-06-18 02:01:23 +00:00
bot ce2721025a Merge pull request 'Update dependency mapshaper to v0.7.26' (#519) from renovate/mapshaper-0.x-lockfile into main 2026-06-16 04:02:04 +02:00
Renovate Bot 371a2aa35f Update dependency mapshaper to v0.7.26 2026-06-16 02:01:52 +00:00
bot 0f986616ae Merge pull request 'Update dependency mapshaper to v0.7.24' (#518) from renovate/mapshaper-0.x-lockfile into main 2026-06-15 04:01:52 +02:00
Renovate Bot eb948c2e59 Update dependency mapshaper to v0.7.24 2026-06-15 02:01:40 +00:00
bot 4fe43c5fc6 Merge pull request 'Lock file maintenance' (#517) from renovate/lock-file-maintenance into main 2026-06-14 04:02:19 +02:00
Renovate Bot eed23b35d4 Lock file maintenance 2026-06-14 02:02:17 +00:00
bot e9d46d0824 Merge pull request 'Update dependency mapshaper to v0.7.23' (#516) from renovate/mapshaper-0.x-lockfile into main 2026-06-14 04:01:58 +02:00
Renovate Bot ccd18f3717 Update dependency mapshaper to v0.7.23 2026-06-14 02:01:46 +00:00
bot 1e78f269c1 Merge pull request 'Lock file maintenance' (#515) from renovate/lock-file-maintenance into main 2026-06-13 04:02:05 +02:00
Renovate Bot 0740c00014 Lock file maintenance 2026-06-13 02:02:01 +00:00
bot 740526104b Merge pull request 'Lock file maintenance' (#514) from renovate/lock-file-maintenance into main 2026-06-07 04:04:22 +02:00
Renovate Bot f807fa62d2 Lock file maintenance 2026-06-07 02:04:13 +00:00
13 changed files with 3809 additions and 4791 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
+7 -7
View File
@@ -2,7 +2,7 @@ plugins {
id 'com.android.application' id 'com.android.application'
id 'org.jetbrains.kotlin.plugin.serialization' version '2.4.0' id 'org.jetbrains.kotlin.plugin.serialization' version '2.4.0'
id 'org.jetbrains.kotlin.plugin.compose' version '2.4.0' id 'org.jetbrains.kotlin.plugin.compose' version '2.4.0'
id 'com.mikepenz.aboutlibraries.plugin' version '14.2.1' id 'com.mikepenz.aboutlibraries.plugin' version '15.0.3'
} }
android { android {
@@ -15,7 +15,7 @@ android {
applicationId 'net.helcel.beans' applicationId 'net.helcel.beans'
minSdk = 28 minSdk = 28
targetSdk = 37 targetSdk = 37
versionName "1.3b" versionName "1.5"
versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1 versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1
} }
signingConfigs { signingConfigs {
@@ -87,7 +87,7 @@ aboutLibraries {
dependencies { dependencies {
implementation 'androidx.compose.material3:material3:1.4.0' implementation 'androidx.compose.material3:material3:1.4.0'
implementation "androidx.compose.material:material:1.11.2" implementation "androidx.compose.material:material:1.11.4"
implementation 'androidx.compose.material:material-icons-extended:1.7.8' implementation 'androidx.compose.material:material-icons-extended:1.7.8'
implementation 'androidx.navigation:navigation-compose:2.9.8' implementation 'androidx.navigation:navigation-compose:2.9.8'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.5' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.5'
@@ -106,12 +106,12 @@ dependencies {
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.mikepenz:aboutlibraries:14.2.1' implementation 'com.mikepenz:aboutlibraries:14.2.1'
implementation 'com.mikepenz:aboutlibraries-compose-m3:14.2.1' implementation 'com.mikepenz:aboutlibraries-compose-m3:15.0.3'
implementation 'com.mikepenz:aboutlibraries-core:14.2.1' implementation 'com.mikepenz:aboutlibraries-core:15.0.3'
implementation platform('androidx.compose:compose-bom:2026.05.01') implementation platform('androidx.compose:compose-bom:2026.06.01')
debugImplementation 'androidx.compose.ui:ui-tooling:1.11.2' debugImplementation 'androidx.compose.ui:ui-tooling:1.11.4'
} }
tasks.configureEach { task -> tasks.configureEach { task ->
@@ -14,7 +14,6 @@ import androidx.compose.material.Icon
import androidx.compose.material.IconButton import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.TopAppBar import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -22,10 +21,11 @@ import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Percent import androidx.compose.material.icons.filled.Percent
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
@@ -43,8 +43,8 @@ import net.helcel.beans.svg.SVGWrapper
class MainScreen : ComponentActivity() { class MainScreen : ComponentActivity() {
private lateinit var psvg: SVGWrapper private var psvg by mutableStateOf<SVGWrapper?>(null)
private lateinit var css: CSSWrapper private var css by mutableStateOf<CSSWrapper?>(null)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -53,14 +53,19 @@ class MainScreen : ComponentActivity() {
Data.loadData(this, Int.MIN_VALUE) Data.loadData(this, Int.MIN_VALUE)
GeoLocImporter.importStates(this) GeoLocImporter.importStates(this)
refreshProjection()
setContent { setContent {
SysTheme { SysTheme {
Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary).statusBarsPadding(),) { val currentPsvg = psvg
AppNavHost(psvg, css) val currentCss = css
if (currentPsvg != null && currentCss != null) {
Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary).statusBarsPadding(),) {
AppNavHost(currentPsvg, currentCss)
}
} }
} }
} }
refreshProjection()
} }
@Composable @Composable
@@ -105,19 +110,25 @@ class MainScreen : ComponentActivity() {
@Composable @Composable
fun MapScreen(psvg: SVGWrapper, css: CSSWrapper) { fun MapScreen(psvg: SVGWrapper, css: CSSWrapper) {
Box { Box {
val opt: RenderOptions = RenderOptions.create() val cssContent = css.get()
opt.css(css.get()) val drawable = remember(psvg, css, cssContent) {
val drawable = remember(psvg, css) { val opt: RenderOptions = RenderOptions.create()
opt.css(cssContent)
PictureDrawable(psvg.get()?.renderToPicture(opt)) PictureDrawable(psvg.get()?.renderToPicture(opt))
} }
AndroidView(factory = { ctx -> AndroidView(
PhotoView(ctx).apply { factory = { ctx ->
setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null) PhotoView(ctx).apply {
setImageDrawable(drawable) setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null)
maximumScale = 32f maximumScale = 64f
scaleType = ImageView.ScaleType.FIT_CENTER scaleType = ImageView.ScaleType.FIT_CENTER
} }
}, modifier = Modifier.fillMaxSize()) },
update = { view ->
view.setImageDrawable(drawable)
},
modifier = Modifier.fillMaxSize()
)
} }
} }
@@ -48,23 +48,22 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.preference.PreferenceManager
import net.helcel.beans.R
import net.helcel.beans.countries.GeoLocImporter
import net.helcel.beans.helper.Settings
import androidx.core.content.edit import androidx.core.content.edit
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.preference.PreferenceManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.helcel.beans.R
import net.helcel.beans.activity.sub.AboutScreen import net.helcel.beans.activity.sub.AboutScreen
import net.helcel.beans.activity.sub.EditPlaceColorDialog import net.helcel.beans.activity.sub.EditPlaceColorDialog
import net.helcel.beans.activity.sub.EditPlaceDialog
import net.helcel.beans.activity.sub.LicenseScreen import net.helcel.beans.activity.sub.LicenseScreen
import net.helcel.beans.countries.GeoLocImporter
import net.helcel.beans.helper.Data import net.helcel.beans.helper.Data
import net.helcel.beans.helper.Settings
@Composable @Composable
fun SysTheme( fun SysTheme(
@@ -156,154 +155,36 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
val defaultTheme = stringResource(R.string.system) val defaultTheme = stringResource(R.string.system)
val keyProjection = stringResource(R.string.key_projection) val keyProjection = stringResource(R.string.key_projection)
val keyGroup = stringResource(R.string.key_group) val keyGroup = stringResource(R.string.key_group)
val keyRegional = stringResource(R.string.key_regional)
val keyRegionalStats = stringResource(R.string.key_regional_stats)
val offString = stringResource(R.string.off) val offString = stringResource(R.string.off)
val onString = stringResource(R.string.on)
var showEdit by remember { mutableStateOf(false) }
var theme by remember { mutableStateOf(prefs.getString(keyTheme, defaultTheme)!!) } var theme by remember { mutableStateOf(prefs.getString(keyTheme, defaultTheme)!!) }
var projection by remember { mutableStateOf(prefs.getString(keyProjection, "default")!!) } var projection by remember { mutableStateOf(prefs.getString(keyProjection, "default")!!) }
var groups by remember { mutableStateOf(prefs.getString(keyGroup,offString)!!) } var groups by remember { mutableStateOf(prefs.getString(keyGroup, offString)!!) }
var regional by remember { mutableStateOf(prefs.getString(keyRegional, offString)!!) }
var regionalStats by remember { mutableStateOf(prefs.getString(keyRegionalStats, offString)!!) }
if(showEdit) var showGroupDialog by remember { mutableStateOf(false) }
EditPlaceDialog(true) { var showRegionalDialog by remember { mutableStateOf(false) }
showEdit = false var showLoad by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
if (showGroupDialog) {
EditPlaceColorDialog(
deleteMode = true,
onDismiss = {
val g = Data.selected_group val g = Data.selected_group
if (it && g != null) { if (g != null) {
Data.visits.reassignAllVisitedToGroup(g.key) Data.visits.reassignAllVisitedToGroup(g.key)
Data.saveData() Data.saveData()
} }
} showGroupDialog = false
})
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.background(MaterialTheme.colors.background)
) {
item {
Text(
"Theme", style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onBackground,
)
MultiPreference(arrayOf(stringResource(R.string.system),stringResource(R.string.light),stringResource(R.string.dark)), theme) { newTheme ->
theme = newTheme
prefs.edit { putString(keyTheme, newTheme) }
}
HorizontalDivider()
}
item {
Text(
"Map Projection",
style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onBackground,
modifier = Modifier.padding(top = 16.dp)
)
MultiPreference(arrayOf(stringResource(R.string.mercator), stringResource(R.string.azimuthalequidistant)), projection) { newProj ->
projection = newProj
prefs.edit { putString(keyProjection, newProj) }
Settings.refreshProjection()
}
HorizontalDivider()
}
item {
Text(
"Groups",
style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onBackground,
modifier = Modifier.padding(top = 16.dp)
)
var showDialog by remember{mutableStateOf(false)}
if(showDialog){
EditPlaceColorDialog(
deleteMode = true,
onDismiss = {
val g = Data.selected_group
if (g != null) {
Data.visits.reassignAllVisitedToGroup(g.key)
Data.saveData()
}
showDialog = false
})
}
MultiPreference(
arrayOf(stringResource(R.string.on), stringResource(R.string.off)),
groups
) { key ->
if (key == offString) {
showDialog=true
}
groups = key
prefs.edit { putString(keyGroup, key) }
}
HorizontalDivider()
}
item {
Text(
text = "Regional",
style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onBackground,
modifier = Modifier
.padding(top = 16.dp)
.clickable(onClick = {}),
)
RegionalScreen()
HorizontalDivider()
}
item{
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument(),
onResult = { uri -> Data.doImport(context, uri) }
)
Row(
modifier = Modifier.fillMaxWidth()
) {
Button(onClick = {
launcher.launch(arrayOf("*/*"))
}, modifier = Modifier
.fillMaxWidth(fraction = 0.4f)
.padding(vertical = 8.dp)) {
Text("Import")
}
Spacer(
modifier = Modifier.fillMaxWidth(0.4f)
)
Button(onClick = {
Data.doExport(context)
}, modifier = Modifier
.fillMaxWidth(fraction = 1f)
.padding(vertical = 8.dp)) {
Text("Export")
}
}
HorizontalDivider()
}
item {
PreferenceButton("Licenses") {
if (navController.currentDestination?.route != "licenses")
navController.navigate("licenses")
}
PreferenceButton("About") {
if (navController.currentDestination?.route != "about")
navController.navigate("about")
}
}
}
} }
@Composable if (showRegionalDialog) {
fun RegionalScreen() {
val context = LocalContext.current
val keyRegional = stringResource(R.string.key_regional)
val offString = stringResource(R.string.off)
val onString = stringResource(R.string.on)
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
var selected by remember { mutableStateOf(prefs.getString(keyRegional, offString)!!)}
var regional by remember{ mutableStateOf(prefs.getString(keyRegional, offString)!!)}
var showDialog by remember{mutableStateOf(false)}
var showLoad by remember{mutableStateOf(false)}
if(showDialog)
Dialog( Dialog(
content = { content = {
Column( Column(
@@ -312,26 +193,27 @@ fun RegionalScreen() {
MaterialTheme.colors.background, MaterialTheme.colors.background,
RoundedCornerShape(corner = CornerSize(16.dp)) RoundedCornerShape(corner = CornerSize(16.dp))
) )
.padding(16.dp),){ .padding(16.dp),
Text(style=MaterialTheme.typography.caption, text= stringResource(R.string.delete_regions)) ) {
Text(
style = MaterialTheme.typography.caption,
text = stringResource(R.string.delete_regions)
)
Button(onClick = { Button(onClick = {
GeoLocImporter.clearStates() GeoLocImporter.clearStates()
regional= selected regional = offString
prefs.edit { prefs.edit { putString(keyRegional, offString) }
putString( showRegionalDialog = false
keyRegional, }) {
regional Text(stringResource(R.string.ok))
)
}
showDialog=false
}){
Text(stringResource(R.string.ok))
} }
} }
}, },
onDismissRequest = { showDialog=false } onDismissRequest = { showRegionalDialog = false }
) )
if(showLoad){ }
if (showLoad) {
Dialog( Dialog(
content = { content = {
CircularProgressIndicator( CircularProgressIndicator(
@@ -343,41 +225,153 @@ fun RegionalScreen() {
onDismissRequest = {} onDismissRequest = {}
) )
} }
val scope = rememberCoroutineScope()
MultiPreference(arrayOf(stringResource(R.string.on),stringResource(R.string.off)),regional) { key -> LazyColumn(
when (key) { modifier = Modifier
offString -> { showDialog=true .fillMaxSize()
selected=key .padding(16.dp)
.background(MaterialTheme.colors.background)
) {
item {
Text(
stringResource(R.string.key_theme),
style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onBackground,
)
MultiPreference(
arrayOf(
stringResource(R.string.system),
stringResource(R.string.light),
stringResource(R.string.dark)
), theme
) { newTheme ->
theme = newTheme
prefs.edit { putString(keyTheme, newTheme) }
}
HorizontalDivider()
}
item {
Text(
stringResource(R.string.key_projection),
style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onBackground,
modifier = Modifier.padding(top = 16.dp)
)
MultiPreference(
arrayOf(stringResource(R.string.mercator), stringResource(R.string.azimuthalequidistant)),
projection
) { newProj ->
projection = newProj
prefs.edit { putString(keyProjection, newProj) }
Settings.refreshProjection()
}
HorizontalDivider()
}
item {
SettingSwitch(
label = stringResource(R.string.key_group),
subtitle = stringResource(R.string.key_group_desc),
isChecked = groups == onString,
onCheckedChange = { isChecked ->
if (!isChecked) {
showGroupDialog = true
} else {
groups = onString
prefs.edit { putString(keyGroup, onString) }
} }
onString -> { }
regional = key )
prefs.edit { putString(keyRegional, key) } HorizontalDivider()
showLoad=true }
item {
SettingSwitch(
label = stringResource(R.string.key_regional),
subtitle = stringResource(R.string.key_regional_desc),
isChecked = regional == onString,
onCheckedChange = { isChecked ->
if (isChecked) {
regional = onString
prefs.edit { putString(keyRegional, onString) }
showLoad = true
scope.launch { scope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
GeoLocImporter.importStates(context, true) GeoLocImporter.importStates(context, true)
} }
showLoad = false showLoad = false
} }
} else {
showRegionalDialog = true
} }
} }
)
if (regional == onString) {
SettingSwitch(
label = stringResource(R.string.pref_regional_stats),
subtitle = stringResource(R.string.pref_regional_stats_desc),
isChecked = regionalStats == onString,
onCheckedChange = { isChecked ->
regionalStats = if (isChecked) onString else offString
prefs.edit { putString(keyRegionalStats, regionalStats) }
}
)
} }
HorizontalDivider()
}
item {
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument(),
onResult = { uri -> Data.doImport(context, uri) }
)
Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)
) {
Button(
onClick = {
launcher.launch(arrayOf("*/*"))
}, modifier = Modifier
.weight(1f)
) {
Text(stringResource(R.string.action_import))
}
Spacer(modifier = Modifier.size(16.dp))
Button(
onClick = {
Data.doExport(context)
}, modifier = Modifier
.weight(1f)
) {
Text(stringResource(R.string.action_export))
}
}
HorizontalDivider()
}
item {
PreferenceButton(stringResource(R.string.licenses)) {
if (navController.currentDestination?.route != "licenses")
navController.navigate("licenses")
}
PreferenceButton(stringResource(R.string.about)) {
if (navController.currentDestination?.route != "about")
navController.navigate("about")
}
}
}
} }
@Composable @Composable
fun MultiPreference(list: Array<String>, selected: String, onSelected: (String) -> Unit) { fun MultiPreference(list: Array<String>, selected: String, onSelected: (String) -> Unit) {
Column(Modifier.padding(2.dp)) { Column(Modifier.padding(vertical = 2.dp)) {
list.forEach { value -> list.forEach { value ->
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(36.dp) .height(42.dp)
.clickable { onSelected(value) }) { .clickable { onSelected(value) }) {
RadioButton(selected = selected == value, onClick = { onSelected(value) }) RadioButton(selected = selected == value, onClick = { onSelected(value) })
Text( Text(
value, modifier = Modifier.padding(start = 8.dp), value, modifier = Modifier.padding(start = 12.dp),
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.onBackground, color = MaterialTheme.colors.onBackground,
) )
} }
@@ -392,4 +386,39 @@ fun PreferenceButton(text: String, onClick: () -> Unit) {
.padding(vertical = 8.dp)) { .padding(vertical = 8.dp)) {
Text(text) Text(text)
} }
} }
@Composable
fun SettingSwitch(
label: String,
subtitle: String? = null,
isChecked: Boolean,
onCheckedChange: (Boolean) -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onCheckedChange(!isChecked) }
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text=label,
style = MaterialTheme.typography.h6,
color = MaterialTheme.colors.onBackground,
)
if (subtitle != null) {
Text(
text = subtitle,
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
)
}
}
androidx.compose.material.Switch(
checked = isChecked,
onCheckedChange = onCheckedChange
)
}
}
@@ -37,7 +37,7 @@ import net.helcel.beans.countries.World
import net.helcel.beans.helper.AUTO_GROUP import net.helcel.beans.helper.AUTO_GROUP
import net.helcel.beans.helper.Data import net.helcel.beans.helper.Data
import net.helcel.beans.helper.Groups import net.helcel.beans.helper.Groups
import net.helcel.beans.helper.Settings.isRegional import net.helcel.beans.helper.Settings
import net.helcel.beans.helper.Theme.getContrastColor import net.helcel.beans.helper.Theme.getContrastColor
private val MODE_LIST = listOf(LocType.WORLD, LocType.COUNTRY, LocType.STATE) private val MODE_LIST = listOf(LocType.WORLD, LocType.COUNTRY, LocType.STATE)
@@ -46,7 +46,7 @@ private val MODE_LIST = listOf(LocType.WORLD, LocType.COUNTRY, LocType.STATE)
fun StatsScreen( fun StatsScreen(
onExit: ()-> Unit onExit: ()-> Unit
) { ) {
val modes = if (isRegional(LocalContext.current)) MODE_LIST else MODE_LIST.take(2) val modes = if (Settings.isRegional(LocalContext.current)) MODE_LIST else MODE_LIST.take(2)
var selectedTab by remember { mutableIntStateOf(0) } var selectedTab by remember { mutableIntStateOf(0) }
var countMode by remember { mutableStateOf(true) } var countMode by remember { mutableStateOf(true) }
@@ -57,7 +57,7 @@ fun StatsScreen(
TopAppBar( TopAppBar(
title = { title = {
Row(verticalAlignment = Alignment.CenterVertically){ Row(verticalAlignment = Alignment.CenterVertically){
Text(text=stringResource(R.string.action_edit), modifier = Modifier.weight(1f)) Text(text=stringResource(R.string.action_stat), modifier = Modifier.weight(1f))
Button(onClick = { countMode = !countMode }) { Button(onClick = { countMode = !countMode }) {
Text(if (countMode) "Count" else "Area") Text(if (countMode) "Count" else "Area")
} }
@@ -115,23 +115,78 @@ fun StatsList(activeMode: LocType, countMode: Boolean) {
@Composable @Composable
fun StatsRow(group: Groups.Group, activeMode: LocType, countMode: Boolean) { fun StatsRow(group: Groups.Group, activeMode: LocType, countMode: Boolean) {
val context = LocalContext.current
val isRegionalStats = remember { Settings.isRegionalStats(context) }
val visited = remember(group, activeMode) { val countries = remember { World.WWW.children.flatMap { it.children } }
Data.visits.getVisitedByValue(group.key) val continents = remember { World.WWW.children.toList() }
val count = remember(group, activeMode, isRegionalStats) {
when (activeMode) {
LocType.WORLD -> continents.filter { continent ->
if (group.key == AUTO_GROUP) {
val isUncat = Data.visits.getVisited(continent) == AUTO_GROUP || continent.children.any { Data.visits.getVisited(it) == AUTO_GROUP }
val isInRealGroup = Data.groups.groupsFlow.value.any { g ->
Data.visits.getVisited(continent) == g.key || continent.children.any { Data.visits.getVisited(it) == g.key }
}
isUncat && (!isRegionalStats || !isInRealGroup)
} else {
Data.visits.getVisited(continent) == group.key || (isRegionalStats && continent.children.any { Data.visits.getVisited(it) == group.key })
}
}.size
LocType.COUNTRY -> countries.filter { country ->
if (group.key == AUTO_GROUP) {
val isUncat = Data.visits.getVisited(country) == AUTO_GROUP || country.children.any { Data.visits.getVisited(it) == AUTO_GROUP }
val isInRealGroup = Data.groups.groupsFlow.value.any { g ->
Data.visits.getVisited(country) == g.key || country.children.any { Data.visits.getVisited(it) == g.key }
}
isUncat && (!isRegionalStats || !isInRealGroup)
} else {
Data.visits.getVisited(country) == group.key || (isRegionalStats && country.children.any { Data.visits.getVisited(it) == group.key })
}
}.size
LocType.STATE -> countries.flatMap { it.children }.filter { region ->
Data.visits.getVisited(region) == group.key
}.size
else -> 0
}
} }
val count = when (activeMode) { val area = remember(group, activeMode, isRegionalStats) {
LocType.WORLD -> World.WWW.children.filter { it.code in visited }.size when (activeMode) {
LocType.COUNTRY -> World.WWW.children.flatMap { it.children.filter { c -> c.code in visited } }.size LocType.WORLD -> continents.filter { continent ->
LocType.STATE -> World.WWW.children.flatMap { a->a.children.flatMap { b->b.children.filter { c->c.code in visited } } }.size if (group.key == AUTO_GROUP) {
else -> 0 val isUncat = Data.visits.getVisited(continent) == AUTO_GROUP || continent.children.any { Data.visits.getVisited(it) == AUTO_GROUP }
} val isInRealGroup = Data.groups.groupsFlow.value.any { g ->
Data.visits.getVisited(continent) == g.key || continent.children.any { Data.visits.getVisited(it) == g.key }
}
isUncat && (!isRegionalStats || !isInRealGroup)
} else {
Data.visits.getVisited(continent) == group.key || (isRegionalStats && continent.children.any { Data.visits.getVisited(it) == group.key })
}
}.sumOf { it.area }
val area = when (activeMode) { LocType.COUNTRY -> countries.filter { country ->
LocType.WORLD -> World.WWW.children.filter { it.code in visited }.sumOf { it.area } if (group.key == AUTO_GROUP) {
LocType.COUNTRY -> World.WWW.children.flatMap { it.children.filter { c -> c.code in visited } }.sumOf { it.area } val isUncat = Data.visits.getVisited(country) == AUTO_GROUP || country.children.any { Data.visits.getVisited(it) == AUTO_GROUP }
LocType.STATE -> World.WWW.children.flatMap { a->a.children.flatMap { b->b.children.filter { c->c.code in visited } } }.sumOf { it.area } val isInRealGroup = Data.groups.groupsFlow.value.any { g ->
else -> 0 Data.visits.getVisited(country) == g.key || country.children.any { Data.visits.getVisited(it) == g.key }
}
isUncat && (!isRegionalStats || !isInRealGroup)
} else {
Data.visits.getVisited(country) == group.key || (isRegionalStats && country.children.any { Data.visits.getVisited(it) == group.key })
}
}.sumOf { it.area }
LocType.STATE -> countries.flatMap { it.children }.filter { region ->
Data.visits.getVisited(region) == group.key
}.sumOf { it.area }
else -> 0
}
} }
val displayValue = if (countMode) count.toString() else stringResource(R.string.number_with_unit, area, "km²") val displayValue = if (countMode) count.toString() else stringResource(R.string.number_with_unit, area, "km²")
@@ -29,6 +29,13 @@ object Settings {
) )
} }
fun isRegionalStats(ctx: Context): Boolean {
return getBooleanValue(
ctx,
sp.getString(ctx.getString(R.string.key_regional_stats), ctx.getString(R.string.off))
)
}
fun getStatPref(ctx: Context): String? { fun getStatPref(ctx: Context): String? {
return sp.getString( return sp.getString(
ctx.getString(R.string.key_stats), ctx.getString(R.string.key_stats),
@@ -17,7 +17,6 @@
android:pathData="M36,36m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0" android:pathData="M36,36m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="2"
android:fillColor="@color/blue"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
@@ -2,5 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground"/> <monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>
+14 -1
View File
@@ -15,8 +15,21 @@
<string name="percentages">Prefer percentages (%)</string> <string name="percentages">Prefer percentages (%)</string>
<string name="licenses">Licenses</string> <string name="licenses">Licenses</string>
<string name="key_group">Groups</string> <string name="key_group">Groups</string>
<string name="key_regional">Regional</string> <string name="key_regional">Regional mode</string>
<string name="key_regional_desc">Enable tracking of states and provinces</string>
<string name="key_regional_stats">key_regional_stats</string>
<string name="pref_regional_stats">Regional statistics</string>
<string name="pref_regional_stats_desc">Count countries with visited regions</string>
<string name="key_group_desc">Enable multiple colors</string>
<string name="about">About</string> <string name="about">About</string>
<string name="pref_category_appearance">Appearance</string>
<string name="pref_category_features">Features</string>
<string name="pref_category_data">Data</string>
<string name="action_import">Import</string>
<string name="action_export">Export</string>
<string name="import_desc">Load data from a previously exported file.</string>
<string name="export_desc">Save your current data to a file for backup or transfer.</string>
<string name="key_projection_desc">Select how the map is projected onto a 2D surface.</string>
<string name="beans_is_foss">Beans is free and open source software, licensed under the GNU General Public License (version 3 or later)</string> <string name="beans_is_foss">Beans is free and open source software, licensed under the GNU General Public License (version 3 or later)</string>
<string name="beans_repo_uri">https://github.com/helcel-net/beans</string> <string name="beans_repo_uri">https://github.com/helcel-net/beans</string>
<string name="beans_repo">Project repository: %1$s\n Feel free to report issues or contribute.</string> <string name="beans_repo">Project repository: %1$s\n Feel free to report issues or contribute.</string>
+2 -2
View File
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=bafc141b619ad6350fd975fc903156dd5c151998cc8b058e8c1044ab5f7b031f distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000 networkTimeout=10000
retries=0 retries=0
retryBackOffMs=500 retryBackOffMs=500
Vendored
+2 -2
View File
@@ -20,7 +20,7 @@
############################################################################## ##############################################################################
# #
# Gradle start up script for POSIX generated by Gradle. # gradlew start up script for POSIX generated by Gradle.
# #
# Important for running: # Important for running:
# #
@@ -29,7 +29,7 @@
# bash, then to run this script, type that shell name before the whole # bash, then to run this script, type that shell name before the whole
# command line, like: # command line, like:
# #
# ksh Gradle # ksh gradlew
# #
# Busybox and similar reduced shells will NOT work, because this script # Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features: # requires all of these POSIX shell features:
Vendored
+2 -2
View File
@@ -19,7 +19,7 @@
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem gradlew startup script for Windows
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@@ -72,7 +72,7 @@ echo location of your Java installation. 1>&2
@rem Execute Gradle @rem Execute gradlew
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded @rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command @rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
+3473 -4569
View File
File diff suppressed because it is too large Load Diff