Cleanup and Colors

This commit is contained in:
soraefir 2024-02-15 22:42:54 +01:00
parent 3f7183d056
commit 56b192d43d
Signed by: sora
GPG Key ID: A362EA0491E2EEA0
36 changed files with 474 additions and 193 deletions

View File

@ -1,6 +1,7 @@
plugins { 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.22'
id 'com.mikepenz.aboutlibraries.plugin' version '10.10.0' id 'com.mikepenz.aboutlibraries.plugin' version '10.10.0'
} }
@ -39,12 +40,13 @@ android {
dependencies { dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7' implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.7' implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
implementation 'androidx.core:core-ktx:1.12.0' implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.1.5'

View File

@ -17,7 +17,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.helcel.beendroid.R import net.helcel.beendroid.R
import net.helcel.beendroid.activity.fragment.SettingsFragment import net.helcel.beendroid.activity.fragment.SettingsFragment
import net.helcel.beendroid.helper.Visited
import net.helcel.beendroid.svg.CSSWrapper import net.helcel.beendroid.svg.CSSWrapper
import net.helcel.beendroid.svg.PSVGWrapper import net.helcel.beendroid.svg.PSVGWrapper
@ -76,14 +75,6 @@ class MainActivity : AppCompatActivity() {
}) })
// Restore visited countries
visited = Visited(this).load()
groups = Groups(this).load()
// Wrap lists of countries
psvg = PSVGWrapper(this)
css = CSSWrapper(this,visited!!)
// Populate map from list of countries // Populate map from list of countries
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
@ -91,6 +82,11 @@ class MainActivity : AppCompatActivity() {
photoView.minimumScale = 1f photoView.minimumScale = 1f
photoView.maximumScale = 30f photoView.maximumScale = 30f
loadData(this, Int.MIN_VALUE)
psvg = PSVGWrapper(this)
css = CSSWrapper(this)
refreshMap() refreshMap()
} }

View File

@ -1,6 +1,7 @@
package net.helcel.beendroid.activity package net.helcel.beendroid.activity
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
@ -10,13 +11,13 @@ import com.github.mikephil.charting.data.PieData
import com.github.mikephil.charting.data.PieDataSet import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry import com.github.mikephil.charting.data.PieEntry
import com.github.mikephil.charting.formatter.PercentFormatter import com.github.mikephil.charting.formatter.PercentFormatter
import com.github.mikephil.charting.utils.ColorTemplate
import com.github.mikephil.charting.utils.MPPointF import com.github.mikephil.charting.utils.MPPointF
import net.helcel.beendroid.R import net.helcel.beendroid.R
import net.helcel.beendroid.countries.World import net.helcel.beendroid.countries.World
import net.helcel.beendroid.helper.colorWrapper import net.helcel.beendroid.helper.colorWrapper
import net.helcel.beendroid.helper.createActionBar import net.helcel.beendroid.helper.createActionBar
import net.helcel.beendroid.helper.visited import net.helcel.beendroid.helper.groups
import net.helcel.beendroid.helper.visits
class StatActivity : AppCompatActivity() { class StatActivity : AppCompatActivity() {
@ -62,13 +63,13 @@ class StatActivity : AppCompatActivity() {
private fun bind() { private fun bind() {
val entries = ArrayList<PieEntry>() val entries = ArrayList<PieEntry>()
val VIS_continents = World.WWW.children.groupBy { visited!!.getVisited(it) }.map { Pair(it.key,it.value.map { c-> c.area }.fold(0){acc,i-> acc+i}) } val VIS_continents = World.WWW.children.groupBy { visits?.getVisited(it)?:0 }.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 { visited!!.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 val vis = VIS_country
Log.d("VIS",vis.toString()) Log.d("VIS",vis.toString())
val max = vis.fold(0) {acc, i -> acc+i.second} val max = vis.map{it.second}.fold(0) {acc, i -> acc+i}
vis.forEach { vis.forEach {
entries.add(PieEntry(it.second.toFloat().div(max.toFloat()),it.first.toString())) entries.add(PieEntry(it.second.toFloat().div(max.toFloat()),groups!!.getGroupFromKey(it.first)?.name?:"None"))
} }
val dataSet = PieDataSet(entries, "GG1") val dataSet = PieDataSet(entries, "GG1")
@ -77,22 +78,9 @@ class StatActivity : AppCompatActivity() {
dataSet.iconsOffset = MPPointF(0f, 40f) dataSet.iconsOffset = MPPointF(0f, 40f)
dataSet.selectionShift = 5f dataSet.selectionShift = 5f
// add a lot of colors
val colors = ArrayList<Int>()
for (c in ColorTemplate.VORDIPLOM_COLORS) colors.add(c) dataSet.setDrawIcons(true)
dataSet.colors = vis.map{ (groups!!.getGroupFromKey(it.first)?.color?:ColorDrawable(Color.WHITE)).color }.toList()
for (c in ColorTemplate.JOYFUL_COLORS) colors.add(c)
for (c in ColorTemplate.COLORFUL_COLORS) colors.add(c)
for (c in ColorTemplate.LIBERTY_COLORS) colors.add(c)
for (c in ColorTemplate.PASTEL_COLORS) colors.add(c)
colors.add(ColorTemplate.getHoloBlue())
dataSet.colors = colors
val data = PieData(dataSet) val data = PieData(dataSet)
data.setDrawValues(false) data.setDrawValues(false)

View File

@ -1,25 +1,29 @@
package net.helcel.beendroid.activity.adapter package net.helcel.beendroid.activity.adapter
import android.content.Context import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.Typeface import android.graphics.Typeface
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.fragment.app.FragmentActivity
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.checkbox.MaterialCheckBox import com.google.android.material.checkbox.MaterialCheckBox
import net.helcel.beendroid.R import net.helcel.beendroid.R
import net.helcel.beendroid.activity.fragment.EditPlaceColorFragment
import net.helcel.beendroid.countries.GeoLoc import net.helcel.beendroid.countries.GeoLoc
import net.helcel.beendroid.helper.colorWrapper import net.helcel.beendroid.helper.colorWrapper
import net.helcel.beendroid.helper.visited import net.helcel.beendroid.helper.groups
import java.util.* import net.helcel.beendroid.helper.saveData
import net.helcel.beendroid.helper.selected_geoloc
import net.helcel.beendroid.helper.selected_group
import net.helcel.beendroid.helper.visits
class GeolocListAdapter( class GeolocListAdapter(
private val ctx: Context, l: List<GeoLoc>) : RecyclerView.Adapter<GeolocListAdapter.FoldingListViewHolder>() { private val ctx: FragmentActivity, l: List<GeoLoc>) : RecyclerView.Adapter<GeolocListAdapter.FoldingListViewHolder>() {
private val cg : MutableMap<GeoLoc,Boolean> = l.sortedBy { it.fullName }.fold(LinkedHashMap<GeoLoc,Boolean>()) { acc, e -> private val cg : MutableMap<GeoLoc,Boolean> = l.sortedBy { it.fullName }.fold(LinkedHashMap()) { acc, e ->
acc[e] = false acc[e] = false
acc acc
} }
@ -35,22 +39,20 @@ class GeolocListAdapter(
val el = cg.toList()[position] val el = cg.toList()[position]
holder.bind(el) holder.bind(el)
holder.addListeners( { holder.addListeners(el) {
if (!el.first.isEnd) { if (!el.first.isEnd) {
cg[el.first] = !el.second cg[el.first] = !el.second
notifyItemChanged(position) notifyItemChanged(position)
} }
!el.first.isEnd !el.first.isEnd
}, { }
visited!!.setVisited(el.first, it)
})
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return cg.size return cg.size
} }
class FoldingListViewHolder(private val ctx: Context, itemView: View) : RecyclerView.ViewHolder(itemView) { class FoldingListViewHolder(private val ctx: FragmentActivity, itemView: View) : RecyclerView.ViewHolder(itemView) {
private val textView: TextView = itemView.findViewById(R.id.textView) private val textView: TextView = itemView.findViewById(R.id.textView)
private val progressView: TextView = itemView.findViewById(R.id.name) private val progressView: TextView = itemView.findViewById(R.id.name)
private val checkBox: MaterialCheckBox = itemView.findViewById(R.id.checkBox) private val checkBox: MaterialCheckBox = itemView.findViewById(R.id.checkBox)
@ -72,7 +74,7 @@ class GeolocListAdapter(
textView.isActivated = false textView.isActivated = false
}else { }else {
textView.setTypeface(null, Typeface.BOLD) textView.setTypeface(null, Typeface.BOLD)
progressView.text = ctx.getString(R.string.rate,(el.first.children.map { visited!!.getVisited(it)>0 }.count { it }),el.first.children.size) progressView.text = ctx.getString(R.string.rate,(el.first.children.map { visits!!.getVisited(it)>0 }.count { it }),el.first.children.size)
textView.background = colorWrapper(ctx, android.R.attr.panelColorBackground) textView.background = colorWrapper(ctx, android.R.attr.panelColorBackground)
textView.background.alpha = 128 textView.background.alpha = 128
@ -80,18 +82,44 @@ class GeolocListAdapter(
list.adapter = GeolocListAdapter(ctx, el.first.children) list.adapter = GeolocListAdapter(ctx, el.first.children)
textView.parent.parent.requestChildFocus(textView, textView) textView.parent.parent.requestChildFocus(textView, textView)
} }
checkBox.checkedState = refreshCheck(el.first)
if (visited!!.getVisited(el.first)>0) MaterialCheckBox.STATE_CHECKED
else if (el.first.children.any { visited!!.getVisited(it)>0 }) MaterialCheckBox.STATE_INDETERMINATE
else MaterialCheckBox.STATE_UNCHECKED
} }
fun addListeners(expandLambda: ()->Boolean, visitedLambda: (Int)->Unit) { fun addListeners(el: Pair<GeoLoc, Boolean>, expandLambda: () -> Boolean) {
textView.setOnClickListener { expandLambda() } textView.setOnClickListener { expandLambda() }
checkBox.addOnCheckedStateChangedListener { _, e -> checkBox.setOnClickListener {
visitedLambda( if(e == MaterialCheckBox.STATE_CHECKED) 1 else 0) val dialogFragment = EditPlaceColorFragment(this)
selected_geoloc = el.first
selected_group = null
dialogFragment.show(ctx.supportFragmentManager, "AddColorDialogFragment")
} }
} }
fun onColorDialogDismiss(clear: Boolean) {
if(clear){
visits!!.setVisited(selected_geoloc!!,0)
saveData()
}
if(selected_group!=null && selected_geoloc!=null) {
visits!!.setVisited(selected_geoloc!!, selected_group!!.key)
saveData()
}
selected_geoloc?.let { refreshCheck(it) }
selected_geoloc = null
selected_group = null
}
private fun refreshCheck(geoLoc: GeoLoc){
val col = groups!!.getGroupFromKey(visits!!.getVisited(geoLoc))?.color?.color?:Color.WHITE
checkBox.checkedState =
if (visits!!.getVisited(geoLoc)!=0) MaterialCheckBox.STATE_CHECKED
else if (geoLoc.children.any { visits!!.getVisited(it)!=0 }) MaterialCheckBox.STATE_INDETERMINATE
else MaterialCheckBox.STATE_UNCHECKED
checkBox.buttonTintList = ColorStateList(arrayOf(
intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)),
intArrayOf(col, col))
}
} }
} }

View File

@ -1,22 +1,24 @@
package net.helcel.beendroid.activity.adapter package net.helcel.beendroid.activity.adapter
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import net.helcel.beendroid.R import net.helcel.beendroid.R
import net.helcel.beendroid.activity.fragment.EditGroupAddFragment import net.helcel.beendroid.activity.fragment.EditGroupAddFragment
import net.helcel.beendroid.helper.Groups
import net.helcel.beendroid.helper.getContrastColor import net.helcel.beendroid.helper.getContrastColor
import net.helcel.beendroid.helper.groups import net.helcel.beendroid.helper.groups
import net.helcel.beendroid.helper.selected_group
class GroupListAdapter(val activity: FragmentActivity) : RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>() { class GroupListAdapter(private val activity: FragmentActivity, private val selectDialog: DialogFragment?) : RecyclerView.Adapter<GroupListAdapter.GroupViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : GroupViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : GroupViewHolder {
val view : View = LayoutInflater.from(parent.context).inflate(R.layout.item_list_group, parent, false) val view : View = LayoutInflater.from(parent.context).inflate(R.layout.item_list_group, parent, false)
return GroupViewHolder(view, activity) return GroupViewHolder(view, activity, selectDialog)
} }
override fun onBindViewHolder(holder: GroupViewHolder, pos: Int) { override fun onBindViewHolder(holder: GroupViewHolder, pos: Int) {
@ -27,21 +29,29 @@ class GroupListAdapter(val activity: FragmentActivity) : RecyclerView.Adapter<Gr
return groups!!.size() return groups!!.size()
} }
class GroupViewHolder(itemView: View, val activity: FragmentActivity) : RecyclerView.ViewHolder(itemView) { class GroupViewHolder(itemView: View, private val activity: FragmentActivity, private val selectDialog: DialogFragment?) : RecyclerView.ViewHolder(itemView) {
private val color: Button = itemView.findViewById(R.id.group_color) private val color: Button = itemView.findViewById(R.id.group_color)
fun bind(entry: Pair<Int, Pair<String, ColorDrawable>>) { fun bind(entry: Pair<Int, Groups.Group>) {
color.text = entry.second.first color.text = entry.second.name
color.setBackgroundColor(entry.second.second.color) color.setBackgroundColor(entry.second.color.color)
color.setTextColor(getContrastColor(entry.second.second.color)) color.setTextColor(getContrastColor(entry.second.color.color))
color.setOnClickListener { color.setOnClickListener {
if(selectDialog==null) {
val dialogFragment = EditGroupAddFragment(entry.first) { val dialogFragment = EditGroupAddFragment(entry.first) {
val newEntry = groups!!.getGroupFromKey(entry.first)!! val newEntry = groups!!.getGroupFromKey(entry.first)!!
color.text = newEntry.first color.text = newEntry.name
color.setBackgroundColor(newEntry.second.color) color.setBackgroundColor(newEntry.color.color)
color.setTextColor(getContrastColor(newEntry.second.color)) color.setTextColor(getContrastColor(newEntry.color.color))
}
dialogFragment.show(
activity.supportFragmentManager,
"AddColorDialogFragment"
)
}else{
selected_group = entry.second
selectDialog.dismiss()
} }
dialogFragment.show(activity.supportFragmentManager, "AddColorDialogFragment")
} }
} }
} }

View File

@ -5,18 +5,34 @@ import android.content.DialogInterface
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.google.android.material.slider.Slider
import com.google.android.material.textfield.TextInputEditText
import net.helcel.beendroid.R import net.helcel.beendroid.R
import net.helcel.beendroid.helper.Groups
import net.helcel.beendroid.helper.colorToHex6 import net.helcel.beendroid.helper.colorToHex6
import net.helcel.beendroid.helper.groups import net.helcel.beendroid.helper.groups
import net.helcel.beendroid.helper.saveData
import java.lang.Exception
class EditGroupAddFragment(private val key: Int =0, val onAddCb : (Int)->Unit) : DialogFragment() { class EditGroupAddFragment(private val key: Int =0, val onAddCb : (Int)->Unit) : DialogFragment() {
private var colorNameEditText: EditText? = null private lateinit var colorNameEditText: TextInputEditText
private var colorEditText: EditText? = null private lateinit var colorEditText: TextInputEditText
private lateinit var colorView : View
private lateinit var colorEditR : Slider
private lateinit var colorEditG : Slider
private lateinit var colorEditB : Slider
private val grp = groups!!.getGroupFromKey(key) private val grp = groups!!.getGroupFromKey(key)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder( val builder = AlertDialog.Builder(
@ -27,18 +43,28 @@ class EditGroupAddFragment(private val key: Int =0, val onAddCb : (Int)->Unit) :
colorNameEditText = view.findViewById(R.id.group_name) colorNameEditText = view.findViewById(R.id.group_name)
colorEditText = view.findViewById(R.id.group_color) colorEditText = view.findViewById(R.id.group_color)
colorView = view.findViewById(R.id.colorView)
colorEditR = view.findViewById(R.id.colorR)
colorEditG = view.findViewById(R.id.colorG)
colorEditB = view.findViewById(R.id.colorB)
if(grp!=null){ setupSlider(colorEditR,(grp?.color?.color?.red ?: 0)/ 255F)
view.findViewById<EditText>(R.id.group_name).setText(grp.first) setupSlider(colorEditG,(grp?.color?.color?.green ?: 0)/ 255F)
view.findViewById<EditText>(R.id.group_color).setText(colorToHex6(grp.second)) setupSlider(colorEditB,(grp?.color?.color?.blue ?: 0)/ 255F)
}
setupText(colorEditText,grp)
colorView.background = ColorDrawable(grp?.color?.color ?: 0)
colorNameEditText.setText(grp?.name ?: "")
builder.setView(view) builder.setView(view)
.setTitle("Add Color") .setPositiveButton("Ok") { _: DialogInterface?, _: Int ->
.setPositiveButton("Add") { _: DialogInterface?, _: Int -> val name = colorNameEditText.text.toString()
val name = colorNameEditText!!.text.toString() val color = colorEditText.text.toString()
val color = colorEditText!!.text.toString()
val key = (if (key!=0) key else groups!!.genKey()) val key = (if (key!=0) key else groups!!.genKey())
groups!!.setGroup(key,name, ColorDrawable(Color.parseColor(color))) groups!!.setGroup(key,name, ColorDrawable(Color.parseColor("#$color")))
saveData()
onAddCb(key) onAddCb(key)
} }
.setNegativeButton( .setNegativeButton(
@ -46,4 +72,65 @@ class EditGroupAddFragment(private val key: Int =0, val onAddCb : (Int)->Unit) :
) { dialog: DialogInterface, _: Int -> dialog.cancel() } ) { dialog: DialogInterface, _: Int -> dialog.cancel() }
return builder.create() return builder.create()
} }
private fun setupText(s: TextInputEditText, grp: Groups.Group?) {
s.setText( colorToHex6(ColorDrawable(grp?.color?.color ?: 0)).substring(1))
s.addTextChangedListener(EditTextListener(colorEditR, colorEditG, colorEditB, colorEditText, colorView))
}
private fun setupSlider(s: Slider, v: Float){
s.valueFrom = 0F
s.valueTo = 1F
s.value = v
s.addOnChangeListener(SliderOnChangeListener( colorEditR, colorEditG, colorEditB,colorEditText, colorView))
}
}
private class EditTextListener(
private val colorEditR: Slider,
private val colorEditG: Slider,
private val colorEditB: Slider,
private val colorEditText: TextInputEditText,
private val colorView: View
): TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
val col : Color
try{
col = Color.valueOf(Color.parseColor("#${colorEditText.text}"))
}catch (e:Exception){
return
}
colorEditR.value = col.red()
colorEditG.value = col.green()
colorEditB.value = col.blue()
colorView.background = ColorDrawable(col.toArgb())
}
}
private class SliderOnChangeListener(
private val colorEditR: Slider,
private val colorEditG: Slider,
private val colorEditB: Slider,
private val colorEditText: TextInputEditText,
private val colorView: View
): Slider.OnChangeListener {
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
val rgb = ColorDrawable(Color.argb(1F,colorEditR.value, colorEditG.value, colorEditB.value))
colorEditText.setText(colorToHex6(rgb).substring(1))
colorView.background = rgb
}
} }

View File

@ -23,13 +23,12 @@ class EditGroupFragment : Fragment() {
): View { ): View {
_binding = FragmentEditGroupsBinding.inflate(inflater, container, false) _binding = FragmentEditGroupsBinding.inflate(inflater, container, false)
listadapt = GroupListAdapter(requireActivity()) listadapt = GroupListAdapter(requireActivity(),null)
binding.addGroup.setOnClickListener { binding.addGroup.setOnClickListener {
val dialogFragment = EditGroupAddFragment { val dialogFragment = EditGroupAddFragment {
listadapt.notifyItemInserted(groups!!.findGroupPos(it)) listadapt.notifyItemInserted(groups!!.findGroupPos(it))
} }
dialogFragment.show(requireActivity().supportFragmentManager, "AddColorDialogFragment") dialogFragment.show(requireActivity().supportFragmentManager, "AddColorDialogFragment")
} }
binding.list.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false) binding.list.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)

View File

@ -0,0 +1,42 @@
package net.helcel.beendroid.activity.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import net.helcel.beendroid.R
import net.helcel.beendroid.activity.adapter.GeolocListAdapter
import net.helcel.beendroid.activity.adapter.GroupListAdapter
class EditPlaceColorFragment(private val parent: GeolocListAdapter.FoldingListViewHolder) : DialogFragment() {
private lateinit var listAdapt : GroupListAdapter
private lateinit var list : RecyclerView
private var clear : Boolean = false
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(
requireActivity()
)
val inflater = requireActivity().layoutInflater
val view: View = inflater.inflate(R.layout.fragment_edit_places_colors, null)
val dialog = builder.setView(view).setNegativeButton("Clear") { dialogInterface: DialogInterface, i: Int -> clear = true }
.create()
listAdapt = GroupListAdapter(requireActivity(),this)
list = view.findViewById(R.id.groups_color)!!
list.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
list.adapter = listAdapt
return dialog
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
parent.onColorDialogDismiss(clear)
}
}

View File

@ -23,7 +23,7 @@ class EditPlaceFragment : Fragment() {
_binding = FragmentEditPlacesBinding.inflate(inflater, container, false) _binding = FragmentEditPlacesBinding.inflate(inflater, container, false)
binding.list.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false) binding.list.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
binding.list.adapter = GeolocListAdapter(requireContext(), World.WWW.children) binding.list.adapter = GeolocListAdapter(requireActivity(), World.WWW.children)
return binding.root return binding.root
} }

View File

@ -3,6 +3,7 @@ package net.helcel.beendroid.countries
enum class LocType { enum class LocType {
WORLD, GROUP, CUSTOM_GROUP, COUNTRY, STATE; WORLD, GROUP, CUSTOM_GROUP, COUNTRY, STATE;
} }
interface GeoLoc { interface GeoLoc {
val code : String val code : String
val fullName : String val fullName : String

View File

@ -1,5 +1,36 @@
package net.helcel.beendroid.helper package net.helcel.beendroid.helper
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import net.helcel.beendroid.countries.GeoLoc
var visited : Visited? = null var visits : Visits? = null
var groups : Groups? = null var groups : Groups? = null
var selected_group : Groups.Group? = null
var selected_geoloc: GeoLoc? = null
val groupsSerial = Groups.GroupsSerializer()
val visitsSerial = Visits.VisitsSerializer()
private var sharedPreferences: SharedPreferences? = null
fun loadData(ctx: Context, id:Int) {
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(ctx)
val groupsString = sharedPreferences!!.getString("groups_$id",null)
val visitsString = sharedPreferences!!.getString("visits_$id",null)
groups = if(!groupsString.isNullOrEmpty()) groupsSerial.readFrom(groupsString.byteInputStream()) else groupsSerial.defaultValue
visits = if(!visitsString.isNullOrEmpty()) visitsSerial.readFrom(visitsString.byteInputStream()) else visitsSerial.defaultValue
}
fun saveData() {
if(groups!!.id != visits!!.id) return
val id = groups!!.id
val editor = sharedPreferences!!.edit()
editor.putString("groups_$id", groupsSerial.writeTo(groups!!))
editor.putString("visits_$id", visitsSerial.writeTo(visits!!))
editor.apply()
}

View File

@ -1,35 +1,24 @@
package net.helcel.beendroid.helper package net.helcel.beendroid.helper
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.json.Json
import java.io.InputStream
import kotlin.random.Random import kotlin.random.Random
class Groups(ctx: Context) { private const val randSeed = 0
private val randSeed = 0 private val rnd = Random(randSeed)
private val rnd = Random(randSeed) @Serializable
private var grps: MutableMap<Int,Pair<String, ColorDrawable>> = HashMap() class Groups(val id: Int, private val grps: HashMap<Int,Group>) {
private val pref = ctx.getSharedPreferences("Groups", Context.MODE_PRIVATE)
private val editor = pref.edit()
fun load(): Groups {
pref.all.keys.filter { !it.endsWith("_color") }.forEach {
grps[it.toInt()] = Pair(pref.getString(it, "")!!,
ColorDrawable(pref.getInt(it+"_color", Color.WHITE)))
}
editor.apply()
return this
}
fun setGroup(key: Int, name: String, col: ColorDrawable) { fun setGroup(key: Int, name: String, col: ColorDrawable) {
grps[key] = Pair(name,col) grps[key] = Group(key,name,col)
editor.putString(key.toString(), name)
editor.putInt(key.toString()+"_color", col.color)
editor.apply()
} }
fun getGroupFromKey(key: Int): Pair<String,ColorDrawable>? { fun getGroupFromKey(key: Int): Group? {
return grps.getOrDefault(key,null) return grps.getOrDefault(key,null)
} }
@ -43,7 +32,7 @@ class Groups(ctx: Context) {
return grps.size return grps.size
} }
fun getGroupFromPos(pos: Int): Pair<Int,Pair<String,ColorDrawable>> { fun getGroupFromPos(pos: Int): Pair<Int,Group> {
val key = grps.keys.toList()[pos] val key = grps.keys.toList()[pos]
return Pair(key,getGroupFromKey(key)!!) return Pair(key,getGroupFromKey(key)!!)
} }
@ -52,4 +41,23 @@ class Groups(ctx: Context) {
return grps.keys.toList().indexOf(key) return grps.keys.toList().indexOf(key)
} }
@Serializable
class Group(val key: Int, val name: String, @Serializable(with = ColorDrawableSerializer::class) val color: ColorDrawable)
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Groups::class)
class GroupsSerializer{
val defaultValue: Groups
get() = Groups(Int.MIN_VALUE,hashMapOf())
fun readFrom(input: InputStream): Groups {
return Json.decodeFromString(serializer(),input.readBytes().decodeToString())
}
fun writeTo(t: Groups): String {
return Json.encodeToString(serializer(),t).encodeToByteArray().decodeToString()
}
}
} }

View File

@ -0,0 +1,20 @@
package net.helcel.beendroid.helper
import android.graphics.drawable.ColorDrawable
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
object ColorDrawableSerializer : KSerializer<ColorDrawable> {
override val descriptor = PrimitiveSerialDescriptor("ColorDrawable", PrimitiveKind.INT)
override fun deserialize(decoder: Decoder): ColorDrawable {
return ColorDrawable(decoder.decodeInt())
}
override fun serialize(encoder: Encoder, value: ColorDrawable) {
encoder.encodeInt(value.color)
}
}

View File

@ -1,52 +0,0 @@
package net.helcel.beendroid.helper
import android.content.Context
import net.helcel.beendroid.countries.Country
import net.helcel.beendroid.countries.GeoLoc
import net.helcel.beendroid.countries.Group
import net.helcel.beendroid.countries.State
import java.lang.ClassCastException
class Visited(ctx: Context) {
private var locs: MutableMap<GeoLoc, Int> = HashMap()
private val pref = ctx.getSharedPreferences("Visited", Context.MODE_PRIVATE)
private val editor = pref.edit()
fun load(): Visited {
Group.entries.forEach {
try {
locs[it] = pref.getInt(it.code, 0)
}catch (e:ClassCastException){
locs[it] = if (pref.getBoolean(it.code, false)) 1 else 0
}
}
Country.entries.forEach {
try {
locs[it] = pref.getInt(it.code, 0)
}catch (e:ClassCastException){
locs[it] = if (pref.getBoolean(it.code, false)) 1 else 0
}
}
State.entries.forEach {
try {
locs[it] = pref.getInt(it.code, 0)
}catch (e:ClassCastException){
locs[it] = if (pref.getBoolean(it.code, false)) 1 else 0
}
}
editor.apply()
return this
}
fun setVisited(key: GeoLoc, b: Int) {
locs[key] = b
editor.putInt(key.code, b)
editor.apply()
}
fun getVisited(key: GeoLoc): Int {
return locs.getOrDefault(key,0)
}
}

View File

@ -0,0 +1,38 @@
package net.helcel.beendroid.helper
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.json.Json
import net.helcel.beendroid.countries.GeoLoc
import java.io.InputStream
@Serializable
class Visits(val id: Int, private val locs: HashMap<String,Int>) {
fun setVisited(key: GeoLoc, b: Int) {
locs[key.code] = b
}
fun getVisited(key: GeoLoc): Int {
return locs.getOrDefault(key.code,0)
}
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Visits::class)
class VisitsSerializer {
val defaultValue: Visits
get() = Visits(Int.MIN_VALUE,hashMapOf())
fun readFrom(input: InputStream): Visits {
return Json.decodeFromString(serializer(),input.readBytes().decodeToString())
}
fun writeTo(t: Visits): String {
return Json.encodeToString(serializer(),t).encodeToByteArray().decodeToString()
}
}
}

View File

@ -1,26 +1,25 @@
package net.helcel.beendroid.svg package net.helcel.beendroid.svg
import android.content.Context import android.content.Context
import net.helcel.beendroid.helper.Visited
import net.helcel.beendroid.countries.World import net.helcel.beendroid.countries.World
import net.helcel.beendroid.helper.colorToHex6 import net.helcel.beendroid.helper.colorToHex6
import net.helcel.beendroid.helper.colorWrapper import net.helcel.beendroid.helper.colorWrapper
import net.helcel.beendroid.helper.groups
import net.helcel.beendroid.helper.visits
class CSSWrapper(ctx: Context, private val visited: Visited) { class CSSWrapper(ctx: Context) {
private val visitedColor = colorToHex6(colorWrapper(ctx,android.R.attr.colorPrimary))
fun get() : String { fun get() : String {
return listOf(World.WWW.children return listOf(World.WWW.children
.filter { visited.getVisited(it)>0} .filter { visits!!.getVisited(it)!=0}
.map { ".${it.code}{fill:$visitedColor;}"} .map { ".${it.code}{fill:${colorToHex6(groups!!.getGroupFromKey(visits!!.getVisited(it))!!.color)};}"}
.fold(""){acc, s-> acc + s}, .fold(""){acc, s-> acc + s},
World.WWW.children World.WWW.children
.filter { visited.getVisited(it)==0 } .filter { visits!!.getVisited(it)==0 }
.map { cg -> cg.children .map { cg -> cg.children
.filter { visited.getVisited(it)>0 } .filter { visits!!.getVisited(it)!=0 }
.map { ".${it.code}{fill:$visitedColor;}"} .map { ".${it.code}{fill:${colorToHex6(groups!!.getGroupFromKey(visits!!.getVisited(it))!!.color)};}"}
.fold(""){acc, s-> acc + s} .fold(""){acc, s-> acc + s}
}.fold(""){acc,s->acc+s}, }.fold(""){acc,s->acc+s},
).fold(""){acc,s-> acc+s} ).fold(""){acc,s-> acc+s}

View File

@ -23,10 +23,6 @@ class PSVGWrapper(ctx: Context) {
build() build()
} }
fun level(el: Country, level: Level){
cm[el]?.changeLevel(level)
}
private fun build(){ private fun build(){
fm = World.WWW.children.map { gr -> fm = World.WWW.children.map { gr ->
gr.children.map {c -> gr.children.map {c ->

View File

@ -5,7 +5,7 @@
android:viewportHeight="1600"> android:viewportHeight="1600">
<path <path
android:fillColor="?attr/colorPrimary" android:fillColor="@color/blue"
android:fillType="nonZero" android:fillType="nonZero"
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: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:strokeWidth="1" android:strokeWidth="1"

View File

@ -1,22 +1,87 @@
<?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"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:padding="16dp">
<EditText <com.google.android.material.textfield.TextInputEditText
android:id="@+id/group_name" android:id="@+id/group_name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/name" android:hint="@string/name"
android:inputType="text" /> android:inputType="text"
android:autofillHints="" />
<EditText <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/group_color"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/colorView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/colorR"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="?attr/background"/>
<com.google.android.material.slider.Slider
android:id="@+id/colorR"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/colorG"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/colorView"
app:layout_constraintTop_toTopOf="parent"
app:thumbColor="@color/red"
app:trackColorActive="@color/red" />
<com.google.android.material.slider.Slider
android:id="@+id/colorG"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:foregroundTint="#FF0000"
app:layout_constraintBottom_toTopOf="@id/colorB"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/colorView"
app:layout_constraintTop_toBottomOf="@id/colorR"
app:thumbColor="@color/green"
app:trackColorActive="@color/green" />
<com.google.android.material.slider.Slider
android:id="@+id/colorB"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/colorView"
app:layout_constraintTop_toBottomOf="@id/colorG"
app:thumbColor="@color/blue"
app:trackColorActive="@color/blue" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@id/group_color"
android:text="@string/hashtag"/>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/group_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autofillHints=""
android:hint="@string/color_rrggbb" android:hint="@string/color_rrggbb"
android:inputType="text" /> android:inputType="text"
android:maxLength="6" />
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/groups_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" /> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground" /> <monochrome android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon> </adaptive-icon>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<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

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -3,6 +3,16 @@
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="darkgray">#FF0C1D2E</color> <color name="darkgray">#FF0C1D2E</color>
<color name="lightgray">#FF93A9BE</color> <color name="lightgray">#FF93A9BE</color>
<color name="blue">#FF3193F5</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<color name="orange">#F59331</color>
<color name="yellow">#F5F531</color>
<color name="green">#93F531</color>
<color name="turquoise">#31F593</color>
<color name="blue">#3193F5</color>
<color name="purple">#9331F5</color>
<color name="pink">#F53193</color>
<color name="red">#F53131</color>
</resources> </resources>

View File

@ -21,5 +21,5 @@
<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="color_rrggbb">Color (#RRGGBB)</string> <string name="color_rrggbb">RRGGBB</string>
</resources> </resources>

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="hashtag">#</string>
</resources> </resources>