Compare commits
1 Commits
1.2
...
7e3173f4cc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e3173f4cc |
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@@ -32,6 +32,7 @@ jobs:
|
|||||||
gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch keystore.asc > app/keystore.properties
|
gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch keystore.asc > app/keystore.properties
|
||||||
gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch key.asc > app/key.jks
|
gpg -d --passphrase "${{ secrets.RELEASE_KEYSTORE_PASSWORD }}" --batch key.asc > app/key.jks
|
||||||
|
|
||||||
|
- uses: gradle/wrapper-validation-action@v3
|
||||||
|
|
||||||
- name: create and checkout branch
|
- name: create and checkout branch
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
@@ -42,17 +43,15 @@ jobs:
|
|||||||
- name: set up JDK
|
- name: set up JDK
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
java-version: 21
|
java-version: 17
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
|
cache: 'gradle'
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v6
|
|
||||||
|
|
||||||
- name: Build APK
|
- name: Build APK
|
||||||
run: ./gradlew assembleSignedRelease
|
run: ./gradlew assembleSignedRelease
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v3
|
uses: softprops/action-gh-release@v2
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
|
|||||||
@@ -1,38 +1,27 @@
|
|||||||
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 {
|
plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'org.jetbrains.kotlin.plugin.serialization' version '2.3.21'
|
id 'org.jetbrains.kotlin.android'
|
||||||
id 'org.jetbrains.kotlin.plugin.compose' version '2.3.21'
|
id 'org.jetbrains.kotlin.plugin.serialization' version '2.3.10'
|
||||||
id 'com.mikepenz.aboutlibraries.plugin' version '14.2.0'
|
id 'org.jetbrains.kotlin.plugin.compose' version '2.3.10'
|
||||||
|
id 'com.mikepenz.aboutlibraries.plugin' version '13.2.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'net.helcel.beans'
|
namespace 'net.helcel.beans'
|
||||||
compileSdk = 37
|
compileSdk 36
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
buildConfigField("String", "APP_NAME", "\"Beans\"")
|
buildConfigField("String", "APP_NAME", "\"Beans\"")
|
||||||
manifestPlaceholders["APP_NAME"] = "Beans"
|
manifestPlaceholders["APP_NAME"] = "Beans"
|
||||||
applicationId 'net.helcel.beans'
|
applicationId 'net.helcel.beans'
|
||||||
minSdk = 28
|
minSdk 28
|
||||||
targetSdk = 37
|
targetSdk 36
|
||||||
versionName "1.2"
|
versionCode 4
|
||||||
versionCode getCommitCount()
|
versionName "1.1a"
|
||||||
}
|
}
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
register("release") {
|
create("release") {
|
||||||
try {
|
try {
|
||||||
def keystorePropertiesFile = rootProject.file("app/keystore.properties")
|
def keystorePropertiesFile = rootProject.file("app/keystore.properties")
|
||||||
def keystoreProperties = new Properties()
|
def keystoreProperties = new Properties()
|
||||||
@@ -47,18 +36,20 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
debuggable true
|
debuggable true
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
signedRelease {
|
signedRelease {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
signingConfig = signingConfigs.getByName("release")
|
signingConfig = signingConfigs.getByName("release")
|
||||||
}
|
}
|
||||||
@@ -87,6 +78,10 @@ android {
|
|||||||
kotlinCompilerExtensionVersion = "2.2.20"
|
kotlinCompilerExtensionVersion = "2.2.20"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(21)
|
||||||
|
}
|
||||||
|
|
||||||
lint {
|
lint {
|
||||||
disable 'UsingMaterialAndMaterial3Libraries'
|
disable 'UsingMaterialAndMaterial3Libraries'
|
||||||
}
|
}
|
||||||
@@ -96,33 +91,34 @@ aboutLibraries {
|
|||||||
library {
|
library {
|
||||||
exclusionPatterns = [~"androidx.*", ~"com.google.android.*", ~"org.jetbrains.*"]
|
exclusionPatterns = [~"androidx.*", ~"com.google.android.*", ~"org.jetbrains.*"]
|
||||||
}
|
}
|
||||||
|
excludeFields = ["generated"]
|
||||||
}
|
}
|
||||||
|
|
||||||
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.10.3"
|
||||||
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.7'
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.1.5'
|
||||||
|
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.11.0'
|
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0'
|
||||||
|
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.1'
|
implementation 'androidx.preference:preference-ktx:1.2.1'
|
||||||
implementation 'androidx.compose.ui:ui'
|
implementation 'androidx.compose.ui:ui'
|
||||||
implementation "androidx.activity:activity-ktx:1.13.0"
|
implementation "androidx.activity:activity-ktx:1.12.4"
|
||||||
|
|
||||||
implementation 'androidx.compose.ui:ui-tooling-preview'
|
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||||
implementation 'com.google.android.material:material:1.14.0'
|
implementation 'com.google.android.material:material:1.13.0'
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.11.0'
|
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0'
|
||||||
|
|
||||||
implementation 'com.caverock:androidsvg-aar:1.4'
|
implementation 'com.caverock:androidsvg-aar:1.4'
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
|
|
||||||
implementation 'com.mikepenz:aboutlibraries:14.2.0'
|
implementation 'com.mikepenz:aboutlibraries:13.2.1'
|
||||||
implementation 'com.mikepenz:aboutlibraries-compose-m3:14.2.0'
|
implementation 'com.mikepenz:aboutlibraries-compose-m3:13.2.1'
|
||||||
implementation 'com.mikepenz:aboutlibraries-core:14.2.0'
|
implementation 'com.mikepenz:aboutlibraries-core:13.2.1'
|
||||||
|
|
||||||
|
|
||||||
implementation platform('androidx.compose:compose-bom:2026.05.01')
|
implementation platform('androidx.compose:compose-bom:2026.01.01')
|
||||||
debugImplementation 'androidx.compose.ui:ui-tooling:1.11.2'
|
debugImplementation 'androidx.compose.ui:ui-tooling:1.10.2'
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
android:hardwareAccelerated="false"
|
android:hardwareAccelerated="false"
|
||||||
android:icon="@mipmap/ic_launcher_round"
|
android:icon="@mipmap/ic_launcher_round"
|
||||||
android:label="${APP_NAME}"
|
android:label="${APP_NAME}"
|
||||||
android:supportsRtl="true">
|
android:supportsRtl="true"
|
||||||
|
tools:replace="android:allowBackup">
|
||||||
<activity
|
<activity
|
||||||
android:name=".activity.MainScreen"
|
android:name=".activity.MainScreen"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.compose.material.Scaffold
|
|||||||
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
|
||||||
|
import androidx.compose.material.icons.filled.DateRange
|
||||||
import androidx.compose.material.icons.filled.Edit
|
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
|
||||||
|
|||||||
@@ -152,17 +152,11 @@ fun SettingsMainScreen(onExit: ()->Unit = {}) {
|
|||||||
fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
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 showEdit by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
var theme by remember { mutableStateOf(prefs.getString(keyTheme, defaultTheme)!!) }
|
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(keyProjection, "default")!!) }
|
var projection by remember { mutableStateOf(prefs.getString(context.getString(R.string.key_projection), "default")!!) }
|
||||||
var groups by remember { mutableStateOf(prefs.getString(keyGroup,offString)!!) }
|
var groups by remember { mutableStateOf(prefs.getString(context.getString(R.string.key_group), context.getString(R.string.off))!!) }
|
||||||
|
|
||||||
if(showEdit)
|
if(showEdit)
|
||||||
EditPlaceDialog(true) {
|
EditPlaceDialog(true) {
|
||||||
@@ -185,7 +179,7 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
|||||||
)
|
)
|
||||||
MultiPreference(arrayOf(stringResource(R.string.system),stringResource(R.string.light),stringResource(R.string.dark)), theme) { newTheme ->
|
MultiPreference(arrayOf(stringResource(R.string.system),stringResource(R.string.light),stringResource(R.string.dark)), theme) { newTheme ->
|
||||||
theme = newTheme
|
theme = newTheme
|
||||||
prefs.edit { putString(keyTheme, newTheme) }
|
prefs.edit { putString(context.getString(R.string.key_theme), newTheme) }
|
||||||
}
|
}
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
}
|
}
|
||||||
@@ -198,7 +192,7 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
|||||||
)
|
)
|
||||||
MultiPreference(arrayOf(stringResource(R.string.mercator), stringResource(R.string.azimuthalequidistant)), projection) { newProj ->
|
MultiPreference(arrayOf(stringResource(R.string.mercator), stringResource(R.string.azimuthalequidistant)), projection) { newProj ->
|
||||||
projection = newProj
|
projection = newProj
|
||||||
prefs.edit { putString(keyProjection, newProj) }
|
prefs.edit { putString(context.getString(R.string.key_projection), newProj) }
|
||||||
Settings.refreshProjection()
|
Settings.refreshProjection()
|
||||||
}
|
}
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
@@ -225,11 +219,11 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
|||||||
arrayOf(stringResource(R.string.on), stringResource(R.string.off)),
|
arrayOf(stringResource(R.string.on), stringResource(R.string.off)),
|
||||||
groups
|
groups
|
||||||
) { key ->
|
) { key ->
|
||||||
if (key == offString) {
|
if (key == context.getString(R.string.off)) {
|
||||||
showDialog=true
|
showDialog=true
|
||||||
}
|
}
|
||||||
groups = key
|
groups = key
|
||||||
prefs.edit { putString(keyGroup, key) }
|
prefs.edit { putString(context.getString(R.string.key_group), key) }
|
||||||
}
|
}
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
}
|
}
|
||||||
@@ -289,13 +283,9 @@ fun SettingsScreen(navController: NavHostController = settingsNav()) {
|
|||||||
@Composable
|
@Composable
|
||||||
fun RegionalScreen() {
|
fun RegionalScreen() {
|
||||||
val context = LocalContext.current
|
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)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
var selected by remember { mutableStateOf(prefs.getString(keyRegional, offString)!!)}
|
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(keyRegional, offString)!!)}
|
var regional by remember{ mutableStateOf(prefs.getString(context.getString(R.string.key_regional), context.getString(R.string.off))!!)}
|
||||||
var showDialog by remember{mutableStateOf(false)}
|
var showDialog by remember{mutableStateOf(false)}
|
||||||
var showLoad by remember{mutableStateOf(false)}
|
var showLoad by remember{mutableStateOf(false)}
|
||||||
|
|
||||||
@@ -315,7 +305,7 @@ fun RegionalScreen() {
|
|||||||
regional= selected
|
regional= selected
|
||||||
prefs.edit {
|
prefs.edit {
|
||||||
putString(
|
putString(
|
||||||
keyRegional,
|
context.getString(R.string.key_regional),
|
||||||
regional
|
regional
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -342,12 +332,12 @@ fun RegionalScreen() {
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
MultiPreference(arrayOf(stringResource(R.string.on),stringResource(R.string.off)),regional) { key ->
|
MultiPreference(arrayOf(stringResource(R.string.on),stringResource(R.string.off)),regional) { key ->
|
||||||
when (key) {
|
when (key) {
|
||||||
offString -> { showDialog=true
|
context.getString(R.string.off) -> { showDialog=true
|
||||||
selected=key
|
selected=key
|
||||||
}
|
}
|
||||||
onString -> {
|
context.getString(R.string.on) -> {
|
||||||
regional = key
|
regional = key
|
||||||
prefs.edit { putString(keyRegional, key) }
|
prefs.edit { putString(context.getString(R.string.key_regional), key) }
|
||||||
showLoad=true
|
showLoad=true
|
||||||
scope.launch {
|
scope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
@@ -364,7 +354,7 @@ fun RegionalScreen() {
|
|||||||
@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(2.dp)) {
|
||||||
list.forEach { value ->
|
list.map { value ->
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ 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 visited = remember(group, activeMode) {
|
val visited = remember(group, activeMode) {
|
||||||
Data.visits.getVisitedByValue(group.key)
|
Data.visits.getVisitedByValue(group.key)
|
||||||
@@ -123,18 +124,18 @@ fun StatsRow(group: Groups.Group, activeMode: LocType, countMode: Boolean) {
|
|||||||
val count = when (activeMode) {
|
val count = when (activeMode) {
|
||||||
LocType.WORLD -> World.WWW.children.filter { it.code in visited }.size
|
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.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
|
LocType.STATE -> World.WWW.children.flatMap { itc->itc.children.flatMap { it.children.filter { it.code in visited } } }.size
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
|
|
||||||
val area = when (activeMode) {
|
val area = when (activeMode) {
|
||||||
LocType.WORLD -> World.WWW.children.filter { it.code in visited }.sumOf { it.area }
|
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.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 }
|
LocType.STATE -> World.WWW.children.flatMap { it.children.flatMap { it.children.filter { it.code in visited } } }.sumOf { it.area }
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
|
|
||||||
val displayValue = if (countMode) count.toString() else stringResource(R.string.number_with_unit, area, "km²")
|
val displayValue = if (countMode) count.toString() else context.getString(R.string.number_with_unit, area, "km²")
|
||||||
|
|
||||||
val backgroundColor = group.color.color
|
val backgroundColor = group.color.color
|
||||||
val textColor = getContrastColor(backgroundColor)
|
val textColor = getContrastColor(backgroundColor)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ fun syncVisited(loc: GeoLoc?=World.WWW){
|
|||||||
loc?.children?.forEach { tt ->
|
loc?.children?.forEach { tt ->
|
||||||
tt.children.forEach {itc->
|
tt.children.forEach {itc->
|
||||||
if(Data.visits.getVisited(itc) in listOf(AUTO_GROUP,NO_GROUP)) {
|
if(Data.visits.getVisited(itc) in listOf(AUTO_GROUP,NO_GROUP)) {
|
||||||
if(itc.children.any { c -> Data.visits.getVisited(c) != NO_GROUP })
|
if(itc.children.any { itcc -> Data.visits.getVisited(itcc) != NO_GROUP })
|
||||||
Data.visits.setVisited(itc, AUTO_GROUP)
|
Data.visits.setVisited(itc, AUTO_GROUP)
|
||||||
else
|
else
|
||||||
Data.visits.setVisited(itc, NO_GROUP)
|
Data.visits.setVisited(itc, NO_GROUP)
|
||||||
@@ -111,20 +111,21 @@ fun EditPlaceScreen(loc: GeoLoc, onExit:()->Unit={}) {
|
|||||||
|
|
||||||
Column {
|
Column {
|
||||||
val currentTab = tabs.getOrNull(selectedTab) ?: return@Column
|
val currentTab = tabs.getOrNull(selectedTab) ?: return@Column
|
||||||
TabRow(
|
TabRow(
|
||||||
selectedTabIndex = min(tabs.lastIndex, selectedTab),
|
selectedTabIndex = min(tabs.lastIndex, selectedTab),
|
||||||
) {
|
) {
|
||||||
tabs.forEachIndexed { index, tab ->
|
tabs.forEachIndexed { index, tab ->
|
||||||
Tab(
|
Tab(
|
||||||
selected = selectedTab == index,
|
selected = selectedTab == index,
|
||||||
onClick = {
|
onClick = {
|
||||||
while (tabs.size > index + 1)
|
while (tabs.size > index + 1)
|
||||||
tabs.removeAt(tabs.lastIndex)
|
tabs.removeAt(tabs.lastIndex)
|
||||||
},
|
},
|
||||||
text = { Text(tab.fullName) }
|
text = { Text(tab.fullName) }
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.DefaultChipColors
|
import com.mikepenz.aboutlibraries.ui.compose.DefaultChipColors
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.DefaultLibraryColors
|
import com.mikepenz.aboutlibraries.ui.compose.DefaultLibraryColors
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.android.produceLibraries
|
import com.mikepenz.aboutlibraries.ui.compose.android.rememberLibraries
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
|
||||||
import net.helcel.beans.R
|
import net.helcel.beans.R
|
||||||
import net.helcel.beans.activity.SysTheme
|
import net.helcel.beans.activity.SysTheme
|
||||||
@@ -16,14 +16,14 @@ import net.helcel.beans.activity.SysTheme
|
|||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun LicenseScreen() {
|
fun LicenseScreen() {
|
||||||
val libraries = produceLibraries(R.raw.aboutlibraries)
|
val libraries = rememberLibraries(R.raw.aboutlibraries)
|
||||||
SysTheme {
|
SysTheme {
|
||||||
LibrariesContainer(
|
LibrariesContainer(
|
||||||
libraries = libraries.value,
|
libraries = libraries.value,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
colors = DefaultLibraryColors(
|
colors = DefaultLibraryColors(
|
||||||
libraryBackgroundColor = MaterialTheme.colors.background,
|
backgroundColor = MaterialTheme.colors.background,
|
||||||
libraryContentColor = MaterialTheme.colors.onBackground,
|
contentColor = MaterialTheme.colors.onBackground,
|
||||||
licenseChipColors = DefaultChipColors(
|
licenseChipColors = DefaultChipColors(
|
||||||
containerColor = MaterialTheme.colors.primary,
|
containerColor = MaterialTheme.colors.primary,
|
||||||
contentColor = MaterialTheme.colors.onPrimary,
|
contentColor = MaterialTheme.colors.onPrimary,
|
||||||
@@ -37,8 +37,6 @@ fun LicenseScreen() {
|
|||||||
contentColor = MaterialTheme.colors.onSecondary,
|
contentColor = MaterialTheme.colors.onSecondary,
|
||||||
),
|
),
|
||||||
dialogConfirmButtonColor = MaterialTheme.colors.primary,
|
dialogConfirmButtonColor = MaterialTheme.colors.primary,
|
||||||
dialogBackgroundColor = MaterialTheme.colors.onPrimary,
|
|
||||||
dialogContentColor = MaterialTheme.colors.primary,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package net.helcel.beans.countries
|
|||||||
|
|
||||||
import net.helcel.beans.countries.Country.*
|
import net.helcel.beans.countries.Country.*
|
||||||
|
|
||||||
@Suppress("RedundantSuppression", "SpellCheckingInspection", "unused")
|
|
||||||
enum class Group(override val fullName: String, override val children: Set<GeoLoc>) : GeoLoc {
|
enum class Group(override val fullName: String, override val children: Set<GeoLoc>) : GeoLoc {
|
||||||
|
|
||||||
EEE(
|
EEE(
|
||||||
|
|||||||
@@ -24,53 +24,53 @@ const val AUTO_GROUP = -1
|
|||||||
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class Groups(val id: Int, private val groups: HashMap<Int, Group>) {
|
class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
|
||||||
@kotlinx.serialization.Transient
|
@kotlinx.serialization.Transient
|
||||||
private val _groupsFlow = MutableStateFlow<List<Group>>(groups.values.toList())
|
private val _groupsFlow = MutableStateFlow<List<Group>>(grps.values.toList())
|
||||||
@kotlinx.serialization.Transient
|
@kotlinx.serialization.Transient
|
||||||
val groupsFlow: StateFlow<List<Group>> = _groupsFlow.asStateFlow()
|
val groupsFlow: StateFlow<List<Group>> = _groupsFlow.asStateFlow()
|
||||||
|
|
||||||
fun setGroup(key: Int, name: String, col: ColorDrawable) {
|
fun setGroup(key: Int, name: String, col: ColorDrawable) {
|
||||||
groups[key] = Group(key, name, col)
|
grps[key] = Group(key, name, col)
|
||||||
_groupsFlow.value = groups.values.toList()
|
_groupsFlow.value = grps.values.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteGroup(key: Int) {
|
fun deleteGroup(key: Int) {
|
||||||
groups.remove(key)
|
grps.remove(key)
|
||||||
_groupsFlow.value = groups.values.toList()
|
_groupsFlow.value = grps.values.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGroupFromKey(key: Int): Group {
|
fun getGroupFromKey(key: Int): Group {
|
||||||
return groups.getOrDefault(key, EmptyGroup())
|
return grps.getOrDefault(key, EmptyGroup())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun genKey(): Int {
|
fun genKey(): Int {
|
||||||
val key = rnd.nextInt()
|
val key = rnd.nextInt()
|
||||||
if (groups.containsKey(key) || key in listOf(NO_GROUP, DEFAULT_GROUP, AUTO_GROUP)) return genKey()
|
if (grps.containsKey(key) || key in listOf(NO_GROUP, DEFAULT_GROUP, AUTO_GROUP)) return genKey()
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
fun size(): Int {
|
fun size(): Int {
|
||||||
return groups.size
|
return grps.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUniqueEntry(): Group? {
|
fun getUniqueEntry(): Group? {
|
||||||
assert(size() == 1)
|
assert(size() == 1)
|
||||||
return if (groups.size == 1) {
|
return if (grps.size == 1) {
|
||||||
groups[groups.keys.first()]
|
grps[grps.keys.first()]
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGroupFromPos(pos: Int): Pair<Int, Group> {
|
fun getGroupFromPos(pos: Int): Pair<Int, Group> {
|
||||||
if(groups.keys.isEmpty()) return Pair(NO_GROUP,Group(NO_GROUP,"-"))
|
if(grps.keys.isEmpty()) return Pair(NO_GROUP,Group(NO_GROUP,"-"))
|
||||||
val key = groups.keys.toList()[pos]
|
val key = grps.keys.toList()[pos]
|
||||||
return Pair(key, getGroupFromKey(key))
|
return Pair(key, getGroupFromKey(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findGroupPos(key: Int): Int {
|
fun findGroupPos(key: Int): Int {
|
||||||
return groups.keys.toList().indexOf(key)
|
return grps.keys.toList().indexOf(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmptyGroup : Group(0, "")
|
class EmptyGroup : Group(0, "")
|
||||||
|
|||||||
@@ -2,5 +2,4 @@
|
|||||||
<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"/>
|
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '9.2.1' apply false
|
id 'com.android.application' version '9.0.0' apply false
|
||||||
id 'com.android.library' version '9.2.1' apply false
|
id 'com.android.library' version '9.0.0' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '2.3.21' apply false
|
id 'org.jetbrains.kotlin.android' version '2.3.10' apply false
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,24 @@
|
|||||||
# Project-wide Gradle settings.
|
# 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
|
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.useAndroidX=true
|
||||||
android.enableJetifier=false
|
android.enableJetifier=false
|
||||||
|
# Kotlin code style for this project: "official" or "obsolete":
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
android.nonTransitiveRClass=true
|
# Enables namespacing of each library's R class so that its R class includes only the
|
||||||
android.uniquePackageNames=false
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
android.dependency.useConstraints=false
|
# thereby reducing the size of the R class for that library
|
||||||
android.r8.strictFullModeForKeepRules=false
|
android.nonTransitiveRClass=true
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,10 +1,8 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=bafc141b619ad6350fd975fc903156dd5c151998cc8b058e8c1044ab5f7b031f
|
distributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
retries=0
|
|
||||||
retryBackOffMs=500
|
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
2
gradlew
vendored
2
gradlew
vendored
@@ -57,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
|||||||
31
gradlew.bat
vendored
31
gradlew.bat
vendored
@@ -23,8 +23,8 @@
|
|||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables, and ensure extensions are enabled
|
@rem Set local scope for the variables with windows NT shell
|
||||||
setlocal EnableExtensions
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@@ -51,7 +51,7 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
"%COMSPEC%" /c exit 1
|
goto fail
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
@@ -65,7 +65,7 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
"%COMSPEC%" /c exit 1
|
goto fail
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
@@ -73,10 +73,21 @@ echo location of your Java installation. 1>&2
|
|||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
@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
|
|
||||||
|
|
||||||
:exitWithErrorLevel
|
:end
|
||||||
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
@rem End local scope for the variables with windows NT shell
|
||||||
"%COMSPEC%" /c exit %ERRORLEVEL%
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@turf/area": "^7.3.5",
|
"@turf/area": "^7.0.0",
|
||||||
"@turf/turf": "^7.3.5",
|
"@turf/turf": "^7.0.0",
|
||||||
"jsdom": "^29.1.1",
|
"jsdom": "^28.0.0",
|
||||||
"mapshaper": "^0.7.19"
|
"mapshaper": "^0.6.79"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,6 @@ pluginManagement {
|
|||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://jitpack.io' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plugins {
|
|
||||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
|
||||||
}
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
repositories {
|
repositories {
|
||||||
|
|||||||
Reference in New Issue
Block a user