19 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
9 changed files with 346 additions and 232 deletions
+1 -1
View File
@@ -15,7 +15,7 @@ android {
applicationId 'net.helcel.beans'
minSdk = 28
targetSdk = 37
versionName "1.3b"
versionName "1.5"
versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1
}
signingConfigs {
@@ -14,7 +14,6 @@ import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
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.Settings
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.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
@@ -43,8 +43,8 @@ import net.helcel.beans.svg.SVGWrapper
class MainScreen : ComponentActivity() {
private lateinit var psvg: SVGWrapper
private lateinit var css: CSSWrapper
private var psvg by mutableStateOf<SVGWrapper?>(null)
private var css by mutableStateOf<CSSWrapper?>(null)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -53,14 +53,19 @@ class MainScreen : ComponentActivity() {
Data.loadData(this, Int.MIN_VALUE)
GeoLocImporter.importStates(this)
refreshProjection()
setContent {
SysTheme {
Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary).statusBarsPadding(),) {
AppNavHost(psvg, css)
val currentPsvg = psvg
val currentCss = css
if (currentPsvg != null && currentCss != null) {
Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colors.primary).statusBarsPadding(),) {
AppNavHost(currentPsvg, currentCss)
}
}
}
}
refreshProjection()
}
@Composable
@@ -105,19 +110,25 @@ class MainScreen : ComponentActivity() {
@Composable
fun MapScreen(psvg: SVGWrapper, css: CSSWrapper) {
Box {
val opt: RenderOptions = RenderOptions.create()
opt.css(css.get())
val drawable = remember(psvg, css) {
val cssContent = css.get()
val drawable = remember(psvg, css, cssContent) {
val opt: RenderOptions = RenderOptions.create()
opt.css(cssContent)
PictureDrawable(psvg.get()?.renderToPicture(opt))
}
AndroidView(factory = { ctx ->
PhotoView(ctx).apply {
setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null)
setImageDrawable(drawable)
maximumScale = 32f
scaleType = ImageView.ScaleType.FIT_CENTER
}
}, modifier = Modifier.fillMaxSize())
AndroidView(
factory = { ctx ->
PhotoView(ctx).apply {
setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null)
maximumScale = 64f
scaleType = ImageView.ScaleType.FIT_CENTER
}
},
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.unit.dp
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.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.preference.PreferenceManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.helcel.beans.R
import net.helcel.beans.activity.sub.AboutScreen
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.countries.GeoLocImporter
import net.helcel.beans.helper.Data
import net.helcel.beans.helper.Settings
@Composable
fun SysTheme(
@@ -156,154 +155,36 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
val defaultTheme = stringResource(R.string.system)
val keyProjection = stringResource(R.string.key_projection)
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)
var showEdit by remember { mutableStateOf(false) }
val onString = stringResource(R.string.on)
var theme by remember { mutableStateOf(prefs.getString(keyTheme, defaultTheme)!!) }
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)
EditPlaceDialog(true) {
showEdit = false
var showGroupDialog by remember { mutableStateOf(false) }
var showRegionalDialog by remember { mutableStateOf(false) }
var showLoad by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
if (showGroupDialog) {
EditPlaceColorDialog(
deleteMode = true,
onDismiss = {
val g = Data.selected_group
if (it && g != null) {
if (g != null) {
Data.visits.reassignAllVisitedToGroup(g.key)
Data.saveData()
}
}
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")
}
}
}
showGroupDialog = false
})
}
@Composable
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)
if (showRegionalDialog) {
Dialog(
content = {
Column(
@@ -312,26 +193,27 @@ fun RegionalScreen() {
MaterialTheme.colors.background,
RoundedCornerShape(corner = CornerSize(16.dp))
)
.padding(16.dp),){
Text(style=MaterialTheme.typography.caption, text= stringResource(R.string.delete_regions))
.padding(16.dp),
) {
Text(
style = MaterialTheme.typography.caption,
text = stringResource(R.string.delete_regions)
)
Button(onClick = {
GeoLocImporter.clearStates()
regional= selected
prefs.edit {
putString(
keyRegional,
regional
)
}
showDialog=false
}){
Text(stringResource(R.string.ok))
regional = offString
prefs.edit { putString(keyRegional, offString) }
showRegionalDialog = false
}) {
Text(stringResource(R.string.ok))
}
}
},
onDismissRequest = { showDialog=false }
onDismissRequest = { showRegionalDialog = false }
)
if(showLoad){
}
if (showLoad) {
Dialog(
content = {
CircularProgressIndicator(
@@ -343,41 +225,153 @@ fun RegionalScreen() {
onDismissRequest = {}
)
}
val scope = rememberCoroutineScope()
MultiPreference(arrayOf(stringResource(R.string.on),stringResource(R.string.off)),regional) { key ->
when (key) {
offString -> { showDialog=true
selected=key
LazyColumn(
modifier = Modifier
.fillMaxSize()
.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) }
showLoad=true
}
)
HorizontalDivider()
}
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 {
withContext(Dispatchers.IO) {
GeoLocImporter.importStates(context, true)
}
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
fun MultiPreference(list: Array<String>, selected: String, onSelected: (String) -> Unit) {
Column(Modifier.padding(2.dp)) {
Column(Modifier.padding(vertical = 2.dp)) {
list.forEach { value ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.height(36.dp)
.height(42.dp)
.clickable { onSelected(value) }) {
RadioButton(selected = selected == value, onClick = { onSelected(value) })
Text(
value, modifier = Modifier.padding(start = 8.dp),
value, modifier = Modifier.padding(start = 12.dp),
style = MaterialTheme.typography.body1,
color = MaterialTheme.colors.onBackground,
)
}
@@ -392,4 +386,39 @@ fun PreferenceButton(text: String, onClick: () -> Unit) {
.padding(vertical = 8.dp)) {
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.Data
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
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(
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 countMode by remember { mutableStateOf(true) }
@@ -57,7 +57,7 @@ fun StatsScreen(
TopAppBar(
title = {
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 }) {
Text(if (countMode) "Count" else "Area")
}
@@ -115,23 +115,78 @@ fun StatsList(activeMode: LocType, countMode: Boolean) {
@Composable
fun StatsRow(group: Groups.Group, activeMode: LocType, countMode: Boolean) {
val context = LocalContext.current
val isRegionalStats = remember { Settings.isRegionalStats(context) }
val visited = remember(group, activeMode) {
Data.visits.getVisitedByValue(group.key)
val countries = remember { World.WWW.children.flatMap { it.children } }
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) {
LocType.WORLD -> World.WWW.children.filter { it.code in visited }.size
LocType.COUNTRY -> World.WWW.children.flatMap { it.children.filter { c -> c.code in visited } }.size
LocType.STATE -> World.WWW.children.flatMap { a->a.children.flatMap { b->b.children.filter { c->c.code in visited } } }.size
else -> 0
}
val area = 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 })
}
}.sumOf { it.area }
val area = when (activeMode) {
LocType.WORLD -> World.WWW.children.filter { it.code in visited }.sumOf { it.area }
LocType.COUNTRY -> World.WWW.children.flatMap { it.children.filter { c -> c.code in visited } }.sumOf { it.area }
LocType.STATE -> World.WWW.children.flatMap { a->a.children.flatMap { b->b.children.filter { c->c.code in visited } } }.sumOf { it.area }
else -> 0
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 })
}
}.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²")
@@ -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? {
return sp.getString(
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:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="@color/blue"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
@@ -2,5 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon>
+14 -1
View File
@@ -15,8 +15,21 @@
<string name="percentages">Prefer percentages (%)</string>
<string name="licenses">Licenses</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="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_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>
+23 -23
View File
@@ -70,9 +70,9 @@
integrity sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==
"@csstools/css-syntax-patches-for-csstree@^1.1.3":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.5.tgz#b8e26e0fe25e9a6ec607d045470cc46d2f62731e"
integrity sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==
version "1.1.6"
resolved "https://registry.yarnpkg.com/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.6.tgz#3a1e91cefb65b4a74ae7dd78c9b2dd60cdbf3ad4"
integrity sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==
"@csstools/css-tokenizer@^4.0.0":
version "4.0.0"
@@ -1988,9 +1988,9 @@
integrity sha512-tdJz7jaWFu4nR+8b2B+CdPZ6811ighYylWsu2hpsivapzW058yP0KdfZuNY89IiRe5jbKvBGXN3LQdN2KPXVdQ==
"@types/node@*":
version "26.1.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-26.1.0.tgz#aa85f0727fc5611347091c478341c63650903439"
integrity sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==
version "26.1.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-26.1.1.tgz#bad758d601e97d6cf457d204ee76a35fce7bd119"
integrity sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==
dependencies:
undici-types "~8.3.0"
@@ -2559,16 +2559,16 @@ iconv-lite@^0.6.3:
safer-buffer ">= 2.1.2 < 3.0.0"
iconv-lite@^0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e"
integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==
version "0.7.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.3.tgz#84ee12f963e7de50bc01a13e160a078b3b0f415f"
integrity sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
idb-keyval@^6.2.0:
version "6.2.6"
resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.6.tgz#6a1204e20dca567f7b8fef2fac5fc52af02fd553"
integrity sha512-FY64UEhw+5liMzMQ1R9Mw6AF0+wyBrg1CIA1z4CjI/EvT5ty/SvQcWZgd8s9sgaNhX10Y8UzScTh89tEAls5nA==
version "6.3.0"
resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.3.0.tgz#3fa4c062fcaddd7e577c51b51f69924bccfb58e6"
integrity sha512-um+2dgAWmYsu615EXpWVwSmapJhON0G43t3Ka/EVaohzPQXSMqKEqeDK/oIW3Ow+BXaF2PvSc+oBTFp793A5Ow==
ieee754@^1.1.13, ieee754@^1.2.1:
version "1.2.1"
@@ -2708,9 +2708,9 @@ map-stream@0.0.7:
integrity sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==
mapshaper@^0.7.22:
version "0.7.35"
resolved "https://registry.yarnpkg.com/mapshaper/-/mapshaper-0.7.35.tgz#5de71cea5d322272a77c7fa1c0fac5f491403479"
integrity sha512-+UuAIVcuRWr3ZR0Lv/weIqUmSn/NMeHxWdfgyc0P2Dbi1NE7PDJ2yUg4utH2wIUqVpMvGzfIG6Uk/mPj/KlGNw==
version "0.7.41"
resolved "https://registry.yarnpkg.com/mapshaper/-/mapshaper-0.7.41.tgz#c03fa2aed375abbc92af47008dc81695a604ed23"
integrity sha512-TC1KL8OtYZPRuq/Wl0AW2LQOic/q/AQbEEiPkCXlN5dGFXPIRj8+Qllc3EWBhN7aViHStI2IIthP2/L7BDzobQ==
dependencies:
"@bokuweb/zstd-wasm" "^0.0.27"
"@ngageoint/geopackage" "^4.2.6"
@@ -3293,17 +3293,17 @@ tinyqueue@^2.0.0, tinyqueue@^2.0.3:
resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
tldts-core@^7.4.4:
version "7.4.4"
resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-7.4.4.tgz#a06de228c70a334e26d1597af7a82376e8588bce"
integrity sha512-vwVLJVvvpslm7vqAH7+XNj/neA/Ynq7DT2EEcMuwc5YzN5XaMyRAqxwU+uX3azZ1FQtB2gvrvnLnAEkvYlVdfg==
tldts-core@^7.4.6:
version "7.4.6"
resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-7.4.6.tgz#4cc8ccdae554742f09e5999708cac5a7d83cb287"
integrity sha512-TkQNGJIhlEphpHCjKodMTSe23egUZr/g+flI2qkLgiJ/maAzSgXypSLRTNH3nCmqgayEmtcJBiLcfODSAr1xoA==
tldts@^7.0.5:
version "7.4.4"
resolved "https://registry.yarnpkg.com/tldts/-/tldts-7.4.4.tgz#343191348abbff80118732a1a84e90fcf95b29df"
integrity sha512-kFXFK7O4WPextIUAOk8qtnw9dxR9UIXP9CjuH1cTBVBZMDeQcUPgr/IazGiw1B0Yiw5L75gHLWeW4iD793r90g==
version "7.4.6"
resolved "https://registry.yarnpkg.com/tldts/-/tldts-7.4.6.tgz#3af5da04b35afd0e00cf0fe2827af30393a28202"
integrity sha512-rbP0Gyx8b3Ae9yO//CU2wbSnQNoQ66m1nJdSbSHmnwKwzkkz/u8mERYU8T2rmlmy+bJvRNn84yNCW8gYqox44Q==
dependencies:
tldts-core "^7.4.4"
tldts-core "^7.4.6"
token-types@^4.1.1:
version "4.2.1"