44 Commits

Author SHA1 Message Date
76b0ad9f41 Improve stats 2024-04-11 00:03:37 +02:00
06f8a1db7a Remove equidistant projection since similar to azimuthal equatorial 2024-04-10 23:17:07 +02:00
c01420a3c6 Nogroup if unchecked country 2024-04-10 21:48:57 +02:00
445cd05800 Fix case autogroup 2024-04-10 21:23:04 +02:00
d1f7c72adb Fixed icon 2024-04-10 21:09:44 +02:00
9228556ed1 Fixes 2024-04-10 21:06:42 +02:00
cd7c54230e CleanUp, Opti, Svg, ... 2024-04-10 20:56:14 +02:00
98582732cd Fix regions not colored in regional mode 2024-04-10 16:50:18 +02:00
ca16a0d20f Use better icons for light theme 2024-04-10 13:14:09 +02:00
99c7f8394c Enable group color change in single group setting 2024-04-10 13:08:49 +02:00
98591691a3 Correct bug when disabling and re-enabling regions 2024-04-10 11:20:08 +02:00
16faddb602 Merge pull request 'Update plugin com.mikepenz.aboutlibraries.plugin to v11.1.3' (#55) from renovate/com.mikepenz.aboutlibraries.plugin-11.x into main
Reviewed-on: #55
2024-04-10 08:36:47 +02:00
4dc3794b7e Merge pull request 'Update dependency com.mikepenz:aboutlibraries to v11.1.3' (#54) from renovate/com.mikepenz-aboutlibraries-11.x into main
Reviewed-on: #54
2024-04-10 08:36:38 +02:00
129d50c61d Update plugin com.mikepenz.aboutlibraries.plugin to v11.1.3 2024-04-10 00:01:23 +00:00
b51c714bfa Update dependency com.mikepenz:aboutlibraries to v11.1.3 2024-04-10 00:01:18 +00:00
63eed7bf59 Delete color 2024-04-10 00:11:40 +02:00
261d5eed5b Logo 2024-04-10 00:08:12 +02:00
494d58034d Choose map projection in settings 2024-04-09 22:29:26 +02:00
e87f2fac28 Better SVG 2024-04-09 19:27:16 +02:00
fd0ae64c0d Compute sum and ratio in stats 2024-04-09 16:51:00 +02:00
6aef6dabb2 Repair edit fragment refresh when groups are active 2024-04-09 13:52:08 +02:00
91574f4060 Correct some region names 2024-04-09 13:47:06 +02:00
8b2b694a00 Improved Stats 2024-04-09 08:29:53 +02:00
fbeefa0276 WIP Stats 2024-04-09 01:43:41 +02:00
cd999c2a6e Fixed Duplicate items in geoloc children 2024-04-09 00:03:34 +02:00
728994a8f3 Fix racecondition when button spam 2024-04-08 23:46:58 +02:00
6123048426 Names & SVG 2024-04-08 21:24:20 +02:00
ddef61a0cf Reassign all mappings to chosen group when disabling groups 2024-04-08 17:44:49 +02:00
59a72e0544 Port regional assignments to parent country if turned off 2024-04-08 13:41:35 +02:00
a3f81c95a0 Add Antarctica SVG 2024-04-08 11:36:05 +02:00
d041df9805 Adapt settings and icons 2024-04-08 11:35:51 +02:00
01dab6aa30 Prevent overriding default group 2024-04-08 10:52:08 +02:00
bafd3cea14 Remove magic group keys 2024-04-08 10:45:16 +02:00
ec52574ae3 Update checkboxes immediately 2024-04-08 10:42:16 +02:00
923404ebc5 Fix regional UI 2024-04-08 00:42:35 +02:00
32ba5e0b07 Merge Shetland Islands with Scotland 2024-04-07 23:27:12 +02:00
72b2148e4b Change some country names 2024-04-07 22:21:08 +02:00
513660b3a4 Reorganize countries in 'Others' group 2024-04-07 22:04:33 +02:00
443d62b6df Fixed state names 2024-04-07 11:59:37 +02:00
a360c7496b Added prerelease to build 2024-04-07 11:25:19 +02:00
3fe83cff2e Fix debug build if no key 2024-04-07 11:10:27 +02:00
71acf04f20 Lock file maintenance 2024-04-06 00:04:23 +00:00
b1de332134 [m] Keystore def 2024-04-04 00:36:54 +02:00
112745188f [m] Fix name 2024-04-04 00:30:18 +02:00
64 changed files with 17915 additions and 8759 deletions

View File

@ -48,17 +48,17 @@ jobs:
cache: 'gradle' cache: 'gradle'
- name: Build APK - name: Build APK
run: ./gradlew assemble run: ./gradlew assembleSignedRelease
# - name: Upload APK
# uses: actions/upload-artifact@v4
# with:
# name: app.apk
# path: app/build/outputs/apk/release/app-release.apk
- name: Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
with: with:
files: | files: |
app/build/outputs/apk/release/app-release.apk app/build/outputs/apk/signedRelease/app-signedRelease.apk
prerelease: |
if [[ ${{ github.ref }} =~ ^refs/tags/[0-9]+\.[0-9]+[a-z]+$ ]]; then
echo "false"
else
echo "true"
fi

View File

@ -2,9 +2,10 @@ plugins {
id 'com.android.application' id 'com.android.application'
id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.23' id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.23'
id 'com.mikepenz.aboutlibraries.plugin' version '11.1.1' id 'com.mikepenz.aboutlibraries.plugin' version '11.1.3'
} }
android { android {
namespace 'net.helcel.beans' namespace 'net.helcel.beans'
compileSdk 34 compileSdk 34
@ -16,22 +17,37 @@ android {
versionCode 1 versionCode 1
versionName "0.1a" versionName "0.1a"
} }
signingConfigs { signingConfigs {
create("release") { create("release") {
try {
def keystorePropertiesFile = rootProject.file("app/keystore.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
keyAlias keystoreProperties['keyAlias'] keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword'] keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile']) storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword'] storePassword keystoreProperties['storePassword']
} catch (FileNotFoundException e) {
println("File not found: ${e.message}")
}
} }
} }
buildTypes { buildTypes {
debug {
debuggable true
}
release { release {
minifyEnabled true minifyEnabled true
shrinkResources false shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
signedRelease {
minifyEnabled true
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig = signingConfigs.getByName("release") signingConfig = signingConfigs.getByName("release")
} }
} }
@ -71,6 +87,5 @@ dependencies {
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.github.AppDevNext:AndroidChart:3.1.0.21" implementation 'com.mikepenz:aboutlibraries:11.1.3'
implementation 'com.mikepenz:aboutlibraries:11.1.1'
} }

View File

@ -3,18 +3,18 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<application <application
android:hardwareAccelerated="false"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:hardwareAccelerated="false"
android:icon="@mipmap/ic_launcher_round"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Beans" android:theme="@style/Theme.Beans"
tools:targetApi="31"
tools:replace="android:allowBackup" tools:replace="android:allowBackup"
> tools:targetApi="31">
<profileable android:shell="true" /> <profileable android:shell="true" />
<activity <activity
android:name=".activity.MainActivity" android:name=".activity.MainActivity"
android:exported="true"> android:exported="true">
@ -31,7 +31,7 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
android:name=".activity.StatActivity" android:name=".activity.StatsActivity"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 MiB

View File

@ -32,7 +32,8 @@ AFG_TK|AFG|Takhar|12361
AFG_OZ|AFG|Uruzgan|12900 AFG_OZ|AFG|Uruzgan|12900
AFG_VR|AFG|Wardak|8945 AFG_VR|AFG|Wardak|8945
AFG_ZB|AFG|Zabul|17375 AFG_ZB|AFG|Zabul|17375
XAD_NA|XAD|Dhekelia|125 XAD_Akrotiri|XAD|Akrotiri|109
XAD_Dhekelia|XAD|Dhekelia|125
ALA_AR|ALA|Archipelago|448 ALA_AR|ALA|Archipelago|448
ALA_CO|ALA|Countryside|1022 ALA_CO|ALA|Countryside|1022
ALA_MH|ALA|Mariehamn|13 ALA_MH|ALA|Mariehamn|13
@ -126,14 +127,17 @@ AGO_NA|AGO|Namibe|58240
AGO_UI|AGO|Uíge|62425 AGO_UI|AGO|Uíge|62425
AGO_ZA|AGO|Zaire|36821 AGO_ZA|AGO|Zaire|36821
AIA_BP|AIA|Blowing Point|5 AIA_BP|AIA|Blowing Point|5
AIA_NA|AIA|Sombrero Island|0 AIA_DogIsland|AIA|Dog Island|2
AIA_EE|AIA|East End|5 AIA_EE|AIA|East End|5
AIA_GH|AIA|George Hill|7 AIA_GH|AIA|George Hill|7
AIA_IH|AIA|Island Harbour|6 AIA_IH|AIA|Island Harbour|6
AIA_NH|AIA|North Hill|1 AIA_NH|AIA|North Hill|1
AIA_NS|AIA|North Side|9 AIA_NS|AIA|North Side|9
AIA_PriclyPearCays|AIA|Pricly Pear Cays|0
AIA_SG|AIA|Sandy Ground|1 AIA_SG|AIA|Sandy Ground|1
AIA_SH|AIA|Sandy Hill|7 AIA_SH|AIA|Sandy Hill|7
AIA_ScrubIsland|AIA|Scrub Island|4
AIA_SombreroIsland|AIA|Sombrero Island|0
AIA_SO|AIA|South Hill|7 AIA_SO|AIA|South Hill|7
AIA_ST|AIA|Stoney Ground|7 AIA_ST|AIA|Stoney Ground|7
AIA_TF|AIA|The Farrington|5 AIA_TF|AIA|The Farrington|5
@ -203,8 +207,16 @@ AUT_ST|AUT|Steiermark|16408
AUT_TR|AUT|Tirol|12646 AUT_TR|AUT|Tirol|12646
AUT_VO|AUT|Vorarlberg|2602 AUT_VO|AUT|Vorarlberg|2602
AUT_WI|AUT|Wien|415 AUT_WI|AUT|Wien|415
AZE_NA|AZE|Yukhari-Karabakh|7407 AZE_Absheron|AZE|Absheron|6147
AZE_Aran|AZE|Aran|21914
AZE_Daglig-Shirvan|AZE|Daglig-Shirvan|5989
AZE_Ganja-Qazakh|AZE|Ganja-Qazakh|12044
AZE_Kalbajar-Lachin|AZE|Kalbajar-Lachin|5770
AZE_LA|AZE|Lankaran|5592 AZE_LA|AZE|Lankaran|5592
AZE_Nakhchivan|AZE|Nakhchivan|5400
AZE_Quba-Khachmaz|AZE|Quba-Khachmaz|7339
AZE_Shaki-Zaqatala|AZE|Shaki-Zaqatala|8729
AZE_Yukhari-Karabakh|AZE|Yukhari-Karabakh|7407
BHS_AK|BHS|Acklins|496 BHS_AK|BHS|Acklins|496
BHS_BR|BHS|Berry Islands|61 BHS_BR|BHS|Berry Islands|61
BHS_BI|BHS|Biminis|34 BHS_BI|BHS|Biminis|34
@ -266,7 +278,9 @@ BLR_HR|BLR|Grodno|24952
BLR_MI|BLR|Minsk|2255 BLR_MI|BLR|Minsk|2255
BLR_MA|BLR|Mogilev|28984 BLR_MA|BLR|Mogilev|28984
BLR_VI|BLR|Vitebsk|40056 BLR_VI|BLR|Vitebsk|40056
BEL_NA|BEL|Wallonie|16827 BEL_Bruxelles|BEL|Bruxelles|156
BEL_Vlaanderen|BEL|Vlaanderen|13685
BEL_Wallonie|BEL|Wallonie|16827
BLZ_BZ|BLZ|Belize|3372 BLZ_BZ|BLZ|Belize|3372
BLZ_CY|BLZ|Cayo|5322 BLZ_CY|BLZ|Cayo|5322
BLZ_CZ|BLZ|Corozal|2012 BLZ_CZ|BLZ|Corozal|2012
@ -374,7 +388,11 @@ BRA_SC|BRA|Santa Catarina|96032
BRA_SP|BRA|São Paulo|249417 BRA_SP|BRA|São Paulo|249417
BRA_SE|BRA|Sergipe|22079 BRA_SE|BRA|Sergipe|22079
BRA_TO|BRA|Tocantins|279170 BRA_TO|BRA|Tocantins|279170
VGB_NA|VGB|Virgin Gorda|28 VGB_Anegada|VGB|Anegada|40
VGB_JostVanDyke|VGB|Jost Van Dyke|11
VGB_OtherIslands|VGB|Other Islands|14
VGB_Tortola|VGB|Tortola|76
VGB_VirginGorda|VGB|Virgin Gorda|28
BRN_BE|BRN|Belait|2863 BRN_BE|BRN|Belait|2863
BRN_BM|BRN|Brunei and Muara|533 BRN_BM|BRN|Brunei and Muara|533
BRN_TE|BRN|Temburong|1283 BRN_TE|BRN|Temburong|1283
@ -636,7 +654,17 @@ COL_VD|COL|Vichada|100014
COM_MO|COM|Mwali|220 COM_MO|COM|Mwali|220
COM_GC|COM|Njazídja|1028 COM_GC|COM|Njazídja|1028
COM_AN|COM|Nzwani|436 COM_AN|COM|Nzwani|436
COK_NA|COK|Rarotonga|70 COK_Aitutaki|COK|Aitutaki|28
COK_Atiu|COK|Atiu|31
COK_Mangaia|COK|Mangaia|49
COK_Manihiki|COK|Manihiki|8
COK_Mauke|COK|Mauke|20
COK_Mitiaro|COK|Mitiaro|25
COK_Palmerston|COK|Palmerston|24
COK_Penhryn|COK|Penhryn|17
COK_Pukapuka|COK|Pukapuka|6
COK_Rakahanga|COK|Rakahanga|5
COK_Rarotonga|COK|Rarotonga|70
CRI_AL|CRI|Alajuela|9834 CRI_AL|CRI|Alajuela|9834
CRI_CA|CRI|Cartago|3113 CRI_CA|CRI|Cartago|3113
CRI_GU|CRI|Guanacaste|10250 CRI_GU|CRI|Guanacaste|10250
@ -878,7 +906,7 @@ EST_JN|EST|Jõgeva|2597
EST_LN|EST|Lääne|2420 EST_LN|EST|Lääne|2420
EST_LV|EST|Lääne-Viru|3478 EST_LV|EST|Lääne-Viru|3478
EST_PR|EST|Pärnu|4796 EST_PR|EST|Pärnu|4796
EST_NA|EST|Peipsi|1758 EST_Peipsi|EST|Peipsi|1758
EST_PL|EST|Põlva|2161 EST_PL|EST|Põlva|2161
EST_RA|EST|Rapla|2971 EST_RA|EST|Rapla|2971
EST_SA|EST|Saare|2932 EST_SA|EST|Saare|2932
@ -934,7 +962,7 @@ PYF_MI|PYF|Îles Marquises|996
PYF_LI|PYF|Îles Sous-le-Vent|429 PYF_LI|PYF|Îles Sous-le-Vent|429
PYF_TG|PYF|Îles Tuamotu-Gambier|1039 PYF_TG|PYF|Îles Tuamotu-Gambier|1039
ATF_CR|ATF|Îles Crozet|372 ATF_CR|ATF|Îles Crozet|372
ATF_NA|ATF|ÎlesÉparses|44 ATF_ÎlesÉparses|ATF|Îles Éparses|44
ATF_AS|ATF|Îles Saint Paulet Amsterdam|64 ATF_AS|ATF|Îles Saint Paulet Amsterdam|64
ATF_KG|ATF|Kerguelen|7372 ATF_KG|ATF|Kerguelen|7372
GAB_ES|GAB|Estuaire|20024 GAB_ES|GAB|Estuaire|20024
@ -1071,9 +1099,14 @@ GGY_SV|GGY|Saint Saviour|6
GGY_SK|GGY|Sark|7 GGY_SK|GGY|Sark|7
GGY_TV|GGY|Torteval|3 GGY_TV|GGY|Torteval|3
GGY_VA|GGY|Vale|10 GGY_VA|GGY|Vale|10
GIN_NA|GIN|Nzérékoré|36751 GIN_Boké|GIN|Boké|34287
GIN_C|GIN|Conakry|423 GIN_C|GIN|Conakry|423
GIN_Faranah|GIN|Faranah|35989
GIN_K|GIN|Kankan|72197 GIN_K|GIN|Kankan|72197
GIN_Kindia|GIN|Kindia|25816
GIN_Labé|GIN|Labé|22959
GIN_Mamou|GIN|Mamou|17935
GIN_Nzérékoré|GIN|Nzérékoré|36751
GNB_BA|GNB|Bafatá|5881 GNB_BA|GNB|Bafatá|5881
GNB_BM|GNB|Biombo|761 GNB_BM|GNB|Biombo|761
GNB_BS|GNB|Bissau|83 GNB_BS|GNB|Bissau|83
@ -1298,7 +1331,7 @@ IMN_MC|IMN|Michael|34
IMN_MD|IMN|Santon|16 IMN_MD|IMN|Santon|16
IMN_GR|IMN|Garff|72 IMN_GR|IMN|Garff|72
IMN_GB|IMN|Peel|2 IMN_GB|IMN|Peel|2
ISR_NA|ISR|Golan|1238 ISR_Golan|ISR|Golan|1238
ISR_HD|ISR|Ha Darom|14557 ISR_HD|ISR|Ha Darom|14557
ISR_HA|ISR|Haifa|887 ISR_HA|ISR|Haifa|887
ISR_HM|ISR|Ha Merkaz|1243 ISR_HM|ISR|Ha Merkaz|1243
@ -1471,10 +1504,13 @@ KEN_UG|KEN|Uasin Gishu|3453
KEN_VI|KEN|Vihiga|562 KEN_VI|KEN|Vihiga|562
KEN_WJ|KEN|Wajir|57017 KEN_WJ|KEN|Wajir|57017
KEN_WP|KEN|West Pokot|9574 KEN_WP|KEN|West Pokot|9574
XKO_NA|XKO|Uroševac|1056 XKO_Đakovica|XKO|Đakovica|1109
XKO_Gnjilane|XKO|Gnjilane|1360
XKO_KM|XKO|Kosovska Mitrovica|2070 XKO_KM|XKO|Kosovska Mitrovica|2070
XKO_PE|XKO|Pećki|1357 XKO_PE|XKO|Pećki|1357
XKO_Pristina|XKO|Pristina|2175
XKO_PZ|XKO|Prizren|1715 XKO_PZ|XKO|Prizren|1715
XKO_Uroševac|XKO|Uroševac|1056
KWT_AH|KWT|Al Ahmadi|4659 KWT_AH|KWT|Al Ahmadi|4659
KWT_FA|KWT|Al Farwaniyah|219 KWT_FA|KWT|Al Farwaniyah|219
KWT_JA|KWT|Al Jahrah|12438 KWT_JA|KWT|Al Jahrah|12438
@ -1512,7 +1548,14 @@ LVA_L|LVA|Latgale|14678
LVA_R|LVA|Riga|10324 LVA_R|LVA|Riga|10324
LVA_V|LVA|Vidzeme|15240 LVA_V|LVA|Vidzeme|15240
LVA_Z|LVA|Zemgale|10775 LVA_Z|LVA|Zemgale|10775
LBN_NA|LBN|South|919 LBN_Akkar|LBN|Akkar|793
LBN_Baalbak-Hermel|LBN|Baalbak-Hermel|2854
LBN_Beirut|LBN|Beirut|21
LBN_Bekaa|LBN|Bekaa|1408
LBN_MountLebanon|LBN|Mount Lebanon|1990
LBN_Nabatiyeh|LBN|Nabatiyeh|1099
LBN_North|LBN|North|1181
LBN_South|LBN|South|919
LSO_BE|LSO|Berea|1999 LSO_BE|LSO|Berea|1999
LSO_BB|LSO|Butha-Buthe|1796 LSO_BB|LSO|Butha-Buthe|1796
LSO_LE|LSO|Leribe|2829 LSO_LE|LSO|Leribe|2829
@ -1624,7 +1667,7 @@ MKD_KZ|MKD|Kriva Palanka|508
MKD_KG|MKD|Krivogaštani|95 MKD_KG|MKD|Krivogaštani|95
MKD_KS|MKD|Kruševo|183 MKD_KS|MKD|Kruševo|183
MKD_UM|MKD|Kumanovo|503 MKD_UM|MKD|Kumanovo|503
MKD_NA|MKD|Staro Nagoričane|438 MKD_LakeOhrid|MKD|Lake Ohrid|247
MKD_LI|MKD|Lipkovo|265 MKD_LI|MKD|Lipkovo|265
MKD_LO|MKD|Lozovo|161 MKD_LO|MKD|Lozovo|161
MKD_MK|MKD|Makedonska Kamenica|198 MKD_MK|MKD|Makedonska Kamenica|198
@ -1647,6 +1690,7 @@ MKD_RM|MKD|Rosoman|133
MKD_AJ|MKD|Saraj|234 MKD_AJ|MKD|Saraj|234
MKD_SS|MKD|Sopište|214 MKD_SS|MKD|Sopište|214
MKD_SD|MKD|Star Dojran|150 MKD_SD|MKD|Star Dojran|150
MKD_NA|MKD|Staro Nagoričane|438
MKD_ST|MKD|Štip|565 MKD_ST|MKD|Štip|565
MKD_UG|MKD|Struga|475 MKD_UG|MKD|Struga|475
MKD_RU|MKD|Strumitsa|320 MKD_RU|MKD|Strumitsa|320
@ -1669,7 +1713,7 @@ MDG_D|MDG|Antsiranana|44120
MDG_F|MDG|Fianarantsoa|101276 MDG_F|MDG|Fianarantsoa|101276
MDG_M|MDG|Mahajanga|152526 MDG_M|MDG|Mahajanga|152526
MDG_A|MDG|Toamasina|71636 MDG_A|MDG|Toamasina|71636
MDG_NA|MDG|Toliary|164809 MDG_Toliary|MDG|Toliary|164809
MWI_BA|MWI|Balaka|2143 MWI_BA|MWI|Balaka|2143
MWI_BL|MWI|Blantyre|2038 MWI_BL|MWI|Blantyre|2038
MWI_CK|MWI|Chikwawa|4908 MWI_CK|MWI|Chikwawa|4908
@ -1728,9 +1772,29 @@ MLT_GO|MLT|Għawdex|71
MLT_SO|MLT|Nofsinhar|78 MLT_SO|MLT|Nofsinhar|78
MLT_NO|MLT|Tramuntana|116 MLT_NO|MLT|Tramuntana|116
MLT_SE|MLT|Xlokk|36 MLT_SE|MLT|Xlokk|36
MHL_NA|MHL|NA|26 MHL_Ailinglaplap|MHL|Ailinglaplap|18
MHL_Ailuk|MHL|Ailuk|11
MHL_Arno|MHL|Arno|28
MHL_Aur|MHL|Aur|6
MHL_Ebon|MHL|Ebon|8
MHL_Enewetok|MHL|Enewetok|16
MHL_Jabat|MHL|Jabat|1
MHL_Jaluit|MHL|Jaluit|13
MHL_KWA|MHL|Kwajalein|27 MHL_KWA|MHL|Kwajalein|27
MHL_Lae|MHL|Lae|3
MHL_Lib|MHL|Lib|1
MHL_Likiep|MHL|Likiep|13
MHL_MAJ|MHL|Majuro|22 MHL_MAJ|MHL|Majuro|22
MHL_Maloelap|MHL|Maloelap|12
MHL_Mejit|MHL|Mejit|4
MHL_Mili|MHL|Mili|27
MHL_Namorik|MHL|Namorik|5
MHL_Namu|MHL|Namu|7
MHL_Ujae|MHL|Ujae|3
MHL_Utirik|MHL|Utirik|14
MHL_Wotho|MHL|Wotho|6
MHL_Wotje|MHL|Wotje|15
MHL_19_1|MHL|NA|26
MTQ_FF|MTQ|Fort-de-France|189 MTQ_FF|MTQ|Fort-de-France|189
MTQ_MA|MTQ|Le Marin|393 MTQ_MA|MTQ|Le Marin|393
MTQ_TR|MTQ|Le Trinité|353 MTQ_TR|MTQ|Le Trinité|353
@ -1896,7 +1960,7 @@ MAR_FB|MAR|Fès-Boulemane|19366
MAR_GB|MAR|Gharb-Chrarda-Béni Hssen|8782 MAR_GB|MAR|Gharb-Chrarda-Béni Hssen|8782
MAR_GC|MAR|Grand Casablanca|879 MAR_GC|MAR|Grand Casablanca|879
MAR_GE|MAR|Guelmim-Es-Semara|64701 MAR_GE|MAR|Guelmim-Es-Semara|64701
MAR_LB|MAR|Laâyoune-Boujdour-Sakia El H|5763 MAR_LB|MAR|Laâyoune-Boujdour-Sakia El Hamra|5763
MAR_MK|MAR|Marrakech-Tensift-Al Haouz|32483 MAR_MK|MAR|Marrakech-Tensift-Al Haouz|32483
MAR_MT|MAR|Meknès-Tafilalet|60303 MAR_MT|MAR|Meknès-Tafilalet|60303
MAR_OR|MAR|Oriental|59914 MAR_OR|MAR|Oriental|59914
@ -1968,13 +2032,15 @@ NLD_FL|NLD|Flevoland|1466
NLD_FR|NLD|Fryslân|3573 NLD_FR|NLD|Fryslân|3573
NLD_GE|NLD|Gelderland|5102 NLD_GE|NLD|Gelderland|5102
NLD_GR|NLD|Groningen|2370 NLD_GR|NLD|Groningen|2370
NLD_SH|NLD|Zuid-Holland|3143 NLD_IJsselmeer|NLD|IJsselmeer|1995
NLD_LI|NLD|Limburg|2159 NLD_LI|NLD|Limburg|2159
NLD_NB|NLD|Noord-Brabant|5082 NLD_NB|NLD|Noord-Brabant|5082
NLD_NH|NLD|Noord-Holland|2872 NLD_NH|NLD|Noord-Holland|2872
NLD_OV|NLD|Overijssel|3369 NLD_OV|NLD|Overijssel|3369
NLD_UT|NLD|Utrecht|1555 NLD_UT|NLD|Utrecht|1555
NLD_ZE|NLD|Zeeland|1804 NLD_ZE|NLD|Zeeland|1804
NLD_Zeeuwsemeren|NLD|Zeeuwsemeren|477
NLD_14_1|NLD|NA|3143
NCL_IL|NCL|Îles Loyauté|1988 NCL_IL|NCL|Îles Loyauté|1988
NCL_NO|NCL|Nord|9520 NCL_NO|NCL|Nord|9520
NCL_SU|NCL|Sud|7408 NCL_SU|NCL|Sud|7408
@ -2067,13 +2133,18 @@ PRK_WB|PRK|Hwanghae-bukto|8248
PRK_WN|PRK|Hwanghae-namdo|8563 PRK_WN|PRK|Hwanghae-namdo|8563
PRK_KS|PRK|Kaesŏng|1182 PRK_KS|PRK|Kaesŏng|1182
PRK_KW|PRK|Kangwŏn-do|10286 PRK_KW|PRK|Kangwŏn-do|10286
PRK_NA|PRK|Sinŭiju|109 PRK_Kumgangsan|PRK|Kumgangsan|987
PRK_PB|PRK|P'yŏngan-bukto|12424 PRK_PB|PRK|P'yŏngan-bukto|12424
PRK_PN|PRK|P'yŏngan-namdo|12479 PRK_PN|PRK|P'yŏngan-namdo|12479
PRK_PY|PRK|P'yŏngyang|2718 PRK_PY|PRK|P'yŏngyang|2718
PRK_NJ|PRK|Rasŏn|856 PRK_NJ|PRK|Rasŏn|856
PRK_YG|PRK|Ryanggang|13935 PRK_YG|PRK|Ryanggang|13935
ZNC_NA|ZNC|Nicosia|522 PRK_Sinŭiju|PRK|Sinŭiju|109
ZNC_Gazimağusa|ZNC|Gazimağusa|927
ZNC_Girne|ZNC|Girne|677
ZNC_Güzelyurt|ZNC|Güzelyurt|346
ZNC_Iskele|ZNC|Iskele|849
ZNC_Nicosia|ZNC|Nicosia|522
MNP_NI|MNP|Northern Islands|181 MNP_NI|MNP|Northern Islands|181
MNP_RO|MNP|Rota|90 MNP_RO|MNP|Rota|90
MNP_SA|MNP|Saipan|123 MNP_SA|MNP|Saipan|123
@ -2318,7 +2389,7 @@ PRT_FA|PRT|Faro|4975
PRT_GU|PRT|Guarda|5541 PRT_GU|PRT|Guarda|5541
PRT_LE|PRT|Leiria|3501 PRT_LE|PRT|Leiria|3501
PRT_LI|PRT|Lisboa|2765 PRT_LI|PRT|Lisboa|2765
PRT_NA|PRT|Madeira|801 PRT_Madeira|PRT|Madeira|801
PRT_PA|PRT|Portalegre|6091 PRT_PA|PRT|Portalegre|6091
PRT_PO|PRT|Porto|2332 PRT_PO|PRT|Porto|2332
PRT_SA|PRT|Santarém|6725 PRT_SA|PRT|Santarém|6725
@ -2511,7 +2582,7 @@ RUS_LP|RUS|Lipetsk|24425
RUS_MG|RUS|Magadan|459480 RUS_MG|RUS|Magadan|459480
RUS_ME|RUS|Mariy-El|23468 RUS_ME|RUS|Mariy-El|23468
RUS_MR|RUS|Mordovia|26161 RUS_MR|RUS|Mordovia|26161
RUS_NA|RUS|Moscow City|1095 RUS_MoscowCity|RUS|Moscow City|1095
RUS_MS|RUS|Moskva|46592 RUS_MS|RUS|Moskva|46592
RUS_MM|RUS|Murmansk|142851 RUS_MM|RUS|Murmansk|142851
RUS_NN|RUS|Nenets|175502 RUS_NN|RUS|Nenets|175502
@ -2557,7 +2628,8 @@ RWA_SU|RWA|Amajyepfo|5997
RWA_ES|RWA|Iburasirazuba|9530 RWA_ES|RWA|Iburasirazuba|9530
RWA_OU|RWA|Iburengerazuba|5910 RWA_OU|RWA|Iburengerazuba|5910
RWA_KV|RWA|Umujyiwa Kigali|733 RWA_KV|RWA|Umujyiwa Kigali|733
BLM_NA|BLM|Sousle Vent|8 BLM_AuVent|BLM|Au Vent|13
BLM_SousleVent|BLM|Sous le Vent|8
SHN_AC|SHN|Ascension|100 SHN_AC|SHN|Ascension|100
SHN_SH|SHN|Saint Helena|124 SHN_SH|SHN|Saint Helena|124
SHN_TA|SHN|Tristanda Cunha|189 SHN_TA|SHN|Tristanda Cunha|189
@ -2697,7 +2769,11 @@ SLE_EA|SLE|Eastern|15846
SLE_NO|SLE|Northern|36238 SLE_NO|SLE|Northern|36238
SLE_SO|SLE|Southern|20261 SLE_SO|SLE|Southern|20261
SLE_WE|SLE|Western|722 SLE_WE|SLE|Western|722
SGP_NA|SGP|West|230 SGP_Central|SGP|Central|133
SGP_East|SGP|East|103
SGP_North|SGP|North|131
SGP_North-East|SGP|North-East|103
SGP_West|SGP|West|230
SVK_BC|SVK|Banskobystrický|9565 SVK_BC|SVK|Banskobystrický|9565
SVK_BL|SVK|Bratislavský|2015 SVK_BL|SVK|Bratislavský|2015
SVK_KI|SVK|Košický|6768 SVK_KI|SVK|Košický|6768
@ -2708,7 +2784,7 @@ SVK_TA|SVK|Trnavský|4125
SVK_ZI|SVK|Žilinský|6828 SVK_ZI|SVK|Žilinský|6828
SVN_GO|SVN|Gorenjska|2117 SVN_GO|SVN|Gorenjska|2117
SVN_SP|SVN|Goriška|2277 SVN_SP|SVN|Goriška|2277
SVN_NA|SVN|Jugovzhodna Slovenija|2635 SVN_JugovzhodnaSlovenija|SVN|Jugovzhodna Slovenija|2635
SVN_KO|SVN|Koroška|1032 SVN_KO|SVN|Koroška|1032
SVN_NO|SVN|Notranjsko-kraška|1452 SVN_NO|SVN|Notranjsko-kraška|1452
SVN_JP|SVN|Obalno-kraška|945 SVN_JP|SVN|Obalno-kraška|945
@ -3191,7 +3267,12 @@ TKM_BA|TKM|Balkan|136605
TKM_DA|TKM|Daşoguz|76751 TKM_DA|TKM|Daşoguz|76751
TKM_LE|TKM|Lebap|96478 TKM_LE|TKM|Lebap|96478
TKM_MA|TKM|Mary|86353 TKM_MA|TKM|Mary|86353
TCA_NA|TCA|South Caicosand East Caicos|247 TCA_GrandTurk|TCA|Grand Turk|20
TCA_MiddleCaicos|TCA|Middle Caicos|306
TCA_NorthCaicos|TCA|North Caicos|259
TCA_ProvidencialesandWestCaicos|TCA|Providenciales and West Caicos|152
TCA_SaltCay|TCA|Salt Cay|11
TCA_SouthCaicosandEastCaicos|TCA|South Caicos and East Caicos|247
TUV_FN|TUV|Funafuti|7 TUV_FN|TUV|Funafuti|7
TUV_NG|TUV|Nanumanga|3 TUV_NG|TUV|Nanumanga|3
TUV_NA|TUV|Nanumea|4 TUV_NA|TUV|Nanumea|4
@ -3231,7 +3312,8 @@ UGA_TG|UGA|Kitgum|9621
UGA_KF|UGA|Kotido|13366 UGA_KF|UGA|Kotido|13366
UGA_KU|UGA|Kumi|2867 UGA_KU|UGA|Kumi|2867
UGA_KJ|UGA|Kyenjojo|4125 UGA_KJ|UGA|Kyenjojo|4125
UGA_NA|UGA|Nakasongola|3536 UGA_LakeAlbert|UGA|Lake Albert|3212
UGA_LakeVictoria|UGA|Lake Victoria|28585
UGA_LA|UGA|Lira|7285 UGA_LA|UGA|Lira|7285
UGA_LW|UGA|Luwero|5734 UGA_LW|UGA|Luwero|5734
UGA_MA|UGA|Masaka|3643 UGA_MA|UGA|Masaka|3643
@ -3245,6 +3327,7 @@ UGA_MI|UGA|Mpigi|3321
UGA_MD|UGA|Mubende|6242 UGA_MD|UGA|Mubende|6242
UGA_MN|UGA|Mukono|3434 UGA_MN|UGA|Mukono|3434
UGA_NP|UGA|Nakapiripirit|5859 UGA_NP|UGA|Nakapiripirit|5859
UGA_NA|UGA|Nakasongola|3536
UGA_NE|UGA|Nebbi|2910 UGA_NE|UGA|Nebbi|2910
UGA_NT|UGA|Ntungamo|2068 UGA_NT|UGA|Ntungamo|2068
UGA_PD|UGA|Pader|6905 UGA_PD|UGA|Pader|6905
@ -3295,7 +3378,7 @@ ARE_UQ|ARE|Ummal-Qaywayn|746
GBR_NIR|GBR|Northern Ireland|14134 GBR_NIR|GBR|Northern Ireland|14134
GBR_SCT|GBR|Scotland|78704 GBR_SCT|GBR|Scotland|78704
GBR_WLS|GBR|Wales|20818 GBR_WLS|GBR|Wales|20818
GBR_NA|GBR|NA|130659 GBR_1_1|GBR|England|130659
USA_AL|USA|Alabama|133995 USA_AL|USA|Alabama|133995
USA_AK|USA|Alaska|1501231 USA_AK|USA|Alaska|1501231
USA_AZ|USA|Arizona|296082 USA_AZ|USA|Arizona|296082
@ -3347,7 +3430,15 @@ USA_WA|USA|Washington|174789
USA_WV|USA|West Virginia|62782 USA_WV|USA|West Virginia|62782
USA_WI|USA|Wisconsin|169315 USA_WI|USA|Wisconsin|169315
USA_WY|USA|Wyoming|253420 USA_WY|USA|Wyoming|253420
UMI_NA|UMI|Wake|9 UMI_Baker|UMI|Baker|2
UMI_Howland|UMI|Howland|2
UMI_Jarvisisland|UMI|Jarvis island|5
UMI_Johnston|UMI|Johnston|5
UMI_KingmanReef|UMI|Kingman Reef|3
UMI_Midway|UMI|Midway|12
UMI_Navassa|UMI|Navassa|5
UMI_Palmyra|UMI|Palmyra|4
UMI_Wake|UMI|Wake|9
URY_AR|URY|Artigas|12058 URY_AR|URY|Artigas|12058
URY_CA|URY|Canelones|4536 URY_CA|URY|Canelones|4536
URY_CL|URY|Cerro Largo|13843 URY_CL|URY|Cerro Largo|13843
@ -3388,22 +3479,28 @@ VUT_SE|VUT|Shefa|1522
VUT_TF|VUT|Tafea|1666 VUT_TF|VUT|Tafea|1666
VUT_TR|VUT|Torba|889 VUT_TR|VUT|Torba|889
VEN_Z|VEN|Amazonas|184052 VEN_Z|VEN|Amazonas|184052
VEN_NA|VEN|Vargas|1002 VEN_Anzoátegui|VEN|Anzoátegui|48025
VEN_C|VEN|Apure|74003 VEN_C|VEN|Apure|74003
VEN_D|VEN|Aragua|6977 VEN_D|VEN|Aragua|6977
VEN_E|VEN|Barinas|36436 VEN_E|VEN|Barinas|36436
VEN_Bolívar|VEN|Bolívar|241518
VEN_G|VEN|Carabobo|4812 VEN_G|VEN|Carabobo|4812
VEN_H|VEN|Cojedes|14572 VEN_H|VEN|Cojedes|14572
VEN_Y|VEN|Delta Amacuro|40278 VEN_Y|VEN|Delta Amacuro|40278
VEN_DP|VEN|Dependencias Federales|343 VEN_DP|VEN|Dependencias Federales|343
VEN_A|VEN|Distrito Capital|329 VEN_A|VEN|Distrito Capital|329
VEN_Falcón|VEN|Falcón|27275
VEN_Guárico|VEN|Guárico|67685
VEN_K|VEN|Lara|19166 VEN_K|VEN|Lara|19166
VEN_Mérida|VEN|Mérida|12914
VEN_M|VEN|Miranda|8623 VEN_M|VEN|Miranda|8623
VEN_N|VEN|Monagas|29251 VEN_N|VEN|Monagas|29251
VEN_O|VEN|Nueva Esparta|1039 VEN_O|VEN|Nueva Esparta|1039
VEN_P|VEN|Portuguesa|19622 VEN_P|VEN|Portuguesa|19622
VEN_R|VEN|Sucre|10950 VEN_R|VEN|Sucre|10950
VEN_Táchira|VEN|Táchira|10851
VEN_T|VEN|Trujillo|8129 VEN_T|VEN|Trujillo|8129
VEN_Vargas|VEN|Vargas|1002
VEN_U|VEN|Yaracuy|6259 VEN_U|VEN|Yaracuy|6259
VEN_V|VEN|Zulia|44191 VEN_V|VEN|Zulia|44191
VNM_AG|VNM|An Giang|3547 VNM_AG|VNM|An Giang|3547
@ -3532,4 +3629,3 @@ Z05_UT|IND|Uttarakhand|259
Z09_UT|IND|Uttarakhand|987 Z09_UT|IND|Uttarakhand|987
Z06_JK|PAK|Azad Kashmir|13931 Z06_JK|PAK|Azad Kashmir|13931
Z06_NA|PAK|Gilgit-Baltistan|68053 Z06_NA|PAK|Gilgit-Baltistan|68053
GBR_EN|GBR|England|417

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.5 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 MiB

View File

@ -1,15 +1,22 @@
package net.helcel.beans.activity package net.helcel.beans.activity
import android.os.Bundle import android.os.Bundle
import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import net.helcel.beans.R import net.helcel.beans.R
import net.helcel.beans.activity.adapter.ViewPagerAdapter import net.helcel.beans.activity.adapter.ViewPagerAdapter
import net.helcel.beans.activity.fragment.EditGroupAddFragment
import net.helcel.beans.activity.fragment.EditPlaceColorFragment
import net.helcel.beans.activity.fragment.EditPlaceFragment import net.helcel.beans.activity.fragment.EditPlaceFragment
import net.helcel.beans.countries.World import net.helcel.beans.countries.World
import net.helcel.beans.databinding.ActivityEditBinding import net.helcel.beans.databinding.ActivityEditBinding
import net.helcel.beans.helper.Data
import net.helcel.beans.helper.DialogCloser
import net.helcel.beans.helper.Settings
import net.helcel.beans.helper.Theme.createActionBar import net.helcel.beans.helper.Theme.createActionBar
@ -39,8 +46,24 @@ class EditActivity : AppCompatActivity() {
} }
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean {
if (Settings.isSingleGroup(this)) {
menuInflater.inflate(R.menu.menu_edit, menu)
}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
finish() when (item.itemId) {
R.id.action_color -> {
Data.groups.getUniqueEntry()?.let { group ->
EditGroupAddFragment(group.key, {
(_binding.pager.adapter as ViewPagerAdapter?)?.refreshColors(group.color)
}, {}, false).show(supportFragmentManager, "AddColorDialogFragment")
}
}
else -> finish()
}
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }

View File

@ -24,6 +24,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var css: CSSWrapper private lateinit var css: CSSWrapper
override fun onRestart() { override fun onRestart() {
refreshProjection()
refreshMap() refreshMap()
super.onRestart() super.onRestart()
} }
@ -36,7 +37,7 @@ class MainActivity : AppCompatActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
val d = when (item.itemId) { val d = when (item.itemId) {
R.id.action_edit -> EditActivity::class.java R.id.action_edit -> EditActivity::class.java
R.id.action_stats -> StatActivity::class.java R.id.action_stats -> StatsActivity::class.java
R.id.action_settings -> SettingsActivity::class.java R.id.action_settings -> SettingsActivity::class.java
else -> throw Exception("Non Existent Menu Item") else -> throw Exception("Non Existent Menu Item")
} }
@ -50,7 +51,6 @@ class MainActivity : AppCompatActivity() {
Settings.start(this) Settings.start(this)
supportActionBar?.setBackgroundDrawable(colorWrapper(this, android.R.attr.colorPrimary)) supportActionBar?.setBackgroundDrawable(colorWrapper(this, android.R.attr.colorPrimary))
setContentView(_binding.root) setContentView(_binding.root)
_binding.photoView.minimumScale = 1f _binding.photoView.minimumScale = 1f
@ -58,9 +58,8 @@ class MainActivity : AppCompatActivity() {
GeoLocImporter.importStates(this) GeoLocImporter.importStates(this)
Data.loadData(this, Int.MIN_VALUE) Data.loadData(this, Int.MIN_VALUE)
psvg = SVGWrapper(this)
css = CSSWrapper(this)
refreshProjection()
refreshMap() refreshMap()
} }
@ -70,4 +69,9 @@ class MainActivity : AppCompatActivity() {
_binding.photoView.setImageDrawable(PictureDrawable(psvg.get()?.renderToPicture(opt))) _binding.photoView.setImageDrawable(PictureDrawable(psvg.get()?.renderToPicture(opt)))
} }
fun refreshProjection() {
psvg = SVGWrapper(this)
css = CSSWrapper(this)
}
} }

View File

@ -1,104 +0,0 @@
package net.helcel.beans.activity
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.data.PieData
import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry
import com.github.mikephil.charting.formatter.PercentFormatter
import com.github.mikephil.charting.utils.MPPointF
import net.helcel.beans.R
import net.helcel.beans.countries.World
import net.helcel.beans.helper.Data.groups
import net.helcel.beans.helper.Data.visits
import net.helcel.beans.helper.Theme.colorWrapper
import net.helcel.beans.helper.Theme.createActionBar
class StatActivity : AppCompatActivity() {
private lateinit var chart: PieChart
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_stat)
createActionBar(this, getString(R.string.action_stat))
chart = findViewById(R.id.chart)
chart.setUsePercentValues(true)
chart.description.isEnabled = false
chart.setExtraOffsets(5F, 10F, 5F, 5F)
chart.centerText = "Country Area"
chart.setDrawCenterText(true)
chart.isDrawHoleEnabled = true
chart.setTransparentCircleColor(Color.TRANSPARENT)
chart.setHoleColor(Color.TRANSPARENT)
chart.setCenterTextColor(colorWrapper(this, android.R.attr.colorForeground).color)
chart.setTransparentCircleAlpha(0)
chart.holeRadius = 40F
chart.transparentCircleRadius = 40F
chart.rotationAngle = 0F
chart.isRotationEnabled = false
chart.isHighlightPerTapEnabled = false
chart.legend.isEnabled = false
bind()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
finish()
return super.onOptionsItemSelected(item)
}
private fun bind() {
val entries = ArrayList<PieEntry>()
val VIS_continents = World.WWW.children.groupBy { visits.getVisited(it) }
.map { Pair(it.key, it.value.map { c -> c.area }.fold(0) { acc, i -> acc + i }) }
val VIS_country =
World.WWW.children.map { it.children }.flatten().groupBy { visits.getVisited(it) }
.map { Pair(it.key, it.value.map { c -> c.area }.fold(0) { acc, i -> acc + i }) }
val vis = VIS_country
Log.d("VIS", vis.toString())
val max = vis.map { it.second }.fold(0) { acc, i -> acc + i }
vis.forEach {
entries.add(
PieEntry(
it.second.toFloat().div(max.toFloat()),
groups.getGroupFromKey(it.first).name
)
)
}
val dataSet = PieDataSet(entries, "GG1")
dataSet.valueTextColor = Color.BLACK
dataSet.sliceSpace = 3f
dataSet.iconsOffset = MPPointF(0f, 40f)
dataSet.selectionShift = 5f
dataSet.setDrawIcons(true)
dataSet.colors = vis.map { groups.getGroupFromKey(it.first).color.color }.toList()
val data = PieData(dataSet)
data.setDrawValues(false)
data.setValueFormatter(PercentFormatter())
data.setValueTextSize(11f)
data.setValueTextColor(Color.BLACK)
chart.setEntryLabelColor(Color.BLACK)
chart.data = data
chart.highlightValues(null)
chart.invalidate()
}
}

View File

@ -0,0 +1,57 @@
package net.helcel.beans.activity
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator
import net.helcel.beans.R
import net.helcel.beans.activity.adapter.StatsListAdapter
import net.helcel.beans.countries.GeoLoc.LocType
import net.helcel.beans.databinding.ActivityStatBinding
import net.helcel.beans.helper.Settings
import net.helcel.beans.helper.Theme.createActionBar
private val MODE_LIST = listOf(LocType.WORLD, LocType.COUNTRY, LocType.STATE)
class StatsActivity : AppCompatActivity() {
private lateinit var _binding: ActivityStatBinding
private var activeMode = LocType.WORLD
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityStatBinding.inflate(layoutInflater)
setContentView(_binding.root)
createActionBar(this, getString(R.string.action_stat))
_binding.stats.layoutManager =
LinearLayoutManager(this, RecyclerView.VERTICAL, false)
val adapter = StatsListAdapter(_binding.stats, _binding.name)
_binding.groupColor.setOnClickListener { adapter.invertCountMode() }
_binding.stats.adapter = adapter
_binding.pager.adapter = object : FragmentStateAdapter(supportFragmentManager, lifecycle) {
override fun getItemCount(): Int = if (Settings.isRegional(applicationContext)) 3 else 2
override fun createFragment(position: Int): Fragment = Fragment()
}
TabLayoutMediator(_binding.tab, _binding.pager) { tab, position ->
tab.text = MODE_LIST[position].txt
}.attach()
_binding.pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
activeMode = MODE_LIST[position]
adapter.refreshMode(activeMode)
}
})
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
finish()
return super.onOptionsItemSelected(item)
}
}

View File

@ -3,39 +3,44 @@ package net.helcel.beans.activity.adapter
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.checkbox.MaterialCheckBox import com.google.android.material.checkbox.MaterialCheckBox
import net.helcel.beans.R
import net.helcel.beans.activity.fragment.EditPlaceColorFragment import net.helcel.beans.activity.fragment.EditPlaceColorFragment
import net.helcel.beans.activity.fragment.EditPlaceFragment import net.helcel.beans.activity.fragment.EditPlaceFragment
import net.helcel.beans.countries.GeoLoc import net.helcel.beans.countries.GeoLoc
import net.helcel.beans.databinding.ItemListGeolocBinding import net.helcel.beans.databinding.ItemListGeolocBinding
import net.helcel.beans.helper.Data import net.helcel.beans.helper.*
import net.helcel.beans.helper.Settings
import net.helcel.beans.helper.Theme.colorWrapper import net.helcel.beans.helper.Theme.colorWrapper
class GeolocListAdapter( class GeolocListAdapter(
private val ctx: EditPlaceFragment, private val l: GeoLoc, private val pager: ViewPagerAdapter private val ctx: EditPlaceFragment, private val l: GeoLoc, private val pager: ViewPagerAdapter,
private val parentHolder: FoldingListViewHolder?
) : RecyclerView.Adapter<GeolocListAdapter.FoldingListViewHolder>() { ) : RecyclerView.Adapter<GeolocListAdapter.FoldingListViewHolder>() {
private val sortedList = l.children.toList().sortedBy { it.fullName }
private val holders: MutableSet<FoldingListViewHolder> = mutableSetOf()
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoldingListViewHolder { override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): FoldingListViewHolder {
val binding = ItemListGeolocBinding.inflate( val binding = ItemListGeolocBinding.inflate(
LayoutInflater.from(viewGroup.context), LayoutInflater.from(viewGroup.context),
viewGroup, viewGroup,
false false
) )
return FoldingListViewHolder(ctx.requireActivity(), binding) val holder = FoldingListViewHolder(ctx.requireActivity(), binding, parentHolder, l)
holders.add(holder)
return holder
} }
override fun onBindViewHolder(holder: FoldingListViewHolder, position: Int) { override fun onBindViewHolder(holder: FoldingListViewHolder, position: Int) {
val el = l.children[position] val el = sortedList[position]
holder.bind(el) holder.bind(el)
holder.addListeners(el) { holder.addListeners(el) {
if (el.children.isNotEmpty()) if (el.children.isNotEmpty())
pager.addFragment(ctx, EditPlaceFragment(el, pager)) pager.addFragment(ctx, EditPlaceFragment(el, pager, holder))
true true
} }
} }
@ -44,23 +49,20 @@ class GeolocListAdapter(
return l.children.size return l.children.size
} }
fun refreshColors(colorDrawable: ColorDrawable) {
holders.forEach { it.refreshColor(colorDrawable) }
}
class FoldingListViewHolder( class FoldingListViewHolder(
private val ctx: FragmentActivity, private val ctx: FragmentActivity,
private val _binding: ItemListGeolocBinding private val _binding: ItemListGeolocBinding,
) : RecyclerView.ViewHolder(_binding.root) { private val _parentHolder: FoldingListViewHolder? = null,
private val _parentGeoLoc: GeoLoc,
) : RecyclerView.ViewHolder(_binding.root), DialogCloser {
private lateinit var el: GeoLoc
private fun bindGroup(el: GeoLoc) { private fun bindGroup(el: GeoLoc) {
val numerator = el.children.map { Data.visits.getVisited(it) != 0 }.count { it } refreshCount(el)
val denominator = el.children.size
_binding.count.text = when (Settings.getStatPref(ctx)) {
ctx.getString(R.string.percentages) -> ctx.getString(
R.string.percentage,
(100 * (numerator.toFloat() / denominator.toFloat())).toInt()
)
else -> ctx.getString(R.string.rate, numerator, denominator)
}
_binding.textView.setTypeface(null, Typeface.BOLD) _binding.textView.setTypeface(null, Typeface.BOLD)
_binding.textView.backgroundTintList = ColorStateList.valueOf( _binding.textView.backgroundTintList = ColorStateList.valueOf(
colorWrapper( colorWrapper(
@ -71,18 +73,27 @@ class GeolocListAdapter(
} }
fun bind(el: GeoLoc) { fun bind(el: GeoLoc) {
this.el = el
_binding.textView.text = el.fullName _binding.textView.text = el.fullName
_binding.textView.backgroundTintList = _binding.textView.backgroundTintList =
ColorStateList.valueOf(colorWrapper(ctx, android.R.attr.colorBackground).color) ColorStateList.valueOf(colorWrapper(ctx, android.R.attr.colorBackground).color)
if (el.shouldShowChildren(ctx)) if (el.children.isNotEmpty())
bindGroup(el) bindGroup(el)
refreshCheck(el) refreshCheck(el)
} }
fun refreshColor(colorDrawable: ColorDrawable) {
if (Data.visits.getVisited(el) !in listOf(NO_GROUP, AUTO_GROUP)) {
_binding.checkBox.buttonTintList =
ColorStateList.valueOf(colorDrawable.color)
refreshCheck(el)
}
}
fun addListeners(el: GeoLoc, expandLambda: () -> Boolean) { fun addListeners(el: GeoLoc, expandLambda: () -> Boolean) {
if (el.shouldShowChildren(ctx)) { if (el.children.isNotEmpty()) {
_binding.textView.setOnClickListener { expandLambda() } _binding.textView.setOnClickListener { expandLambda() }
} }
_binding.checkBox.setOnClickListener { _binding.checkBox.setOnClickListener {
@ -91,11 +102,11 @@ class GeolocListAdapter(
if (_binding.checkBox.isChecked) { if (_binding.checkBox.isChecked) {
// If one has just checked the box (assign unique group) // If one has just checked the box (assign unique group)
Data.selected_group = Data.groups.getUniqueEntry() Data.selected_group = Data.groups.getUniqueEntry()
onColorDialogDismiss(false) onDialogDismiss(false)
} else { } else {
// If one has just unchecked the box (unassign unique group) // If one has just unchecked the box (unassign unique group)
Data.selected_group = null Data.selected_group = null
onColorDialogDismiss(true) onDialogDismiss(true)
} }
} else { } else {
Data.selected_group = null Data.selected_group = null
@ -104,39 +115,79 @@ class GeolocListAdapter(
"AddColorDialogFragment" "AddColorDialogFragment"
) )
} }
_parentHolder?.refresh(_parentGeoLoc)
} }
} }
fun onColorDialogDismiss(clear: Boolean) { override fun onDialogDismiss(clear: Boolean) {
if (clear) { if (clear) {
Data.visits.setVisited(Data.selected_geoloc, 0) Data.visits.setVisited(Data.selected_geoloc, NO_GROUP)
Data.saveData() Data.saveData()
if (_parentGeoLoc.children.all { Data.visits.getVisited(it) == NO_GROUP }) {
Data.clearing_geoloc = _parentGeoLoc
}
} }
if (Data.selected_group != null && Data.selected_geoloc != null) { if (Data.selected_group != null && Data.selected_geoloc != null) {
Data.visits.setVisited(Data.selected_geoloc, Data.selected_group?.key ?: 0) Data.visits.setVisited(Data.selected_geoloc, Data.selected_group?.key ?: NO_GROUP)
Data.saveData() Data.saveData()
} }
Data.selected_geoloc?.let { refreshCheck(it) } Data.selected_geoloc?.let { refreshCheck(it) }
Data.selected_geoloc = null Data.selected_geoloc = null
Data.selected_group = null Data.selected_group = null
_parentHolder?.refresh(_parentGeoLoc)
} }
private fun refreshCheck(geoLoc: GeoLoc) { private fun refreshCheck(geoLoc: GeoLoc) {
_binding.checkBox.checkedState =
if (Data.visits.getVisited(geoLoc) !in listOf(NO_GROUP, AUTO_GROUP)) {
MaterialCheckBox.STATE_CHECKED
} else if (geoLoc.children.isNotEmpty() &&
geoLoc.children.all {
Data.visits.getVisited(it) !in listOf(NO_GROUP, AUTO_GROUP)
}
) {
Data.visits.setVisited(geoLoc, AUTO_GROUP)
MaterialCheckBox.STATE_CHECKED
} else if (geoLoc.children.isEmpty() && Data.visits.getVisited(geoLoc) == AUTO_GROUP) {
MaterialCheckBox.STATE_CHECKED
} else if (geoLoc.children.any { Data.visits.getVisited(it) != NO_GROUP }) {
Data.visits.setVisited(geoLoc, AUTO_GROUP)
MaterialCheckBox.STATE_INDETERMINATE
} else {
Data.visits.setVisited(geoLoc, NO_GROUP)
if (Data.clearing_geoloc == geoLoc) {
Data.clearing_geoloc = null
}
MaterialCheckBox.STATE_UNCHECKED
}
Data.saveData()
var col = Data.groups.getGroupFromKey(Data.visits.getVisited(geoLoc)).color var col = Data.groups.getGroupFromKey(Data.visits.getVisited(geoLoc)).color
if (col.color == Color.TRANSPARENT) { if (Data.visits.getVisited(geoLoc) == AUTO_GROUP) {
col = colorWrapper( col = colorWrapper(ctx, android.R.attr.colorPrimary)
ctx, } else if (col.color == Color.TRANSPARENT) {
android.R.attr.panelColorBackground col = colorWrapper(ctx, android.R.attr.panelColorBackground)
)
col.alpha = 64 col.alpha = 64
} }
_binding.checkBox.checkedState =
if (Data.visits.getVisited(geoLoc) != 0) MaterialCheckBox.STATE_CHECKED
else if (geoLoc.children.any { Data.visits.getVisited(it) != 0 }) MaterialCheckBox.STATE_INDETERMINATE
else MaterialCheckBox.STATE_UNCHECKED
_binding.checkBox.buttonTintList = ColorStateList.valueOf(col.color) _binding.checkBox.buttonTintList = ColorStateList.valueOf(col.color)
} }
private fun refreshCount(geoLoc: GeoLoc) {
val numerator =
geoLoc.children.map { Data.visits.getVisited(it) != NO_GROUP }.count { it }
val denominator = geoLoc.children.size
_binding.count.text = Settings.getStats(ctx, numerator, denominator)
}
private fun refresh(geoLoc: GeoLoc) {
// Refresh
refreshCheck(geoLoc)
refreshCount(geoLoc)
// Recursively refresh parent
_parentHolder?.refresh(_parentGeoLoc)
}
} }
} }

View File

@ -13,7 +13,8 @@ import net.helcel.beans.helper.Theme.getContrastColor
class GroupListAdapter( class GroupListAdapter(
private val activity: FragmentActivity, private val activity: FragmentActivity,
private val selectDialog: DialogFragment private val selectDialog: DialogFragment,
private val delete: Boolean = false
) : RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>() { ) : RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroupViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GroupViewHolder {
@ -63,6 +64,7 @@ class GroupListAdapter(
Data.selected_group = entry.second Data.selected_group = entry.second
selectDialog.dismiss() selectDialog.dismiss()
} }
if (!delete) {
_binding.groupColor.setOnLongClickListener { _binding.groupColor.setOnLongClickListener {
dialogFragment.show( dialogFragment.show(
activity.supportFragmentManager, activity.supportFragmentManager,
@ -73,3 +75,4 @@ class GroupListAdapter(
} }
} }
} }
}

View File

@ -0,0 +1,152 @@
package net.helcel.beans.activity.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textview.MaterialTextView
import net.helcel.beans.R
import net.helcel.beans.countries.GeoLoc
import net.helcel.beans.countries.GeoLoc.LocType
import net.helcel.beans.countries.World
import net.helcel.beans.databinding.ItemListGroupBinding
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
import net.helcel.beans.helper.Theme.getContrastColor
class StatsListAdapter(private val stats: RecyclerView, private val total: MaterialTextView) :
RecyclerView.Adapter<StatsListAdapter.StatsViewHolder>() {
private val unit = "km²"
private var locMode = LocType.WORLD
private lateinit var ctx: Context
private var countMode: Boolean = true
private var initialSum: Int = 0
private val wwwTotal: List<GeoLoc> = World.WWW.children.toList()
private val countryTotal: List<GeoLoc> = World.WWW.children.flatMap { it.children }
private val stateTotal: List<GeoLoc> =
World.WWW.children.flatMap { it.children.flatMap { itt -> itt.children } }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatsViewHolder {
ctx = parent.context
val binding =
ItemListGroupBinding.inflate(LayoutInflater.from(ctx), parent, false)
return StatsViewHolder(binding)
}
override fun onBindViewHolder(holder: StatsViewHolder, pos: Int) {
initialSum += if (pos == itemCount - 1) {
holder.bind(
Pair(
AUTO_GROUP,
Groups.Group(AUTO_GROUP, ctx.getString(R.string.uncategorized))
)
)
} else {
holder.bind(Data.groups.getGroupFromPos(pos))
}
val unitNow = if (!countMode) unit else ""
total.text = Settings.getStats(ctx, initialSum, getTotal(), unitNow)
}
override fun getItemCount(): Int {
return Data.groups.size() + 1
}
private fun getTotal(): Int {
return if (countMode) {
when (locMode) {
LocType.WORLD -> wwwTotal.size
LocType.COUNTRY -> countryTotal.size
LocType.STATE -> stateTotal.size
else -> 0
}
} else {
when (locMode) {
LocType.WORLD -> wwwTotal.sumOf { it.area }
LocType.COUNTRY -> countryTotal.sumOf { it.area }
LocType.STATE -> stateTotal.sumOf { it.area }
else -> 0
}
}
}
fun refreshMode(mode: LocType) {
val sum = (0 until itemCount).map {
val viewHolder = stats.findViewHolderForAdapterPosition(it) as? StatsViewHolder
viewHolder?.refresh(mode)
}.reduce { acc, i -> acc?.plus((i ?: 0)) }
val unitNow = if (!countMode) unit else ""
total.text = Settings.getStats(ctx, sum, getTotal(), unitNow)
}
fun invertCountMode() {
countMode = !countMode
refreshMode(locMode)
}
inner class StatsViewHolder(
private val _binding: ItemListGroupBinding
) : RecyclerView.ViewHolder(_binding.root) {
private lateinit var data: Pair<Int, Groups.Group>
private lateinit var wwwCount: List<GeoLoc>
private lateinit var countryCount: List<GeoLoc>
private lateinit var stateCount: List<GeoLoc>
fun bind(entry: Pair<Int, Groups.Group>): Int {
data = entry
_binding.groupColor.text = entry.second.name
val entryColor = data.second.color.color
val contrastEntryColor = getContrastColor(entryColor)
_binding.groupColor.setBackgroundColor(entryColor)
_binding.groupColor.setTextColor(contrastEntryColor)
_binding.name.setTextColor(contrastEntryColor)
_binding.groupColor.setOnClickListener { invertCountMode() }
compute()
return refresh(locMode)
}
private fun compute() {
val visited = Data.visits.getVisitedByValue(data.first)
wwwCount = World.WWW.children.filter { it.code in visited }
countryCount =
World.WWW.children.map { it.children.filter { itt -> itt.code in visited } }
.flatten()
stateCount =
World.WWW.children.map { it.children.map { itt -> itt.children.filter { ittt -> ittt.code in visited } } }
.flatten().flatten()
}
fun refresh(mode: LocType): Int {
locMode = mode
return if (countMode) {
val count = when (locMode) {
LocType.WORLD -> wwwCount.size
LocType.COUNTRY -> countryCount.size
LocType.STATE -> stateCount.size
else -> -1
}
_binding.name.text = count.toString()
count
} else {
val area = when (locMode) {
LocType.WORLD -> wwwCount.sumOf { it.area }
LocType.COUNTRY -> countryCount.sumOf { it.area }
LocType.STATE -> stateCount.sumOf { it.area }
else -> -1
}
_binding.name.text = ctx.getString(R.string.number_with_unit, area, unit)
area
}
}
}
}

View File

@ -1,11 +1,13 @@
package net.helcel.beans.activity.adapter package net.helcel.beans.activity.adapter
import android.graphics.drawable.ColorDrawable
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import net.helcel.beans.activity.fragment.EditPlaceFragment import net.helcel.beans.activity.fragment.EditPlaceFragment
import kotlin.math.max
class ViewPagerAdapter( class ViewPagerAdapter(
fragmentManager: FragmentManager, fragmentManager: FragmentManager,
@ -17,15 +19,13 @@ class ViewPagerAdapter(
private val fragmentList: MutableList<EditPlaceFragment> = ArrayList() private val fragmentList: MutableList<EditPlaceFragment> = ArrayList()
fun addFragment(src: EditPlaceFragment?, target: EditPlaceFragment) { fun addFragment(src: EditPlaceFragment?, target: EditPlaceFragment) {
if (src != null) { val idx = fragmentList.indexOf(src)
while (fragmentList.last() != src) { viewPager.currentItem = max(0, idx)
fragmentList.removeLast() if (src != null && idx >= 0) {
notifyItemRemoved(fragmentList.size) fragmentList.subList(idx + 1, fragmentList.size).clear()
} }
}
println(src.toString() + " - " + target.toString())
fragmentList.add(target) fragmentList.add(target)
notifyItemInserted(fragmentList.size) notifyItemRangeChanged(max(0, idx), fragmentList.size)
viewPager.currentItem = fragmentList.size - 1 viewPager.currentItem = fragmentList.size - 1
} }
@ -52,6 +52,10 @@ class ViewPagerAdapter(
override fun createFragment(position: Int): Fragment { override fun createFragment(position: Int): Fragment {
return fragmentList[position] return fragmentList[position]
} }
fun refreshColors(colorDrawable: ColorDrawable) {
fragmentList.forEach{ it.refreshColors(colorDrawable)}
}
} }

View File

@ -24,7 +24,8 @@ import net.helcel.beans.helper.Theme.colorToHex6
class EditGroupAddFragment( class EditGroupAddFragment(
private val key: Int = 0, private val key: Int = 0,
val onAddCb: (Int) -> Unit, val onAddCb: (Int) -> Unit,
val onDelCb: (Int) -> Unit val onDelCb: (Int) -> Unit,
private val deleteEnabled: Boolean = true
) : DialogFragment() { ) : DialogFragment() {
private lateinit var _binding: FragmentEditGroupsAddBinding private lateinit var _binding: FragmentEditGroupsAddBinding
@ -42,7 +43,7 @@ class EditGroupAddFragment(
_binding.colorView.background = ColorDrawable(grp.color.color) _binding.colorView.background = ColorDrawable(grp.color.color)
if (key == 0) { if (key == 0 || !deleteEnabled) {
_binding.btnDelete.visibility = View.INVISIBLE _binding.btnDelete.visibility = View.INVISIBLE
_binding.btnDelete.isEnabled = false _binding.btnDelete.isEnabled = false
} }
@ -52,8 +53,8 @@ class EditGroupAddFragment(
.setPositiveButton(android.R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->
val pos = Data.groups.findGroupPos(key) val pos = Data.groups.findGroupPos(key)
// Remove all countries belonging to that group // Remove all countries belonging to that group
// Delete the group
Data.visits.deleteVisited(key) Data.visits.deleteVisited(key)
// Delete the group
Data.groups.deleteGroup(key) Data.groups.deleteGroup(key)
Data.saveData() Data.saveData()
onDelCb(pos) onDelCb(pos)

View File

@ -3,17 +3,19 @@ package net.helcel.beans.activity.fragment
import android.app.Dialog import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.view.View
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import net.helcel.beans.activity.adapter.GeolocListAdapter import net.helcel.beans.R
import net.helcel.beans.activity.adapter.GroupListAdapter import net.helcel.beans.activity.adapter.GroupListAdapter
import net.helcel.beans.databinding.FragmentEditPlacesColorsBinding import net.helcel.beans.databinding.FragmentEditPlacesColorsBinding
import net.helcel.beans.helper.Data import net.helcel.beans.helper.Data
import net.helcel.beans.helper.DialogCloser
class EditPlaceColorFragment(private val parent: GeolocListAdapter.FoldingListViewHolder) : class EditPlaceColorFragment(private val parent: DialogCloser, private val delete: Boolean = false) :
DialogFragment() { DialogFragment() {
private lateinit var _binding: FragmentEditPlacesColorsBinding private lateinit var _binding: FragmentEditPlacesColorsBinding
@ -21,7 +23,8 @@ class EditPlaceColorFragment(private val parent: GeolocListAdapter.FoldingListVi
private var clear: Boolean = false private var clear: Boolean = false
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext()) val ctx = requireContext()
val builder = MaterialAlertDialogBuilder(ctx)
_binding = FragmentEditPlacesColorsBinding.inflate(layoutInflater) _binding = FragmentEditPlacesColorsBinding.inflate(layoutInflater)
_binding.btnAdd.setOnClickListener { _binding.btnAdd.setOnClickListener {
EditGroupAddFragment(0, { EditGroupAddFragment(0, {
@ -34,16 +37,24 @@ class EditPlaceColorFragment(private val parent: GeolocListAdapter.FoldingListVi
} }
val dialog = builder.setView(_binding.root).create() val dialog = builder.setView(_binding.root).create()
listAdapt = GroupListAdapter(requireActivity(), this) listAdapt = GroupListAdapter(requireActivity(), this, delete)
_binding.groupsColor.layoutManager = _binding.groupsColor.layoutManager =
LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false) LinearLayoutManager(ctx, RecyclerView.VERTICAL, false)
_binding.groupsColor.adapter = listAdapt _binding.groupsColor.adapter = listAdapt
if (delete) {
_binding.btnAdd.visibility = View.GONE
_binding.btnClear.text = ctx.getString(R.string.cancel)
_binding.warningText.text = ctx.getString(R.string.select_group)
} else {
_binding.warningText.text = ctx.getString(R.string.edit_group)
}
return dialog return dialog
} }
override fun onDismiss(dialog: DialogInterface) { override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog) super.onDismiss(dialog)
parent.onColorDialogDismiss(clear) parent.onDialogDismiss(clear)
} }
} }

View File

@ -1,5 +1,6 @@
package net.helcel.beans.activity.fragment package net.helcel.beans.activity.fragment
import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -8,11 +9,12 @@ import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import net.helcel.beans.activity.adapter.GeolocListAdapter import net.helcel.beans.activity.adapter.GeolocListAdapter
import net.helcel.beans.activity.adapter.GeolocListAdapter.FoldingListViewHolder
import net.helcel.beans.activity.adapter.ViewPagerAdapter import net.helcel.beans.activity.adapter.ViewPagerAdapter
import net.helcel.beans.countries.GeoLoc import net.helcel.beans.countries.GeoLoc
import net.helcel.beans.databinding.FragmentEditPlacesBinding import net.helcel.beans.databinding.FragmentEditPlacesBinding
class EditPlaceFragment(val loc: GeoLoc, private val pager: ViewPagerAdapter) : Fragment() { class EditPlaceFragment(val loc: GeoLoc, private val pager: ViewPagerAdapter, private val holder: FoldingListViewHolder? = null) : Fragment() {
private lateinit var _binding: FragmentEditPlacesBinding private lateinit var _binding: FragmentEditPlacesBinding
override fun onCreateView( override fun onCreateView(
@ -26,7 +28,11 @@ class EditPlaceFragment(val loc: GeoLoc, private val pager: ViewPagerAdapter) :
_binding.list.setHasFixedSize(true) _binding.list.setHasFixedSize(true)
_binding.list.layoutManager = _binding.list.layoutManager =
LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false) LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
_binding.list.adapter = GeolocListAdapter(this, loc, pager) _binding.list.adapter = GeolocListAdapter(this, loc, pager, holder)
return _binding.root return _binding.root
} }
fun refreshColors(colorDrawable: ColorDrawable) {
(_binding.list.adapter as GeolocListAdapter?)?.refreshColors(colorDrawable)
}
} }

View File

@ -5,29 +5,79 @@ import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import net.helcel.beans.R import net.helcel.beans.R
import net.helcel.beans.countries.GeoLocImporter import net.helcel.beans.countries.GeoLocImporter
import net.helcel.beans.helper.Data
import net.helcel.beans.helper.DialogCloser
import net.helcel.beans.helper.Settings
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat(), DialogCloser {
private var savedInstanceState: Bundle? = null
private var rootKey: String? = null
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
this.savedInstanceState = savedInstanceState
this.rootKey = rootKey
setPreferencesFromResource(R.xml.fragment_settings, rootKey) setPreferencesFromResource(R.xml.fragment_settings, rootKey)
val ctx = requireContext() val ctx = requireContext()
findPreference<Preference>(getString(R.string.key_regional))?.setOnPreferenceChangeListener { _, key ->
when (key as String) {
ctx.getString(R.string.off) -> GeoLocImporter.clearStates()
ctx.getString(R.string.on) -> GeoLocImporter.importStates(ctx)
else -> GeoLocImporter.clearStates()
}
true
}
// Select Light/Dark/System Mode // Select Light/Dark/System Mode
findPreference<Preference>(getString(R.string.key_theme))?.setOnPreferenceChangeListener { _, key -> findPreference<Preference>(getString(R.string.key_theme))?.setOnPreferenceChangeListener { _, key ->
setTheme(ctx, key as String) setTheme(ctx, key as String)
} }
// Select map projection
findPreference<Preference>(getString(R.string.key_projection))?.setOnPreferenceChangeListener { _, key ->
Settings.refreshProjection()
}
// Toggle groups
findPreference<Preference>(getString(R.string.key_group))?.setOnPreferenceChangeListener { _, key ->
if (key as String == ctx.getString(R.string.off)) {
val fragment = EditPlaceColorFragment(this, true)
fragment.show(
this.parentFragmentManager,
"AddColorDialogFragment"
)
false
} else {
true
}
}
// Toggle regional geolocs
findPreference<Preference>(getString(R.string.key_regional))?.setOnPreferenceChangeListener { _, key ->
when (key as String) {
ctx.getString(R.string.off) -> {
MaterialAlertDialogBuilder(requireActivity())
.setMessage(R.string.delete_regions)
.setPositiveButton(android.R.string.ok) { _, _ ->
GeoLocImporter.clearStates()
PreferenceManager.getDefaultSharedPreferences(ctx).edit().putString(
ctx.getString(R.string.key_regional),
ctx.getString(R.string.off)
).apply()
refreshPreferences()
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()
false
}
ctx.getString(R.string.on) -> {
GeoLocImporter.importStates(ctx, true)
true
}
else -> false
}
}
// Open license fragment // Open license fragment
findPreference<Preference>(getString(R.string.licenses))?.setOnPreferenceClickListener { findPreference<Preference>(getString(R.string.licenses))?.setOnPreferenceClickListener {
requireActivity().supportFragmentManager.beginTransaction() requireActivity().supportFragmentManager.beginTransaction()
@ -59,4 +109,34 @@ class SettingsFragment : PreferenceFragmentCompat() {
return true return true
} }
} }
override fun onDialogDismiss(clear: Boolean) {
// When turning groups off, select one group to keep and reassign everything
Data.selected_group?.let { selectedGroup ->
// Reassign all visited that are not to selectedGroup to selectedGroup
Data.visits.reassignAllVisitedToGroup(selectedGroup.key)
// Delete all groups that are not selectedGroup
Data.groups.deleteAllExcept(selectedGroup.key)
// Save and clear global variables
Data.saveData()
Data.selected_geoloc = null
Data.selected_group = null
// Actually change preference
val ctx = requireContext()
val sp = PreferenceManager.getDefaultSharedPreferences(ctx)
sp.edit().putString(ctx.getString(R.string.key_group), ctx.getString(R.string.off))
.apply()
// Refresh entire preference fragment to reflect changes
refreshPreferences()
}
}
private fun refreshPreferences() {
preferenceScreen.removeAll()
onCreatePreferences(savedInstanceState, rootKey)
}
} }

View File

@ -8,8 +8,6 @@ enum class Country(
HKG("Hong Kong", 1104), HKG("Hong Kong", 1104),
MAC("Macao", 32), MAC("Macao", 32),
ANT("Netherlands Antilles", 800), ANT("Netherlands Antilles", 800),
AFG("Afghanistan", 645487), AFG("Afghanistan", 645487),
XAD("Akrotiri and Dhekelia", 234), XAD("Akrotiri and Dhekelia", 234),
ALA("Åland", 1483), ALA("Åland", 1483),
@ -217,7 +215,7 @@ enum class Country(
SLB("Solomon Islands", 28686), SLB("Solomon Islands", 28686),
SOM("Somalia", 637672), SOM("Somalia", 637672),
ZAF("South Africa", 1224059), ZAF("South Africa", 1224059),
SGS("South Georgia and the South Sand", 4085), SGS("South Georgia and the South Sandwich Islands", 4085),
KOR("South Korea", 100721), KOR("South Korea", 100721),
SSD("South Sudan", 632186), SSD("South Sudan", 632186),
ESP("Spain", 506617), ESP("Spain", 506617),
@ -248,7 +246,7 @@ enum class Country(
ARE("United Arab Emirates", 71429), ARE("United Arab Emirates", 71429),
GBR("United Kingdom", 244732), GBR("United Kingdom", 244732),
USA("United States", 9477483), USA("United States", 9477483),
UMI("United States Minor Outlying Isl", 47), UMI("United States Minor Outlying Islands", 47),
URY("Uruguay", 178103), URY("Uruguay", 178103),
UZB("Uzbekistan", 447894), UZB("Uzbekistan", 447894),
VUT("Vanuatu", 12384), VUT("Vanuatu", 12384),
@ -265,5 +263,5 @@ enum class Country(
override val code = this.name override val code = this.name
override val type = GeoLoc.LocType.COUNTRY override val type = GeoLoc.LocType.COUNTRY
override val children: MutableList<GeoLoc> = ArrayList() override val children: MutableSet<GeoLoc> = HashSet()
} }

View File

@ -1,13 +1,10 @@
package net.helcel.beans.countries package net.helcel.beans.countries
import android.content.Context
import net.helcel.beans.helper.Settings
interface GeoLoc { interface GeoLoc {
enum class LocType { enum class LocType(val txt: String) {
WORLD, GROUP, CUSTOM_GROUP, COUNTRY, STATE; WORLD("World"), GROUP("Group"), CUSTOM_GROUP("Group"), COUNTRY("Country"), STATE("State");
} }
val code: String val code: String
@ -15,16 +12,7 @@ interface GeoLoc {
val area: Int val area: Int
val type: LocType val type: LocType
val children: List<GeoLoc> val children: Set<GeoLoc>
fun shouldShowChildren(ctx: Context): Boolean {
if (children.isEmpty())
return false
if (type == LocType.COUNTRY && !Settings.isRegional(ctx))
return false
return true
}
} }

View File

@ -1,25 +1,44 @@
package net.helcel.beans.countries package net.helcel.beans.countries
import android.content.Context import android.content.Context
import net.helcel.beans.helper.AUTO_GROUP
import net.helcel.beans.helper.Data
import net.helcel.beans.helper.NO_GROUP
import net.helcel.beans.helper.Settings import net.helcel.beans.helper.Settings
import java.io.BufferedReader import java.io.BufferedReader
import java.io.InputStreamReader import java.io.InputStreamReader
object GeoLocImporter { object GeoLocImporter {
fun importStates(ctx: Context) { fun importStates(ctx: Context, force: Boolean = false) {
if (!Settings.isRegional(ctx)) { if (!Settings.isRegional(ctx) and !force) {
return return
} }
val fs = BufferedReader(InputStreamReader(ctx.assets.open("geoloc_state.txt"))) val fs = BufferedReader(InputStreamReader(ctx.assets.open("geoloc_state.txt")))
while (fs.ready()) { while (fs.ready()) {
val line = fs.readLine().split("|") val line = fs.readLine().split("|")
val state = State(line[0], line[2], line[3].toInt()) val state = State(line[0], line[2], line[3].toInt())
Country.entries.find { it.code == line[1] }?.children?.add(state) val country = Country.entries.find { it.code == line[1] }
country?.children?.add(state)
country?.let {
if (Data.visits.getVisited(it) == NO_GROUP) {
Data.visits.setVisited(state, NO_GROUP)
}
}
} }
} }
fun clearStates() { fun clearStates() {
Country.entries.forEach { it.children.clear() } Country.entries.forEach { country ->
if (country.children.any { region ->
Data.visits.getVisited(region) != NO_GROUP
}) {
if (Data.visits.getVisited(country) == NO_GROUP) {
Data.visits.setVisited(country, AUTO_GROUP)
}
}
country.children.clear()
}
Data.saveData()
} }
} }

View File

@ -2,10 +2,12 @@ package net.helcel.beans.countries
import net.helcel.beans.countries.Country.* import net.helcel.beans.countries.Country.*
enum class Group(override val fullName: String, override val children: List<GeoLoc>) : GeoLoc { enum class Group(override val fullName: String, override val children: Set<GeoLoc>) : GeoLoc {
EEE( EEE(
"Europe", listOf( "Europe", setOf(
XAD,
ALA,// Åland Islands: an autonomous region of Finland, but not a member of the EU or UN
ALB, ALB,
AND, AND,
AUT, AUT,
@ -18,14 +20,19 @@ enum class Group(override val fullName: String, override val children: List<GeoL
CZE, CZE,
DNK, DNK,
EST, EST,
FRO, // Faroe Islands: an autonomous region of Denmark
FIN, FIN,
FRA, FRA,
DEU, DEU,
GIB, // Gibraltar: a British overseas territory located at the southern tip of the Iberian Peninsula
GRC, GRC,
GGY, // Guernsey: a British Crown dependency in the English Channel
HUN, HUN,
ISL, ISL,
IRL, IRL,
IMN, // Isle of Man: a British Crown dependency located in the Irish Sea
ITA, ITA,
JEY, // Jersey: a British Crown dependency located in the English Channel
KAZ, KAZ,
XKO, XKO,
LVA, LVA,
@ -48,25 +55,28 @@ enum class Group(override val fullName: String, override val children: List<GeoL
SVK, SVK,
SVN, SVN,
ESP, ESP,
SJM, // Svalbard and Jan Mayen: an archipelago administered by Norway
SWE, SWE,
CHE, CHE,
UKR, UKR,
GBR, GBR,
VAT, VAT,
XAD,
) )
), ),
ABB( ABB(
"Asia", listOf( "Asia", setOf(
AFG, AFG,
ARM, ARM,
AZE, AZE,
BHR, BHR,
BGD, BGD,
BTN, BTN,
IOT, // British Indian Ocean Territory: a British overseas territory in the Indian Ocean
BRN, BRN,
KHM, KHM,
CCK, // Cocos (Keeling) Islands: an Australian external territory in the Indian Ocean
CHN, CHN,
CXR, // Christmas Island: an Australian external territory in the Indian Ocean
GEO, GEO,
HKG, HKG,
IND, IND,
@ -111,7 +121,7 @@ enum class Group(override val fullName: String, override val children: List<GeoL
) )
), ),
FFF( FFF(
"Africa", listOf( "Africa", setOf(
DZA, DZA,
AGO, AGO,
BDI, BDI,
@ -131,8 +141,8 @@ enum class Group(override val fullName: String, override val children: List<GeoL
EGY, EGY,
GNQ, GNQ,
ERI, ERI,
SWZ,
ETH, ETH,
ATF, // French Southern and Antarctic Lands: a territory of France located in the southern Indian Ocean
GAB, GAB,
GMB, GMB,
GHA, GHA,
@ -165,6 +175,7 @@ enum class Group(override val fullName: String, override val children: List<GeoL
SSD, SSD,
SHN, SHN,
SDN, SDN,
SWZ,
TZA, TZA,
TGO, TGO,
TUN, TUN,
@ -176,7 +187,7 @@ enum class Group(override val fullName: String, override val children: List<GeoL
) )
), ),
NNN( NNN(
"North America", listOf( "North America", setOf(
ABW, ABW,
AIA, AIA,
ATG, ATG,
@ -184,9 +195,11 @@ enum class Group(override val fullName: String, override val children: List<GeoL
BRB, BRB,
BLZ, BLZ,
BMU, BMU,
BES, // Bonaire, Sint Eustatius and Saba: special municipalities of the Netherlands in the Caribbean
VGB, VGB,
CAN, CAN,
CYM, CYM,
XCL,
CRI, CRI,
CUB, CUB,
CUW, CUW,
@ -208,19 +221,22 @@ enum class Group(override val fullName: String, override val children: List<GeoL
NIC, NIC,
PAN, PAN,
PRI, PRI,
BLM, // Saint Barthélemy: an overseas collectivity of France in the Caribbean
KNA, KNA,
LCA, LCA,
MAF, MAF,
SPM, SPM,
VCT, VCT,
SXM, // Sint Maarten: a constituent country of the Kingdom of the Netherlands in the Caribbean
TTO, TTO,
TCA, TCA,
USA, USA,
XCL, UMI, // United States Minor Outlying Islands: a collection of nine insular areas of the United States
VIR, // United States Virgin Islands: an unincorporated territory of the United States in the Caribbean
) )
), ),
SRR( SRR(
"South America", listOf( "South America", setOf(
ARG, ARG,
BOL, BOL,
BRA, BRA,
@ -238,7 +254,7 @@ enum class Group(override val fullName: String, override val children: List<GeoL
) )
), ),
UUU( UUU(
"Oceania", listOf( "Oceania", setOf(
ASM, ASM,
AUS, AUS,
COK, COK,
@ -257,6 +273,7 @@ enum class Group(override val fullName: String, override val children: List<GeoL
PLW, PLW,
PNG, PNG,
PCN, PCN,
WSM, // Samoa: an independent island nation in the South Pacific
SLB, SLB,
TKL, TKL,
TON, TON,
@ -267,39 +284,22 @@ enum class Group(override val fullName: String, override val children: List<GeoL
), ),
XXX( XXX(
"Others", listOf( "Others", setOf(
ATA, // Antarctica: not in any other region ATA, // Antarctica: not in any other region
ALA,// Åland Islands: an autonomous region of Finland, but not a member of the EU or UN
BES,// Bonaire, Sint Eustatius and Saba: special municipalities of the Netherlands in the Caribbean
BVT, // Bouvet Island: an uninhabited territory of Norway in the South Atlantic BVT, // Bouvet Island: an uninhabited territory of Norway in the South Atlantic
IOT,// British Indian Ocean Territory: a British overseas territory in the Indian Ocean
CXR,// Christmas Island: an Australian external territory in the Indian Ocean
CCK,// Cocos (Keeling) Islands: an Australian external territory in the Indian Ocean
FRO,// Faroe Islands: an autonomous region of Denmark
ATF,// French Southern and Antarctic Lands: a territory of France located in the southern Indian Ocean
GIB,// Gibraltar: a British overseas territory located at the southern tip of the Iberian Peninsula
GGY,// Guernsey: a British Crown dependency in the English Channel
HMD, // Heard Island and McDonald Islands: an uninhabited Australian external territory in the southern Indian Ocean HMD, // Heard Island and McDonald Islands: an uninhabited Australian external territory in the southern Indian Ocean
IMN,// Isle of Man: a British Crown dependency located in the Irish Sea
JEY,// Jersey: a British Crown dependency located in the English Channel
BLM,// Saint Barthélemy: an overseas collectivity of France in the Caribbean
WSM, // Samoa: an independent island nation in the South Pacific
SXM, // Sint Maarten: a constituent country of the Kingdom of the Netherlands in the Caribbean
SGS, // South Georgia and the South Sandwich Islands: a British overseas territory in the southern Atlantic Ocean SGS, // South Georgia and the South Sandwich Islands: a British overseas territory in the southern Atlantic Ocean
SJM, // Svalbard and Jan Mayen: an archipelago administered by Norway
UMI, // United States Minor Outlying Islands: a collection of nine insular areas of the United States
VIR, // United States Virgin Islands: an unincorporated territory of the United States in the Caribbean
) )
), ),
ZZZ( ZZZ(
"Undefined", listOf( "Undefined", setOf(
) )
), ),
NTT( NTT(
"NATO", listOf( "NATO", setOf(
ALB, BEL, BGR, CAN, HRV, CZE, DNK, EST, FRA, DEU, GRC, HUN, ISL, ITA, LVA, LTU, LUX, ALB, BEL, BGR, CAN, HRV, CZE, DNK, EST, FRA, DEU, GRC, HUN, ISL, ITA, LVA, LTU, LUX,
MNE, NLD, NOR, POL, PRT, ROU, SVK, SVN, ESP, TUR, GBR, USA MNE, NLD, NOR, POL, PRT, ROU, SVK, SVN, ESP, TUR, GBR, USA
) )

View File

@ -3,6 +3,17 @@ package net.helcel.beans.countries
class State(override val code: String, override val fullName: String, override val area: Int) : class State(override val code: String, override val fullName: String, override val area: Int) :
GeoLoc { GeoLoc {
override val children = emptyList<GeoLoc>() override val children = emptySet<GeoLoc>()
override val type = GeoLoc.LocType.STATE override val type = GeoLoc.LocType.STATE
override fun hashCode(): Int {
return code.hashCode()
}
override fun equals(other: Any?): Boolean {
if (other is GeoLoc) {
return other.code == this.code
}
return false
}
} }

View File

@ -2,19 +2,18 @@ package net.helcel.beans.countries
import net.helcel.beans.countries.Group.* import net.helcel.beans.countries.Group.*
enum class World(override val fullName: String, override val children: List<GeoLoc>) : GeoLoc { enum class World(override val fullName: String, override val children: Set<GeoLoc>) : GeoLoc {
WWW("World", listOf( WWW(
"World", setOf(
EEE, ABB, FFF, NNN, SRR, UUU, XXX EEE, ABB, FFF, NNN, SRR, UUU, XXX
)); )
);
override val area = children.fold(0) { acc, i -> override val area = children.fold(0) { acc, i ->
acc + i.area acc + i.area
} }
override val type = GeoLoc.LocType.WORLD override val type = GeoLoc.LocType.WORLD
override val code = this.name override val code = this.name
} }

View File

@ -10,13 +10,12 @@ import net.helcel.beans.countries.GeoLoc
import java.util.HashMap import java.util.HashMap
object Data { object Data {
var visits : Visits = Visits(0, HashMap()) var visits : Visits = Visits(0, HashMap())
var groups : Groups = Groups(0,HashMap()) var groups : Groups = Groups(0,HashMap())
var selected_group : Groups.Group? = null var selected_group : Groups.Group? = null
var selected_geoloc: GeoLoc? = null var selected_geoloc: GeoLoc? = null
var clearing_geoloc: GeoLoc? = null
private val groupsSerial = Groups.GroupsSerializer() private val groupsSerial = Groups.GroupsSerializer()
private val visitsSerial = Visits.VisitsSerializer() private val visitsSerial = Visits.VisitsSerializer()
@ -34,10 +33,9 @@ fun loadData(ctx: Context, id:Int) {
// Add default group "Visited" with app's color if there is no group already // Add default group "Visited" with app's color if there is no group already
if (groups.size() == 0) { if (groups.size() == 0) {
groups.setGroup(1, "Visited", ColorDrawable(ContextCompat.getColor(ctx, R.color.blue))) groups.setGroup(DEFAULT_GROUP, "Visited", ColorDrawable(ContextCompat.getColor(ctx, R.color.blue)))
saveData() saveData()
} }
} }
fun saveData() { fun saveData() {

View File

@ -0,0 +1,5 @@
package net.helcel.beans.helper
interface DialogCloser {
fun onDialogDismiss(clear: Boolean)
}

View File

@ -2,17 +2,24 @@ package net.helcel.beans.helper
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import androidx.core.content.ContextCompat
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer import kotlinx.serialization.Serializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import net.helcel.beans.R
import java.io.InputStream import java.io.InputStream
import kotlin.coroutines.coroutineContext
import kotlin.random.Random import kotlin.random.Random
private const val randSeed = 0 private const val randSeed = 0
private val rnd = Random(randSeed) private val rnd = Random(randSeed)
const val NO_GROUP = 0
const val DEFAULT_GROUP = 1
const val AUTO_GROUP = -1
@Serializable @Serializable
class Groups(val id: Int, private val grps: HashMap<Int, Group>) { class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
@ -24,13 +31,18 @@ class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
grps.remove(key) grps.remove(key)
} }
fun deleteAllExcept(grp: Int) {
val keysToDelete = grps.keys.filter { it != grp }
keysToDelete.forEach { grps.remove(it) }
}
fun getGroupFromKey(key: Int): Group { fun getGroupFromKey(key: Int): Group {
return grps.getOrDefault(key, EmptyGroup()) return grps.getOrDefault(key, EmptyGroup())
} }
fun genKey(): Int { fun genKey(): Int {
val key = rnd.nextInt() val key = rnd.nextInt()
if (grps.containsKey(key) || key == 0) return genKey() if (grps.containsKey(key) || key in listOf(NO_GROUP, DEFAULT_GROUP, AUTO_GROUP)) return genKey()
return key return key
} }
@ -63,7 +75,7 @@ class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
val key: Int, val key: Int,
val name: String, val name: String,
@Serializable(with = Theme.ColorDrawableSerializer::class) val color: ColorDrawable = ColorDrawable( @Serializable(with = Theme.ColorDrawableSerializer::class) val color: ColorDrawable = ColorDrawable(
Color.TRANSPARENT Color.GRAY
) )
) )

View File

@ -4,12 +4,15 @@ import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import net.helcel.beans.R import net.helcel.beans.R
import net.helcel.beans.activity.MainActivity
import net.helcel.beans.activity.fragment.SettingsFragment import net.helcel.beans.activity.fragment.SettingsFragment
object Settings { object Settings {
private lateinit var sp: SharedPreferences private lateinit var sp: SharedPreferences
fun start(ctx: Context) { private lateinit var mainActivity: MainActivity
fun start(ctx: MainActivity) {
mainActivity = ctx
sp = PreferenceManager.getDefaultSharedPreferences(ctx) sp = PreferenceManager.getDefaultSharedPreferences(ctx)
SettingsFragment.setTheme( SettingsFragment.setTheme(
ctx, sp.getString(ctx.getString(R.string.key_theme), ctx.getString(R.string.system)) ctx, sp.getString(ctx.getString(R.string.key_theme), ctx.getString(R.string.system))
@ -37,6 +40,11 @@ object Settings {
) )
} }
fun refreshProjection(): Boolean {
mainActivity.refreshProjection()
return true
}
private fun getBooleanValue(ctx: Context, key: String?): Boolean { private fun getBooleanValue(ctx: Context, key: String?): Boolean {
return when (key) { return when (key) {
ctx.getString(R.string.on) -> true ctx.getString(R.string.on) -> true
@ -44,4 +52,24 @@ object Settings {
else -> false else -> false
} }
} }
fun getStats(ctx: Context, numerator: Int?, denominator: Int?, unit: String = ""): String {
if (numerator == null || denominator == null || denominator == 0) {
return ""
}
return when (getStatPref(ctx)) {
ctx.getString(R.string.percentages) -> ctx.getString(
R.string.percentage,
(100 * (numerator.toFloat() / denominator.toFloat())).toInt()
)
else -> {
if (unit == "") {
ctx.getString(R.string.rate, numerator, denominator)
} else {
ctx.getString(R.string.rate_with_unit, numerator, denominator, unit)
}
}
}
}
} }

View File

@ -27,7 +27,7 @@ class Visits(val id: Int, private val locs: HashMap<String, Int>) {
} }
fun getVisited(key: GeoLoc): Int { fun getVisited(key: GeoLoc): Int {
return locs.getOrDefault(key.code, 0) return getVisited(key.code)
} }
private fun getVisited(key: String): Int { private fun getVisited(key: String): Int {
@ -42,6 +42,19 @@ class Visits(val id: Int, private val locs: HashMap<String, Int>) {
return locs.keys.groupBy { getVisited(it) } return locs.keys.groupBy { getVisited(it) }
} }
fun getVisitedByValue(key: Int): List<String> {
return locs.filter { it.value == key }.keys.toList()
}
fun reassignAllVisitedToGroup(group: Int) {
val keys = locs.filter { (_, grp) ->
grp !in listOf(NO_GROUP, AUTO_GROUP)
}.keys
keys.forEach {
locs[it] = group
}
}
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
@Serializer(Visits::class) @Serializer(Visits::class)
class VisitsSerializer { class VisitsSerializer {

View File

@ -2,49 +2,64 @@ package net.helcel.beans.svg
import android.content.Context import android.content.Context
import net.helcel.beans.countries.World import net.helcel.beans.countries.World
import net.helcel.beans.helper.AUTO_GROUP
import net.helcel.beans.helper.Data.groups import net.helcel.beans.helper.Data.groups
import net.helcel.beans.helper.Data.visits import net.helcel.beans.helper.Data.visits
import net.helcel.beans.helper.NO_GROUP
import net.helcel.beans.helper.Settings
import net.helcel.beans.helper.Theme.colorToHex6 import net.helcel.beans.helper.Theme.colorToHex6
import net.helcel.beans.helper.Theme.colorWrapper import net.helcel.beans.helper.Theme.colorWrapper
class CSSWrapper(ctx: Context) { class CSSWrapper(private val ctx: Context) {
private val colorForeground: String = private val colorForeground: String =
colorToHex6(colorWrapper(ctx, android.R.attr.panelColorBackground)) colorToHex6(colorWrapper(ctx, android.R.attr.panelColorBackground))
private val colorBackground: String = private val colorBackground: String =
colorToHex6(colorWrapper(ctx, android.R.attr.colorBackground)) colorToHex6(colorWrapper(ctx, android.R.attr.colorBackground))
private val baseCSS: String private val continents: String = World.WWW.children.joinToString(",") { "#${it.code}2" }
private val countries: String = World.WWW.children.joinToString(",") { itt ->
itt.children.joinToString(",") { "#${it.code}2" }
}
private val regional: String = World.WWW.children.joinToString(",") { itt ->
itt.children.joinToString(",") { "#${it.code}1" }
}
private val countryOnlyCSS: String =
"svg{fill:$colorForeground;stroke:$colorBackground;stroke-width:0.1;}" +
"${regional}{display:none;}"
private val countryRegionalCSS: String =
"svg{fill:$colorForeground;stroke:$colorBackground;stroke-width:0.01;}" +
"$continents,$countries{fill:none;stroke:$colorBackground;stroke-width:0.1;}"
private var customCSS: String = "" private var customCSS: String = ""
init { init {
val www = World.WWW.children.joinToString(",") { "#${it.code}2" }
val ccc = World.WWW.children.joinToString(",") { itt ->
itt.children.joinToString(",") { "#${it.code}2" }
}
baseCSS = "svg{fill:$colorForeground;stroke:$colorBackground;stroke-width:0.01;}" +
"$www,$ccc{stroke:$colorBackground;stroke-width:0.1;fill:none}"
refresh() refresh()
} }
fun refresh() { private fun refresh() {
val id = if (Settings.isRegional(ctx)) "1" else "2"
customCSS = visits.getVisitedByValue().map { (k, v) -> customCSS = visits.getVisitedByValue().map { (k, v) ->
if (groups.getGroupFromKey(k).key == 0) if (groups.getGroupFromKey(k).key != NO_GROUP || (!Settings.isRegional(ctx) && k == AUTO_GROUP)) {
"" v.joinToString(",") { "#${it}$id,#${it}" } + "{fill:${
else
v.joinToString(",") { "#${it}1,#${it}" } + "{fill:${
colorToHex6( colorToHex6(
groups.getGroupFromKey( if (k == AUTO_GROUP)
k colorWrapper(ctx, android.R.attr.colorPrimary)
).color else groups.getGroupFromKey(k).color
) )
};}" };}"
} else {
""
}
}.joinToString("") }.joinToString("")
} }
fun get(): String { fun get(): String {
refresh() refresh()
return baseCSS + customCSS return if (Settings.isRegional(ctx)) {
countryRegionalCSS + customCSS
} else {
countryOnlyCSS + customCSS
}
} }
} }

View File

@ -1,11 +1,24 @@
package net.helcel.beans.svg package net.helcel.beans.svg
import android.content.Context import android.content.Context
import androidx.preference.PreferenceManager
import com.caverock.androidsvg.SVG import com.caverock.androidsvg.SVG
import net.helcel.beans.R
class SVGWrapper(ctx: Context) { class SVGWrapper(ctx: Context) {
private var svg: SVG? = SVG.getFromAsset(ctx.assets, "mercator01.svg") val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx)
private val svgFile = when (sharedPreferences.getString(
ctx.getString(R.string.key_projection),
ctx.getString(R.string.mercator)
)) {
ctx.getString(R.string.azimuthalequidistant) -> "aeqd01.svg"
ctx.getString(R.string.loximuthal) -> "loxim01.svg"
ctx.getString(R.string.mercator) -> "webmercator01.svg"
else -> "webmercator01.svg"
}
private var svg: SVG? = SVG.getFromAsset(ctx.assets, svgFile)
fun get(): SVG? { fun get(): SVG? {
return svg return svg

View File

@ -0,0 +1,10 @@
<vector
android:height="24dp"
android:viewportHeight="960"
android:viewportWidth="960"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="?attr/colorOnBackground"
android:pathData="M346,820L100,574Q90,564 85,552Q80,540 80,527Q80,514 85,502Q90,490 100,480L330,251L224,145L286,80L686,480Q696,490 700.5,502Q705,514 705,527Q705,540 700.5,552Q696,564 686,574L440,820Q430,830 418,835Q406,840 393,840Q380,840 368,835Q356,830 346,820ZM393,314L179,528Q179,528 179,528Q179,528 179,528L607,528Q607,528 607,528Q607,528 607,528L393,314ZM792,840Q756,840 731,814.5Q706,789 706,752Q706,725 719.5,701Q733,677 750,654L792,600L836,654Q852,677 866,701Q880,725 880,752Q880,789 854,814.5Q828,840 792,840Z"/>
</vector>

View File

@ -8,34 +8,34 @@
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="4" android:strokeWidth="4"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#000000" android:strokeColor="?attr/colorOnBackground"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
<path <path
android:pathData="M51,25v31c0,2.209 -1.791,4 -4,4H25c-2.209,0 -4,-1.791 -4,-4V25" android:pathData="M51,25v31c0,2.209 -1.791,4 -4,4H25c-2.209,0 -4,-1.791 -4,-4V25"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="4" android:strokeWidth="4"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#000000" android:strokeColor="?attr/colorOnBackground"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
<path <path
android:pathData="M17,16h38v4h-38z" android:pathData="M17,16h38v4h-38z"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="4" android:strokeWidth="4"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#000000" android:strokeColor="?attr/colorOnBackground"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
<path <path
android:pathData="M41,28.25L41,55" android:pathData="M41,28.25L41,55"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="4" android:strokeWidth="4"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#000000" android:strokeColor="?attr/colorOnBackground"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
<path <path
android:pathData="M31,28.25L31,55" android:pathData="M31,28.25L31,55"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="4" android:strokeWidth="4"
android:fillColor="#00000000" android:fillColor="#00000000"
android:strokeColor="#000000" android:strokeColor="?attr/colorOnBackground"
android:strokeLineCap="round"/> android:strokeLineCap="round"/>
</vector> </vector>

View File

@ -0,0 +1,16 @@
<vector
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android" >
<path android:fillColor="?attr/colorOnBackground" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
<path android:fillColor="?attr/colorPrimary" android:pathData="M8,14m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path android:fillColor="?attr/colorPrimary" android:pathData="M12,8m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path android:fillColor="?attr/colorPrimary" android:pathData="M16,14m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
</vector>

View File

@ -5,6 +5,6 @@
android:viewportWidth="960" android:viewportWidth="960"
android:viewportHeight="960"> android:viewportHeight="960">
<path <path
android:fillColor="@color/blue" android:fillColor="@color/darkgray"
android:pathData="M0,0h960v960h-960z" /> android:pathData="M0,0h960v960h-960z" />
</vector> </vector>

View File

@ -1,13 +1,50 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp" android:width="108dp"
android:height="12dp" android:height="108dp"
android:viewportWidth="1600" android:viewportWidth="128"
android:viewportHeight="1600"> android:viewportHeight="128">
<group android:scaleX="0.8918919"
android:scaleY="0.8918919"
android:translateX="6.918919"
android:translateY="6.918919">
<group
android:scaleX="1.5"
android:scaleY="1.5"
android:translateX="10"
android:translateY="10">
<path <path
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"/>
</group>
<group
android:scaleX="1.25"
android:scaleY="1.25"
android:translateX="18"
android:translateY="18">
<path
android:pathData="M56.803,45.75c0.599,-0.299 1.157,-0.672 1.663,-1.11 0.804,-0.698 1.463,-1.546 1.94,-2.497 0.599,-1.303 0.883,-2.728 0.829,-4.161 0.034,-1.498 -0.154,-2.994 -0.558,-4.437 -0.451,-1.645 -1.104,-3.229 -1.944,-4.714 -0.967,-2.141 -2.28,-4.108 -3.887,-5.822 -1.242,-1.326 -2.757,-2.366 -4.44,-3.048 -0.877,-0.372 -1.821,-0.56 -2.774,-0.553 -1.402,0.074 -2.729,0.697 -3.882,1.389 -1.285,0.81 -2.244,1.735 -2.771,3.053 -0.739,2.362 0.827,4.821 1.113,5.269 0.003,0.005 0.187,0.281 0.555,0.832 1.512,2.264 1.589,2.358 1.666,2.495 0.646,1.221 1.114,2.528 1.389,3.882 1.043,4.001 1.565,6.001 2.223,6.932 1.208,1.71 3.455,3.414 5.826,3.325 1.059,-0.088 2.093,-0.371 3.05,-0.835Z"
android:strokeWidth="2"
android:fillColor="@color/white" android:fillColor="@color/white"
android:fillType="nonZero" android:strokeColor="#000000"
android:pathData="m800,1200q-83,0 -156,-31.5Q571,1137 517,1083 463,1029 431.5,956 400,883 400,800 400,717 431.5,644 463,571 517,517 571,463 644,431.5 717,400 800,400q83,0 156,31.5 73,31.5 127,85.5 54,54 85.5,127 31.5,73 31.5,156 0,83 -31.5,156 -31.5,73 -85.5,127 -54,54 -127,85.5 -73,31.5 -156,31.5zM800,1120q134,0 227,-93 93,-93 93,-227 0,-7 -0.5,-14.5 -0.5,-7.5 -0.5,-12.5 -5,29 -27,48 -22,19 -52,19L960,840Q927,840 903.5,816.5 880,793 880,760L880,720L720,720v-80q0,-33 23.5,-56.5Q767,560 800,560h40v0q0,-23 12.5,-40.5Q865,502 883,491q-20,-5 -40.5,-8 -20.5,-3 -42.5,-3 -134,0 -227,93 -93,93 -93,227 0,0 0,0 0,0 0,0h200q66,0 113,47 47,47 47,113v40L720,1000v110q20,5 39.5,7.5 19.5,2.5 40.5,2.5z" android:strokeLineCap="round"/>
android:strokeWidth="1" <path
android:strokeColor="#00000000" /> android:pathData="M22,41c-1.54,0.554 -2.83,1.642 -3.636,3.066 -0.714,1.365 -0.957,2.928 -0.693,4.445 0.178,1.247 0.632,2.439 1.329,3.488 2.032,3.228 5.383,4.423 7,5 1.613,0.561 3.295,0.897 5,1 2.387,0.205 6.923,0.535 11,-2 1.287,-0.665 2.335,-1.713 3,-3 0.661,-1.601 0.661,-3.399 0,-5 -0.389,-1.156 -1.121,-2.165 -2.099,-2.894 -0.919,-0.599 -1.974,-0.956 -3.069,-1.039 -2.057,-0.313 -2.756,0.139 -5.014,0.057 -1.271,-0.019 -2.534,-0.214 -3.753,-0.577 -3.036,-0.95 -3.33,-2.457 -5.889,-2.829 -1.066,-0.158 -2.155,-0.061 -3.177,0.282Z"
android:strokeWidth="2"
android:fillColor="@color/red"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
<path
android:pathData="M12.7,26.975c1.758,-3.604 5.311,-3.191 9.58,-7.091 2.701,-2.469 2.858,-4.078 5.613,-5.202 1.407,-0.644 2.984,-0.819 4.498,-0.5 2.053,0.475 3.761,1.891 4.61,3.819 1.116,2.742 -0.314,5.437 -1.398,7.482 -0.951,1.689 -2.167,3.215 -3.602,4.518 -1.479,1.552 -3.161,2.898 -5,4 -2.629,1.541 -6.332,3.711 -9.989,2.43 -1.481,-0.548 -2.768,-1.521 -3.699,-2.796 -1.496,-1.906 -1.735,-4.512 -0.612,-6.659Z"
android:strokeWidth="2"
android:fillColor="@color/green"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
</group>
</group>
</vector> </vector>

View File

@ -0,0 +1,16 @@
<vector
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android" >
<path
android:fillColor="?attr/colorOnBackground"
android:pathData="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48L3,20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48L21,3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM10,5.47l4,1.4v11.66l-4,-1.4L10,5.47zM5,6.46l3,-1.01v11.7l-3,1.16L5,6.46zM19,17.54l-3,1.01L16,6.86l3,-1.16v11.84z" />
<path
android:fillColor="?attr/colorPrimary"
android:pathData="M15,18.89l-6,-2.11L9,5.11l6,2.11v11.67z"/>
</vector>

View File

@ -7,7 +7,7 @@
<path <path
android:fillColor="?attr/colorOnBackground" android:fillColor="?attr/colorOnBackground"
android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10c1.38,0 2.5,-1.12 2.5,-2.5c0,-0.61 -0.23,-1.2 -0.64,-1.67c-0.08,-0.1 -0.13,-0.21 -0.13,-0.33c0,-0.28 0.22,-0.5 0.5,-0.5H16c3.31,0 6,-2.69 6,-6C22,6.04 17.51,2 12,2zM17.5,13c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C19,12.33 18.33,13 17.5,13zM14.5,9C13.67,9 13,8.33 13,7.5C13,6.67 13.67,6 14.5,6S16,6.67 16,7.5C16,8.33 15.33,9 14.5,9zM5,11.5C5,10.67 5.67,10 6.5,10S8,10.67 8,11.5C8,12.33 7.33,13 6.5,13S5,12.33 5,11.5zM11,7.5C11,8.33 10.33,9 9.5,9S8,8.33 8,7.5C8,6.67 8.67,6 9.5,6S11,6.67 11,7.5z" /> android:pathData="M12,22C6.49,22 2,17.51 2,12S6.49,2 12,2s10,4.04 10,9c0,3.31 -2.69,6 -6,6h-1.77c-0.28,0 -0.5,0.22 -0.5,0.5c0,0.12 0.05,0.23 0.13,0.33c0.41,0.47 0.64,1.06 0.64,1.67C14.5,20.88 13.38,22 12,22zM12,4c-4.41,0 -8,3.59 -8,8s3.59,8 8,8c0.28,0 0.5,-0.22 0.5,-0.5c0,-0.16 -0.08,-0.28 -0.14,-0.35c-0.41,-0.46 -0.63,-1.05 -0.63,-1.65c0,-1.38 1.12,-2.5 2.5,-2.5H16c2.21,0 4,-1.79 4,-4C20,7.14 16.41,4 12,4z" />
<path <path
android:fillColor="?attr/colorPrimary" android:fillColor="?attr/colorPrimary"
android:pathData="M17.5,13c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C19,12.33 18.33,13 17.5,13zM14.5,9C13.67,9 13,8.33 13,7.5C13,6.67 13.67,6 14.5,6S16,6.67 16,7.5C16,8.33 15.33,9 14.5,9zM5,11.5C5,10.67 5.67,10 6.5,10S8,10.67 8,11.5C8,12.33 7.33,13 6.5,13S5,12.33 5,11.5zM11,7.5C11,8.33 10.33,9 9.5,9S8,8.33 8,7.5C8,6.67 8.67,6 9.5,6S11,6.67 11,7.5z" /> android:pathData="M17.5,13c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5s1.5,0.67 1.5,1.5C19,12.33 18.33,13 17.5,13zM14.5,9C13.67,9 13,8.33 13,7.5C13,6.67 13.67,6 14.5,6S16,6.67 16,7.5C16,8.33 15.33,9 14.5,9zM5,11.5C5,10.67 5.67,10 6.5,10S8,10.67 8,11.5C8,12.33 7.33,13 6.5,13S5,12.33 5,11.5zM11,7.5C11,8.33 10.33,9 9.5,9S8,8.33 8,7.5C8,6.67 8.67,6 9.5,6S11,6.67 11,7.5z" />

View File

@ -0,0 +1,12 @@
<vector
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android" >
<path android:fillColor="?attr/colorOnBackground" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
<path android:fillColor="?attr/colorPrimary" android:pathData="M12,10h-2v2H9v-2H7V9h2V7h1v2h2v1z"/>
</vector>

View File

@ -1,15 +1,66 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:theme="@style/Theme.Beans" android:theme="@style/Theme.Beans"
tools:context=".activity.StatActivity"> tools:context=".activity.StatsActivity">
<com.github.mikephil.charting.charts.PieChart <com.google.android.material.tabs.TabLayout
android:id="@+id/chart" android:id="@+id/tab"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="gone" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/group_color"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:paddingStart="56dp"
android:text="@string/total"
android:textAlignment="textStart"
android:textColor="?attr/colorOnPrimary"
app:cornerRadius="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlSymmetry" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="start|center_vertical"
android:paddingStart="20dp"
android:paddingEnd="52dp"
android:text=""
android:textColor="?attr/colorOnPrimary"
app:layout_constraintBottom_toBottomOf="@id/group_color"
app:layout_constraintEnd_toEndOf="@id/group_color"
app:layout_constraintTop_toTopOf="@id/group_color" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/stats"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>

View File

@ -12,12 +12,11 @@
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.imageview.ShapeableImageView <com.google.android.material.imageview.ShapeableImageView
android:layout_width="250dp" android:layout_width="300dp"
android:layout_height="250dp" android:layout_height="300dp"
android:layout_marginTop="40dp" android:layout_marginTop="20dp"
android:layout_marginBottom="30dp"
android:contentDescription="@string/logo" android:contentDescription="@string/logo"
android:src="@mipmap/ic_launcher_round" /> android:src="@drawable/ic_launcher_foreground" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -6,6 +6,12 @@
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:padding="16dp">
<TextView
android:id="@+id/warning_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp" />
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -0,0 +1,13 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="net.helcel.beans.activity.EditActivity" >
<item
android:id="@+id/action_color"
android:orderInCategory="100"
android:icon="@drawable/color"
android:title="@string/action_color"
app:showAsAction="ifRoom" />
</menu>

View File

@ -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>

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -15,4 +15,11 @@
<item>@string/on</item> <item>@string/on</item>
<item>@string/off</item> <item>@string/off</item>
</string-array> </string-array>
<string-array name="map_projection">
<item>@string/azimuthalequidistant</item>
<item>@string/loximuthal</item>
<item>@string/mercator</item>
</string-array>
</resources> </resources>

View File

@ -2,12 +2,12 @@
<resources> <resources>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="darkgray">#FF0C1D2E</color> <color name="darkgray">#FF0C1D2E</color>
<color name="gray">#425F7C</color>
<color name="lightgray">#FF93A9BE</color> <color name="lightgray">#FF93A9BE</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFF0F3F7</color>
<color name="green">#93F531</color>
<color name="blue">#3193F5</color>
<color name="red">#F53131</color>
<color name="blue">#0d5cab</color>
<color name="green">#B9F57D</color>
<color name="red">#F57D7D</color>
</resources> </resources>

View File

@ -5,6 +5,7 @@
<string name="action_settings">Settings</string> <string name="action_settings">Settings</string>
<string name="action_stat">Stats</string> <string name="action_stat">Stats</string>
<string name="action_edit">Edit</string> <string name="action_edit">Edit</string>
<string name="action_color">Color</string>
<string name="key_theme">App theme</string> <string name="key_theme">App theme</string>
<string name="system">System</string> <string name="system">System</string>
<string name="light">Light</string> <string name="light">Light</string>
@ -20,13 +21,18 @@
<string name="beans_repo">Project repository: https://git.helcel.net/helcel/beans\n Feel free to report issues or contribute to the project.</string> <string name="beans_repo">Project repository: https://git.helcel.net/helcel/beans\n Feel free to report issues or contribute to the project.</string>
<string name="foss_licenses">Free and open source dependencies and licenses</string> <string name="foss_licenses">Free and open source dependencies and licenses</string>
<string name="about_beans">About the Beans application</string> <string name="about_beans">About the Beans application</string>
<string name="edit_group">Select the group to assign. Long press on a group to edit its name and color.</string>
<string name="delete_group">Are your sure you want to delete this group and remove all its country mappings?</string> <string name="delete_group">Are your sure you want to delete this group and remove all its country mappings?</string>
<string name="select_group">Select one group you want to keep. All others will be deleted and its mappings reassigned to the group you choose here.</string>
<string name="delete_regions">Are you sure you want to disable regions and reassign all regional mappings to the corresponding countries?</string>
<string name="add">Add</string> <string name="add">Add</string>
<string name="clear">Clear</string> <string name="clear">Clear</string>
<string name="logo">Logo</string> <string name="logo">Logo</string>
<string name="name">Name</string> <string name="name">Name</string>
<string name="rate">%1$d/%2$d</string> <string name="rate">%1$d/%2$d</string>
<string name="rate_with_unit">%1$d / %2$d %3$s</string>
<string name="percentage">%1$d&#65285;</string> <string name="percentage">%1$d&#65285;</string>
<string name="number_with_unit">%1$d %2$s</string>
<string name="color_rrggbb">RRGGBB</string> <string name="color_rrggbb">RRGGBB</string>
<string name="hashtag">#</string> <string name="hashtag">#</string>
<string name="on">On</string> <string name="on">On</string>
@ -34,4 +40,10 @@
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="cancel">Cancel</string> <string name="cancel">Cancel</string>
<string name="ok">Ok</string> <string name="ok">Ok</string>
<string name="total">Total</string>
<string name="uncategorized">Uncategorized</string>
<string name="azimuthalequidistant">Azimuthal Equidistant</string>
<string name="mercator">Mercator</string>
<string name="loximuthal">Loximuthal</string>
<string name="key_projection">Map Projection</string>
</resources> </resources>

View File

@ -4,23 +4,23 @@
android:theme="@style/Theme.Beans"> android:theme="@style/Theme.Beans">
<ListPreference <ListPreference
app:defaultValue="@string/off" app:defaultValue="@string/system"
app:enabled="true" app:enabled="true"
app:entries="@array/entries_onoff" app:entries="@array/entries_theme"
app:entryValues="@array/entries_onoff" app:entryValues="@array/entries_theme"
app:icon="@drawable/edit" app:icon="@drawable/palette"
app:key="@string/key_group" app:key="@string/key_theme"
app:title="@string/key_group" app:title="@string/key_theme"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<ListPreference <ListPreference
app:defaultValue="@string/off" app:defaultValue="@string/mercator"
app:enabled="true" app:enabled="true"
app:entries="@array/entries_onoff" app:entries="@array/map_projection"
app:entryValues="@array/entries_onoff" app:entryValues="@array/map_projection"
app:icon="@drawable/edit" app:icon="@drawable/map"
app:key="@string/key_regional" app:key="@string/key_projection"
app:title="@string/key_regional" app:title="@string/key_projection"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<ListPreference <ListPreference
@ -34,18 +34,30 @@
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<ListPreference <ListPreference
app:defaultValue="@string/system" app:defaultValue="@string/off"
app:enabled="true" app:enabled="true"
app:entries="@array/entries_theme" app:allowDividerAbove="true"
app:entryValues="@array/entries_theme" app:entries="@array/entries_onoff"
app:icon="@drawable/palette" app:entryValues="@array/entries_onoff"
app:key="@string/key_theme" app:icon="@drawable/group"
app:title="@string/key_theme" app:key="@string/key_group"
app:title="@string/key_group"
app:useSimpleSummaryProvider="true" />
<ListPreference
app:defaultValue="@string/off"
app:enabled="true"
app:entries="@array/entries_onoff"
app:entryValues="@array/entries_onoff"
app:icon="@drawable/zoomin"
app:key="@string/key_regional"
app:title="@string/key_regional"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<Preference <Preference
android:summary="@string/foss_licenses" android:summary="@string/foss_licenses"
app:enabled="true" app:enabled="true"
app:allowDividerAbove="true"
app:icon="@drawable/licenses" app:icon="@drawable/licenses"
app:key="@string/licenses" app:key="@string/licenses"
app:title="@string/licenses" /> app:title="@string/licenses" />

View File

@ -58,12 +58,25 @@ const groups = {
var dict0 = {} var dict0 = {}
var dict1 = {} var dict1 = {}
const formatStr = (str)=> str.replace(/(?<!\b\w)\B[A-Z]|,(?!$)/g, match => { const formatStr = (str)=> str.replace(/(?<!\b\w\u00E0-\u00FC)\B[A-Z\u00C0-\u00DC]|,(?!$)/g, match => {
if (match.startsWith(',')) { if (match.startsWith(',')) {
return ', '; return ', ';
} else { } else {
return ' ' + match; return ' ' + match;
}}) }}).replace("ofthe "," of the ").replace("dela ", " de la ").replace("delos ", " de los ").replace("áD","á D")
.replace("Côted'","Côte d'").replace("leof ","le of ").replace("dde ","d de ").replace("iode ","io de ").replace("àde ","à de ")
.replace("yof ","y of ").replace("Andrésy ","Andrés y")
.replace("aand ","a and ").replace("iand ", "i and ").replace("tsand ","ts and ").replace("onand ","on and ").replace("reand ", "re and ")
.replace("odel ","o del ").replace("adel ", "a del ").replace("ndel ","n del ").replace("zdel ","z del ").replace("falde ", "fal de ").replace("casdel ","cas del ")
.replace("odosÓ", "o dos Ó")
.replace("Grandedo ", "Grande do ").replace("Grandede ","Grande de ")
.replace("Santiagode ","Santiago de ").replace("Joséde ","José de ").replace("Pedrode ","Pedro de ")
.replace("andthe "," and the ")
.replace("emunicipality", "e municipality").replace("Villede ", "Ville de ")
.replace("Valledel ","Valle del ").replace("Valde ","Val de ").replace("Îlesdu ","Îles du ")
.replace("sÉ","s É").replace("áO","á O").replace("N C Tof ","NCT of ").replace("N A","NA")
.replace("Nortede ", "Norte de ")
.trim()
const parse0 = (country) => { const parse0 = (country) => {
const filepath = `temp/0/${country}.json` const filepath = `temp/0/${country}.json`

View File

@ -6,6 +6,7 @@ GADM_VERSION="4.1"
GADM_BASEPATH="https://geodata.ucdavis.edu/gadm" GADM_BASEPATH="https://geodata.ucdavis.edu/gadm"
mapshaper="./node_modules/mapshaper/bin/mapshaper" mapshaper="./node_modules/mapshaper/bin/mapshaper"
ATA_URL="https://media.githubusercontent.com/media/wmgeolab/geoBoundaries/905b0baf5f4fb3b9ccf45293647dcacdb2b799d4/releaseData/gbOpen/ATA/ADM0/geoBoundaries-ATA-ADM0_simplified.geojson"
countries=( countries=(
"AFG" "XAD" "ALA" "ALB" "DZA" "ASM" "AND" "AGO" "AIA" "ATG" "ARG" "ARM" "ABW" "AUS" "AUT" "AZE" "AFG" "XAD" "ALA" "ALB" "DZA" "ASM" "AND" "AGO" "AIA" "ATG" "ARG" "ARM" "ABW" "AUS" "AUT" "AZE"
@ -67,7 +68,10 @@ download_1() {
jq '.features[] |= . + {properties: (.properties | .GID_1 = (.GID_0 + "_" + ( jq '.features[] |= . + {properties: (.properties | .GID_1 = (.GID_0 + "_" + (
if .HASC_1 != "NA" then (.HASC_1 | split(".") | .[-1]) if .HASC_1 != "NA" then (.HASC_1 | split(".") | .[-1])
elif .ISO_1 != "NA" then (.ISO_1 | split("-") | .[-1]) elif .ISO_1 != "NA" then (.ISO_1 | split("-") | .[-1])
else (.CC_1) elif .CC_1 != "NA" then (.CC_1)
elif .NAME_1 != "NA" then (.NAME_1)
elif .GID_1 != "NA" then (.GID_1 | split(".") | .[-1])
else .GID_1
end end
)))}' "$output_dir/gadm41_${1}_1.json" > "$output_dir/$1.json.1" )))}' "$output_dir/gadm41_${1}_1.json" > "$output_dir/$1.json.1"
sed -E 's/"[gadm41_]*([A-Z]*)_1"/"\1"/g' "$output_dir/$1.json.1" > "$output_dir/$1.json" sed -E 's/"[gadm41_]*([A-Z]*)_1"/"\1"/g' "$output_dir/$1.json.1" > "$output_dir/$1.json"
@ -76,7 +80,7 @@ download_1() {
toSVG_0() { toSVG_0() {
local input_files=() local input_files=("ATA")
for country in "${countries[@]}" for country in "${countries[@]}"
do do
@ -94,7 +98,7 @@ toSVG_0() {
} }
toSVG_1() { toSVG_1() {
input_files=() input_files=("ATA")
for country in "${countries[@]}" for country in "${countries[@]}"
do do
@ -113,12 +117,12 @@ toSVG_1() {
toSVG_01() { toSVG_01() {
input_files=() input_files=("./temp/1/ATA.json" "./temp/0/ATA.json")
for country in "${countries[@]}" for country in "${countries[@]}"
do do
input_file0="./temp/0/${country}.json"
input_file1="./temp/1/${country}.json" input_file1="./temp/1/${country}.json"
input_file0="./temp/0/${country}.json"
if [ -f "$input_file1" ]; then if [ -f "$input_file1" ]; then
input_files+=("$input_file1") input_files+=("$input_file1")
fi fi
@ -127,8 +131,11 @@ toSVG_01() {
fi fi
done done
"$mapshaper" -i combine-files ${input_files[@]} -proj webmercator -simplify 0.005 weighted keep-shapes resolution=1200x1200 -o ./app/src/main/assets/mercator01.svg svg-data=GID_0,COUNTRY,GID,NAME id-field=GID
"$mapshaper" -i combine-files ${input_files[@]} -proj aeqd +lat_0=90 -simplify 0.005 weighted keep-shapes resolution=1200x1200 -o ./app/src/main/assets/aeqd01.svg svg-data=GID_0,COUNTRY,GID,NAME id-field=GID "$mapshaper" -i combine-files ${input_files[@]} snap -proj eqdc +lat_1=55 +lat_2=60 -simplify 0.005 weighted keep-shapes resolution=1200x1200 -o ./app/src/main/assets/eqdc01.svg svg-data=GID_0,COUNTRY,GID,NAME id-field=GID
"$mapshaper" -i combine-files ${input_files[@]} snap -proj loxim densify -simplify 0.005 weighted keep-shapes resolution=1200x1200 -o ./app/src/main/assets/loxim01.svg svg-data=GID_0,COUNTRY,GID,NAME id-field=GID
"$mapshaper" -i combine-files ${input_files[@]} snap -proj webmercator densify -simplify 0.005 weighted keep-shapes resolution=1200x1200 -o ./app/src/main/assets/webmercator01.svg svg-data=GID_0,COUNTRY,GID,NAME id-field=GID
"$mapshaper" -i combine-files ${input_files[@]} snap -proj aeqd +lat_0=90 densify -simplify 0.005 weighted keep-shapes resolution=1200x1200 -o ./app/src/main/assets/aeqd01.svg svg-data=GID_0,COUNTRY,GID,NAME id-field=GID
} }
do_1() { do_1() {
@ -136,15 +143,17 @@ do_1() {
do do
download_1 "$country" download_1 "$country"
done done
wget -q -O "./temp/1/ATA.json" "$ATA_URL"
} }
do_0() { do_0() {
for country in "${countries[@]}" for country in "${countries[@]}"
do do
download_0 "$country" download_0 "$country"
done done
wget -q -O "./temp/1/ATA.json" "$ATA_URL"
} }
# do_0 do_0
do_1 do_1
# toSVG_0 # toSVG_0
toSVG_1 # toSVG_1
toSVG_01 toSVG_01

5329
yarn.lock

File diff suppressed because it is too large Load Diff