Compare commits
6 Commits
cf886b9581
...
1.2
| Author | SHA1 | Date | |
|---|---|---|---|
| ae2cde3545 | |||
|
|
1000319b8f
|
||
|
|
8c4c5e16e0
|
||
|
|
0ce1e604a8
|
||
|
|
757783534c
|
||
|
|
3eba48ea7d
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
- name: set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: 17
|
||||
java-version: 21
|
||||
distribution: "temurin"
|
||||
|
||||
- name: Setup Gradle
|
||||
|
||||
@@ -1,27 +1,38 @@
|
||||
def getCommitCount() {
|
||||
try {
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine 'git', 'rev-list', '--count', 'HEAD'
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim().toInteger()
|
||||
} catch (ignored) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version '2.3.21'
|
||||
id 'org.jetbrains.kotlin.plugin.compose' version '2.3.21'
|
||||
id 'com.mikepenz.aboutlibraries.plugin' version '14.2.0'
|
||||
}
|
||||
|
||||
|
||||
android {
|
||||
namespace 'net.helcel.beans'
|
||||
compileSdk 36
|
||||
compileSdk = 37
|
||||
|
||||
defaultConfig {
|
||||
buildConfigField("String", "APP_NAME", "\"Beans\"")
|
||||
manifestPlaceholders["APP_NAME"] = "Beans"
|
||||
applicationId 'net.helcel.beans'
|
||||
minSdk 28
|
||||
targetSdk 36
|
||||
versionCode 4
|
||||
versionName "1.1a"
|
||||
minSdk = 28
|
||||
targetSdk = 37
|
||||
versionName "1.2"
|
||||
versionCode getCommitCount()
|
||||
}
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
register("release") {
|
||||
try {
|
||||
def keystorePropertiesFile = rootProject.file("app/keystore.properties")
|
||||
def keystoreProperties = new Properties()
|
||||
@@ -36,20 +47,18 @@ android {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
debuggable true
|
||||
}
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources false
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
signedRelease {
|
||||
minifyEnabled true
|
||||
shrinkResources false
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
@@ -78,10 +87,6 @@ android {
|
||||
kotlinCompilerExtensionVersion = "2.2.20"
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(21)
|
||||
}
|
||||
|
||||
lint {
|
||||
disable 'UsingMaterialAndMaterial3Libraries'
|
||||
}
|
||||
@@ -91,7 +96,6 @@ aboutLibraries {
|
||||
library {
|
||||
exclusionPatterns = [~"androidx.*", ~"com.google.android.*", ~"org.jetbrains.*"]
|
||||
}
|
||||
excludeFields = ["generated"]
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
android:hardwareAccelerated="false"
|
||||
android:icon="@mipmap/ic_launcher_round"
|
||||
android:label="${APP_NAME}"
|
||||
android:supportsRtl="true"
|
||||
tools:replace="android:allowBackup">
|
||||
android:supportsRtl="true">
|
||||
<activity
|
||||
android:name=".activity.MainScreen"
|
||||
android:exported="true">
|
||||
|
||||
@@ -16,7 +16,6 @@ import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.DateRange
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.Percent
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
|
||||
@@ -152,11 +152,17 @@ fun SettingsMainScreen(onExit: ()->Unit = {}) {
|
||||
fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
||||
val context = LocalContext.current
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val keyTheme = stringResource(R.string.key_theme)
|
||||
val defaultTheme = stringResource(R.string.system)
|
||||
val keyProjection = stringResource(R.string.key_projection)
|
||||
val keyGroup = stringResource(R.string.key_group)
|
||||
val offString = stringResource(R.string.off)
|
||||
|
||||
var showEdit by remember { mutableStateOf(false) }
|
||||
|
||||
var theme by remember { mutableStateOf(prefs.getString(context.getString(R.string.key_theme), context.getString(R.string.system))!!) }
|
||||
var projection by remember { mutableStateOf(prefs.getString(context.getString(R.string.key_projection), "default")!!) }
|
||||
var groups by remember { mutableStateOf(prefs.getString(context.getString(R.string.key_group), context.getString(R.string.off))!!) }
|
||||
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)!!) }
|
||||
|
||||
if(showEdit)
|
||||
EditPlaceDialog(true) {
|
||||
@@ -179,7 +185,7 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
||||
)
|
||||
MultiPreference(arrayOf(stringResource(R.string.system),stringResource(R.string.light),stringResource(R.string.dark)), theme) { newTheme ->
|
||||
theme = newTheme
|
||||
prefs.edit { putString(context.getString(R.string.key_theme), newTheme) }
|
||||
prefs.edit { putString(keyTheme, newTheme) }
|
||||
}
|
||||
HorizontalDivider()
|
||||
}
|
||||
@@ -192,7 +198,7 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
||||
)
|
||||
MultiPreference(arrayOf(stringResource(R.string.mercator), stringResource(R.string.azimuthalequidistant)), projection) { newProj ->
|
||||
projection = newProj
|
||||
prefs.edit { putString(context.getString(R.string.key_projection), newProj) }
|
||||
prefs.edit { putString(keyProjection, newProj) }
|
||||
Settings.refreshProjection()
|
||||
}
|
||||
HorizontalDivider()
|
||||
@@ -219,11 +225,11 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
||||
arrayOf(stringResource(R.string.on), stringResource(R.string.off)),
|
||||
groups
|
||||
) { key ->
|
||||
if (key == context.getString(R.string.off)) {
|
||||
if (key == offString) {
|
||||
showDialog=true
|
||||
}
|
||||
groups = key
|
||||
prefs.edit { putString(context.getString(R.string.key_group), key) }
|
||||
prefs.edit { putString(keyGroup, key) }
|
||||
}
|
||||
HorizontalDivider()
|
||||
}
|
||||
@@ -283,9 +289,13 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
||||
@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(context.getString(R.string.key_regional),context.getString(R.string.off))!!)}
|
||||
var regional by remember{ mutableStateOf(prefs.getString(context.getString(R.string.key_regional), context.getString(R.string.off))!!)}
|
||||
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)}
|
||||
|
||||
@@ -305,7 +315,7 @@ fun RegionalScreen() {
|
||||
regional= selected
|
||||
prefs.edit {
|
||||
putString(
|
||||
context.getString(R.string.key_regional),
|
||||
keyRegional,
|
||||
regional
|
||||
)
|
||||
}
|
||||
@@ -332,12 +342,12 @@ fun RegionalScreen() {
|
||||
val scope = rememberCoroutineScope()
|
||||
MultiPreference(arrayOf(stringResource(R.string.on),stringResource(R.string.off)),regional) { key ->
|
||||
when (key) {
|
||||
context.getString(R.string.off) -> { showDialog=true
|
||||
offString -> { showDialog=true
|
||||
selected=key
|
||||
}
|
||||
context.getString(R.string.on) -> {
|
||||
onString -> {
|
||||
regional = key
|
||||
prefs.edit { putString(context.getString(R.string.key_regional), key) }
|
||||
prefs.edit { putString(keyRegional, key) }
|
||||
showLoad=true
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
@@ -354,7 +364,7 @@ fun RegionalScreen() {
|
||||
@Composable
|
||||
fun MultiPreference(list: Array<String>, selected: String, onSelected: (String) -> Unit) {
|
||||
Column(Modifier.padding(2.dp)) {
|
||||
list.map { value ->
|
||||
list.forEach { value ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
|
||||
@@ -115,7 +115,6 @@ fun StatsList(activeMode: LocType, countMode: Boolean) {
|
||||
|
||||
@Composable
|
||||
fun StatsRow(group: Groups.Group, activeMode: LocType, countMode: Boolean) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val visited = remember(group, activeMode) {
|
||||
Data.visits.getVisitedByValue(group.key)
|
||||
@@ -124,18 +123,18 @@ fun StatsRow(group: Groups.Group, activeMode: LocType, countMode: Boolean) {
|
||||
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 { itc->itc.children.flatMap { it.children.filter { it.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 = 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 { it.children.flatMap { it.children.filter { it.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
|
||||
}
|
||||
|
||||
val displayValue = if (countMode) count.toString() else context.getString(R.string.number_with_unit, area, "km²")
|
||||
val displayValue = if (countMode) count.toString() else stringResource(R.string.number_with_unit, area, "km²")
|
||||
|
||||
val backgroundColor = group.color.color
|
||||
val textColor = getContrastColor(backgroundColor)
|
||||
|
||||
@@ -58,7 +58,7 @@ fun syncVisited(loc: GeoLoc?=World.WWW){
|
||||
loc?.children?.forEach { tt ->
|
||||
tt.children.forEach {itc->
|
||||
if(Data.visits.getVisited(itc) in listOf(AUTO_GROUP,NO_GROUP)) {
|
||||
if(itc.children.any { itcc -> Data.visits.getVisited(itcc) != NO_GROUP })
|
||||
if(itc.children.any { c -> Data.visits.getVisited(c) != NO_GROUP })
|
||||
Data.visits.setVisited(itc, AUTO_GROUP)
|
||||
else
|
||||
Data.visits.setVisited(itc, NO_GROUP)
|
||||
@@ -111,21 +111,20 @@ fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) {
|
||||
|
||||
Column {
|
||||
val currentTab = tabs.getOrNull(selectedTab) ?: return@Column
|
||||
TabRow(
|
||||
selectedTabIndex = min(tabs.lastIndex, selectedTab),
|
||||
) {
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
Tab(
|
||||
selected = selectedTab == index,
|
||||
onClick = {
|
||||
while (tabs.size > index + 1)
|
||||
tabs.removeAt(tabs.lastIndex)
|
||||
},
|
||||
text = { Text(tab.fullName) }
|
||||
)
|
||||
}
|
||||
TabRow(
|
||||
selectedTabIndex = min(tabs.lastIndex, selectedTab),
|
||||
) {
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
Tab(
|
||||
selected = selectedTab == index,
|
||||
onClick = {
|
||||
while (tabs.size > index + 1)
|
||||
tabs.removeAt(tabs.lastIndex)
|
||||
},
|
||||
text = { Text(tab.fullName) }
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
|
||||
@@ -7,7 +7,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.mikepenz.aboutlibraries.ui.compose.DefaultChipColors
|
||||
import com.mikepenz.aboutlibraries.ui.compose.DefaultLibraryColors
|
||||
import com.mikepenz.aboutlibraries.ui.compose.android.rememberLibraries
|
||||
import com.mikepenz.aboutlibraries.ui.compose.android.produceLibraries
|
||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
||||
import net.helcel.beans.R
|
||||
import net.helcel.beans.activity.SysTheme
|
||||
@@ -16,14 +16,14 @@ import net.helcel.beans.activity.SysTheme
|
||||
@Preview
|
||||
@Composable
|
||||
fun LicenseScreen() {
|
||||
val libraries = rememberLibraries(R.raw.aboutlibraries)
|
||||
val libraries = produceLibraries(R.raw.aboutlibraries)
|
||||
SysTheme {
|
||||
LibrariesContainer(
|
||||
libraries = libraries.value,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
colors = DefaultLibraryColors(
|
||||
backgroundColor = MaterialTheme.colors.background,
|
||||
contentColor = MaterialTheme.colors.onBackground,
|
||||
libraryBackgroundColor = MaterialTheme.colors.background,
|
||||
libraryContentColor = MaterialTheme.colors.onBackground,
|
||||
licenseChipColors = DefaultChipColors(
|
||||
containerColor = MaterialTheme.colors.primary,
|
||||
contentColor = MaterialTheme.colors.onPrimary,
|
||||
@@ -37,6 +37,8 @@ fun LicenseScreen() {
|
||||
contentColor = MaterialTheme.colors.onSecondary,
|
||||
),
|
||||
dialogConfirmButtonColor = MaterialTheme.colors.primary,
|
||||
dialogBackgroundColor = MaterialTheme.colors.onPrimary,
|
||||
dialogContentColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.helcel.beans.countries
|
||||
|
||||
import net.helcel.beans.countries.Country.*
|
||||
|
||||
@Suppress("RedundantSuppression", "SpellCheckingInspection", "unused")
|
||||
enum class Group(override val fullName: String, override val children: Set<GeoLoc>) : GeoLoc {
|
||||
|
||||
EEE(
|
||||
|
||||
@@ -24,53 +24,53 @@ const val AUTO_GROUP = -1
|
||||
|
||||
|
||||
@Serializable
|
||||
class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
|
||||
class Groups(val id: Int, private val groups: HashMap<Int, Group>) {
|
||||
@kotlinx.serialization.Transient
|
||||
private val _groupsFlow = MutableStateFlow<List<Group>>(grps.values.toList())
|
||||
private val _groupsFlow = MutableStateFlow<List<Group>>(groups.values.toList())
|
||||
@kotlinx.serialization.Transient
|
||||
val groupsFlow: StateFlow<List<Group>> = _groupsFlow.asStateFlow()
|
||||
|
||||
fun setGroup(key: Int, name: String, col: ColorDrawable) {
|
||||
grps[key] = Group(key, name, col)
|
||||
_groupsFlow.value = grps.values.toList()
|
||||
groups[key] = Group(key, name, col)
|
||||
_groupsFlow.value = groups.values.toList()
|
||||
}
|
||||
|
||||
fun deleteGroup(key: Int) {
|
||||
grps.remove(key)
|
||||
_groupsFlow.value = grps.values.toList()
|
||||
groups.remove(key)
|
||||
_groupsFlow.value = groups.values.toList()
|
||||
}
|
||||
|
||||
fun getGroupFromKey(key: Int): Group {
|
||||
return grps.getOrDefault(key, EmptyGroup())
|
||||
return groups.getOrDefault(key, EmptyGroup())
|
||||
}
|
||||
|
||||
fun genKey(): Int {
|
||||
val key = rnd.nextInt()
|
||||
if (grps.containsKey(key) || key in listOf(NO_GROUP, DEFAULT_GROUP, AUTO_GROUP)) return genKey()
|
||||
if (groups.containsKey(key) || key in listOf(NO_GROUP, DEFAULT_GROUP, AUTO_GROUP)) return genKey()
|
||||
return key
|
||||
}
|
||||
|
||||
fun size(): Int {
|
||||
return grps.size
|
||||
return groups.size
|
||||
}
|
||||
|
||||
fun getUniqueEntry(): Group? {
|
||||
assert(size() == 1)
|
||||
return if (grps.size == 1) {
|
||||
grps[grps.keys.first()]
|
||||
return if (groups.size == 1) {
|
||||
groups[groups.keys.first()]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun getGroupFromPos(pos: Int): Pair<Int, Group> {
|
||||
if(grps.keys.isEmpty()) return Pair(NO_GROUP,Group(NO_GROUP,"-"))
|
||||
val key = grps.keys.toList()[pos]
|
||||
if(groups.keys.isEmpty()) return Pair(NO_GROUP,Group(NO_GROUP,"-"))
|
||||
val key = groups.keys.toList()[pos]
|
||||
return Pair(key, getGroupFromKey(key))
|
||||
}
|
||||
|
||||
fun findGroupPos(key: Int): Int {
|
||||
return grps.keys.toList().indexOf(key)
|
||||
return groups.keys.toList().indexOf(key)
|
||||
}
|
||||
|
||||
class EmptyGroup : Group(0, "")
|
||||
|
||||
@@ -2,4 +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"/>
|
||||
</adaptive-icon>
|
||||
@@ -1,24 +1,9 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=false
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.nonTransitiveRClass=true
|
||||
android.uniquePackageNames=false
|
||||
android.dependency.useConstraints=false
|
||||
android.r8.strictFullModeForKeepRules=false
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@turf/area": "^7.0.0",
|
||||
"@turf/turf": "^7.0.0",
|
||||
"jsdom": "^29.0.0",
|
||||
"mapshaper": "^0.7.0"
|
||||
"@turf/area": "^7.3.5",
|
||||
"@turf/turf": "^7.3.5",
|
||||
"jsdom": "^29.1.1",
|
||||
"mapshaper": "^0.7.19"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ pluginManagement {
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
|
||||
Reference in New Issue
Block a user