diff --git a/ffc/src/main/kotlin/ffc/android/Color.kt b/ffc/src/main/kotlin/ffc/android/Color.kt new file mode 100644 index 00000000..5f9b0ead --- /dev/null +++ b/ffc/src/main/kotlin/ffc/android/Color.kt @@ -0,0 +1,9 @@ +package ffc.android + +import android.content.Context +import android.support.annotation.ColorRes +import android.support.v4.content.ContextCompat +import android.view.View + +fun Context.color(@ColorRes resId: Int) = ContextCompat.getColor(this, resId) +fun View.color(@ColorRes resId: Int) = ContextCompat.getColor(context, resId) diff --git a/ffc/src/main/kotlin/ffc/android/TextView.kt b/ffc/src/main/kotlin/ffc/android/TextView.kt index 50d018b9..3b339576 100644 --- a/ffc/src/main/kotlin/ffc/android/TextView.kt +++ b/ffc/src/main/kotlin/ffc/android/TextView.kt @@ -1,18 +1,26 @@ -/* - * Copyright (c) 2019 NECTEC - * National Electronics and Computer Technology Center, Thailand +/** + * MIT License * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright (c) 2018 Piruin Panichphol * - * http://www.apache.org/licenses/LICENSE-2.0 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ @file:Suppress("DEPRECATION") @@ -22,6 +30,8 @@ package ffc.android import android.graphics.drawable.Drawable import android.text.Editable import android.text.TextWatcher +import android.os.Build.VERSION +import android.os.Build.VERSION_CODES import android.widget.TextView fun TextView.getDouble(default: Double? = null): Double? { @@ -69,6 +79,16 @@ private fun TextView.compoundDrawablesRelativeWithIntrinsicBounds( setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom) } +var TextView.textAppearance: Int + get() = throw IllegalAccessException("you can't get textAppearance ") + set(textAppearance) { + if (VERSION.SDK_INT >= VERSION_CODES.M) { + setTextAppearance(textAppearance) + } else { + setTextAppearance(context, textAppearance) + } + } + class TextWatcherDsl : TextWatcher { private var afterChanged: ((Editable?) -> Unit)? = null private var beforeChanged: ((s: CharSequence?, start: Int, count: Int, after: Int) -> Unit)? = null diff --git a/ffc/src/main/kotlin/ffc/app/MainActivity.kt b/ffc/src/main/kotlin/ffc/app/MainActivity.kt index be2aed26..897fabc6 100644 --- a/ffc/src/main/kotlin/ffc/app/MainActivity.kt +++ b/ffc/src/main/kotlin/ffc/app/MainActivity.kt @@ -37,6 +37,7 @@ import ffc.android.setTransition import ffc.android.viewModel import ffc.app.auth.auth import ffc.app.location.GeoMapsFragment +import ffc.app.location.GeoMapsInfoSheet import ffc.app.location.housesOf import ffc.app.search.SearchActivity import ffc.app.setting.AboutActivity @@ -46,7 +47,6 @@ import kotlinx.android.synthetic.main.activity_main.navView import kotlinx.android.synthetic.main.activity_main_content.addLocationButton import kotlinx.android.synthetic.main.activity_main_content.searchButton import kotlinx.android.synthetic.main.activity_main_content.toolbar -import kotlinx.android.synthetic.main.activity_main_content.versionView import org.jetbrains.anko.browse import org.jetbrains.anko.dimen import org.jetbrains.anko.find @@ -75,7 +75,6 @@ class MainActivity : FamilyFolderActivity(), NavigationView.OnNavigationItemSele } setupNavigationDrawer() - versionView.text = BuildConfig.VERSION_NAME with(geoMapsFragment) { setPaddingTop(dimen(R.dimen.maps_padding_top)) } supportFragmentManager @@ -87,6 +86,8 @@ class MainActivity : FamilyFolderActivity(), NavigationView.OnNavigationItemSele observe(viewModel.houseNoLocation) { if (it == true) addLocationButton.show() else addLocationButton.hide() } + + GeoMapsInfoSheet(this, geoMapsFragment) } private fun setupNavigationDrawer() { diff --git a/ffc/src/main/kotlin/ffc/app/location/BaseMapsFragment.kt b/ffc/src/main/kotlin/ffc/app/location/BaseMapsFragment.kt new file mode 100644 index 00000000..b3d4b95b --- /dev/null +++ b/ffc/src/main/kotlin/ffc/app/location/BaseMapsFragment.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019 NECTEC + * National Electronics and Computer Technology Center, Thailand + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ffc.app.location + +import android.os.Bundle +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.sembozdemir.permissionskt.handlePermissionsResult +import ffc.android.gone +import ffc.app.familyFolderActivity +import th.or.nectec.marlo.MarloFragment + +open class BaseMapsFragment : MarloFragment() { + + private val org by lazy { familyFolderActivity.org } + internal val preference by lazy { GeoPreferences(context!!, org) } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + preference.lastCameraPosition?.let { setStartLocation(it) } + viewFinder.gone() + hideToolsMenu() + } + + private fun setStartLocation(lastPosition: CameraPosition?) { + if (lastPosition != null) { + setStartLocation(lastPosition.target, lastPosition.zoom) + } else { + setStartLocation(LatLng(13.76498, 100.538335), 5.0f) + setStartAtCurrentLocation(true) + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + activity!!.handlePermissionsResult(requestCode, permissions, grantResults) + } + + override fun onPause() { + super.onPause() + googleMap?.cameraPosition?.let { preference.lastCameraPosition = it } + } + + override fun onMapReady(googleMap: GoogleMap?) { + super.onMapReady(googleMap) + askMyLocationPermission() + } + + override fun showToolsMenu() { + //do nothing + } + + override fun undo() = true + + override fun hideToolsMenu() { + //do nothing + } + + override fun mark(markPoint: LatLng?) { + //do nothing + } +} diff --git a/ffc/src/main/kotlin/ffc/app/location/GeoMapsFragment.kt b/ffc/src/main/kotlin/ffc/app/location/GeoMapsFragment.kt index 504730ed..000613d2 100644 --- a/ffc/src/main/kotlin/ffc/app/location/GeoMapsFragment.kt +++ b/ffc/src/main/kotlin/ffc/app/location/GeoMapsFragment.kt @@ -20,39 +20,45 @@ package ffc.app.location import android.app.Activity import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.ViewModel +import android.content.Context import android.content.Intent import android.os.Bundle +import android.support.annotation.ColorInt import android.support.annotation.DrawableRes import android.support.design.widget.FloatingActionButton import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.model.BitmapDescriptor import com.google.android.gms.maps.model.BitmapDescriptorFactory -import com.google.android.gms.maps.model.CameraPosition -import com.google.android.gms.maps.model.LatLng +import com.google.maps.android.data.geojson.GeoJsonFeature import com.google.maps.android.data.geojson.GeoJsonLayer import com.google.maps.android.data.geojson.GeoJsonPointStyle -import com.sembozdemir.permissionskt.handlePermissionsResult import ffc.android.drawable -import ffc.android.gone import ffc.android.observe import ffc.android.rawAs import ffc.android.sceneTransition +import ffc.android.tint import ffc.android.toBitmap import ffc.android.viewModel import ffc.app.R import ffc.app.dev import ffc.app.familyFolderActivity +import ffc.app.location.GeoMapsInfo.Disability +import ffc.app.location.GeoMapsInfo.ELDER import ffc.app.util.alert.handle +import ffc.app.util.forEachChunk +import ffc.app.util.md5 import ffc.entity.gson.toJson import ffc.entity.place.House import me.piruin.geok.geometry.FeatureCollection import me.piruin.geok.geometry.Point -import org.jetbrains.anko.doAsyncResult +import org.jetbrains.anko.doAsync import org.jetbrains.anko.find import org.jetbrains.anko.support.v4.intentFor +import org.jetbrains.anko.support.v4.onUiThread import org.json.JSONObject -import th.or.nectec.marlo.PointMarloFragment +import timber.log.Timber -class GeoMapsFragment : PointMarloFragment() { +class GeoMapsFragment : BaseMapsFragment() { val REQ_ADD_LOCATION = 1032 @@ -60,17 +66,15 @@ class GeoMapsFragment : PointMarloFragment() { private var addLocationButton: FloatingActionButton? = null private val viewModel by lazy { viewModel() } - private val preference by lazy { GeoPreferences(context!!, org) } - private val org by lazy { familyFolderActivity.org } + lateinit var markerStyles: MarkerStyles - override fun onActivityCreated(bundle: Bundle?) { - super.onActivityCreated(bundle) - setStartLocation(preference.lastCameraPosition) + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) addLocationButton = activity!!.find(R.id.addLocationButton) - viewFinder.gone() - hideToolsMenu() + observeViewModel() + markerStyles = ChronicMarkerStyles(context!!) } private fun observeViewModel() { @@ -84,8 +88,8 @@ class GeoMapsFragment : PointMarloFragment() { ?: preferZoomLevel ) googleMap.clear() - addGeoJsonLayer(GeoJsonLayer(googleMap, JSONObject(it.toJson()))) - preference.geojsonCache = it + viewModel.json.value = JSONObject(it.toJson()) + addGeoJsonLayer(GeoJsonLayer(googleMap, viewModel.json.value)) } } observe(viewModel.exception) { @@ -93,26 +97,16 @@ class GeoMapsFragment : PointMarloFragment() { } } - private fun setStartLocation(lastPosition: CameraPosition?) { - if (lastPosition != null) { - setStartLocation(lastPosition.target, lastPosition.zoom) - } else { - setStartLocation(LatLng(13.76498, 100.538335), 5.0f) - setStartAtCurrentLocation(true) - } - } - override fun onMapReady(googleMap: GoogleMap?) { super.onMapReady(googleMap) - viewModel.geojson.value = doAsyncResult { preference.geojsonCache }.get() - addLocationButton?.setOnClickListener { - val intent = intentFor( - "target" to googleMap!!.cameraPosition.target, - "zoom" to googleMap.cameraPosition.zoom - ) - startActivityForResult(intent, REQ_ADD_LOCATION) - } - askMyLocationPermission() +// viewModel.geojson.value = doAsyncResult { preference.geojsonCache }.get() +// addLocationButton?.setOnClickListener { +// val intent = intentFor( +// "target" to googleMap!!.cameraPosition.target, +// "zoom" to googleMap.cameraPosition.zoom +// ) +// startActivityForResult(intent, REQ_ADD_LOCATION) +// } loadGeoJson() } @@ -128,19 +122,14 @@ class GeoMapsFragment : PointMarloFragment() { private fun addGeoJsonLayer(layer: GeoJsonLayer) { with(layer) { - features.forEach { - it.pointStyle = GeoJsonPointStyle().apply { - icon = if (it.getProperty("haveChronic") == "true") chronicHomeIcon else homeIcon - title = "บ้านเลขที่ ${it.getProperty("no")}" - snippet = it.getProperty("coordinates")?.trimMargin() - } - } + features.forEach { it.pointStyle = markerStyles.pointStyleOf(it) } setOnFeatureClickListener { feature -> val intent = intentFor("houseId" to feature.getProperty("id")) startActivityForResult(intent, REQ_ADD_LOCATION, activity!!.sceneTransition()) } addLayerToMap() } + viewModel.layer.value = layer } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -152,23 +141,100 @@ class GeoMapsFragment : PointMarloFragment() { } } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - activity!!.handlePermissionsResult(requestCode, permissions, grantResults) + fun showInfo(info: GeoMapsInfo, onProgress: (Double) -> Unit) { + markerStyles = when (info) { + ELDER -> ElderMarkerStyle(context!!) + Disability -> DisabilityMarkerStyle(context!!) + else -> ChronicMarkerStyles(context!!) + } + + viewModel.layer.value?.let { layer -> + googleMap.uiSettings.setAllGesturesEnabled(false) + doAsync { + layer.features.forEachChunk(200, 150) { progress, list -> + onUiThread { + list.forEach { + it.pointStyle = markerStyles.pointStyleOf(it) + } + onProgress(progress) + } + } + Timber.d("finish") + onUiThread { googleMap.uiSettings.setAllGesturesEnabled(true) } + } + } } - override fun onPause() { - super.onPause() - googleMap?.cameraPosition?.let { preference.lastCameraPosition = it } + class GeoViewModel : ViewModel() { + val geojson = MutableLiveData>() + val json = MutableLiveData() + val layer = MutableLiveData() + val exception = MutableLiveData() } - fun bitmapOf(@DrawableRes resId: Int) = BitmapDescriptorFactory.fromBitmap(context!!.drawable(resId).toBitmap()) + interface MarkerStyles { - private val homeIcon by lazy { bitmapOf(R.drawable.ic_marker_home_green_24dp) } + val context: Context - private val chronicHomeIcon by lazy { bitmapOf(R.drawable.ic_marker_home_red_24dp) } + fun bitmapOf(@DrawableRes resId: Int, @ColorInt color: Int? = null): BitmapDescriptor { + val drawable = context.drawable(resId) + color?.let { drawable.tint(color) } + return BitmapDescriptorFactory.fromBitmap(drawable.toBitmap()) + } - class GeoViewModel : ViewModel() { - val geojson = MutableLiveData>() - val exception = MutableLiveData() + fun pointStyleOf(it: GeoJsonFeature): GeoJsonPointStyle + } + + class ChronicMarkerStyles(override val context: Context) : MarkerStyles { + + private val homeIcon by lazy { bitmapOf(R.drawable.ic_marker_home_green_24dp) } + + private val chronicHomeIcon by lazy { bitmapOf(R.drawable.ic_marker_home_red_24dp) } + + override fun pointStyleOf(it: GeoJsonFeature): GeoJsonPointStyle { + return GeoJsonPointStyle().apply { + icon = if (it.getProperty("haveChronic") == "true") chronicHomeIcon else homeIcon + title = "บ้านเลขที่ ${it.getProperty("no")}" + snippet = it.getProperty("coordinates")?.trimMargin() + } + } + } + + class ElderMarkerStyle(override val context: Context) : MarkerStyles { + + private val notElderIcon by lazy { bitmapOf(R.drawable.ic_marker_home_grey_24dp) } + private val socialIcon by lazy { bitmapOf(R.drawable.ic_marker_home_green_24dp) } + private val stayIcon by lazy { bitmapOf(R.drawable.ic_marker_home_yellow_24dp) } + private val bedIcon by lazy { bitmapOf(R.drawable.ic_marker_home_red_24dp) } + + override fun pointStyleOf(it: GeoJsonFeature): GeoJsonPointStyle { + return GeoJsonPointStyle().apply { + val md5 = it.getProperty("no").md5().toLowerCase() + icon = when (md5[0]) { + '1' -> bedIcon + '4', '5' -> stayIcon + '6', '8', 'a' -> socialIcon + else -> notElderIcon + } + title = md5 + } + } + } + + class DisabilityMarkerStyle(override val context: Context) : MarkerStyles { + + private val notElderIcon by lazy { bitmapOf(R.drawable.ic_marker_home_grey_24dp) } + private val disabilityIcon by lazy { bitmapOf(R.drawable.ic_marker_home_purple_24dp) } + + override fun pointStyleOf(it: GeoJsonFeature): GeoJsonPointStyle { + return GeoJsonPointStyle().apply { + val md5 = it.getProperty("no").md5().toLowerCase() + icon = when (md5[0]) { + '1' -> disabilityIcon + else -> notElderIcon + } + title = md5 + } + } } } diff --git a/ffc/src/main/kotlin/ffc/app/location/GeoMapsInfoSheet.kt b/ffc/src/main/kotlin/ffc/app/location/GeoMapsInfoSheet.kt new file mode 100644 index 00000000..2ce0e94a --- /dev/null +++ b/ffc/src/main/kotlin/ffc/app/location/GeoMapsInfoSheet.kt @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2019 NECTEC + * National Electronics and Computer Technology Center, Thailand + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ffc.app.location + +import android.support.design.widget.BottomSheetBehavior +import android.support.design.widget.BottomSheetBehavior.BottomSheetCallback +import android.support.design.widget.FloatingActionButton +import android.view.View +import android.view.View.OnClickListener +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.ProgressBar +import ffc.android.drawable +import ffc.android.layoutInflater +import ffc.android.onClick +import ffc.app.MainActivity +import ffc.app.R +import ffc.app.location.GeoMapsInfo.Chronic +import ffc.app.location.GeoMapsInfo.Disability +import ffc.app.location.GeoMapsInfo.ELDER +import ffc.app.location.GeoMapsInfo.NORMAL +import org.jetbrains.anko.find + +class GeoMapsInfoSheet(actvity: MainActivity, geoMapsFragment: GeoMapsFragment) { + + private val fab = actvity.find(R.id.mapLayoutOption) + private val progress = actvity.find(R.id.progress) + val peek = actvity.find(R.id.mapInfoPeek) + private val behavior = BottomSheetBehavior.from(actvity.find(R.id.bottom_sheet))!! + + var currentInfo: GeoMapsInfo = Chronic + + val onClick = OnClickListener { view -> + val newInfo = when (view.id) { + R.id.elderMapInfo -> ELDER + R.id.cvdMapInfo -> Chronic + R.id.disabilityMapInfo -> Disability + else -> NORMAL + } + if (newInfo != currentInfo) { + currentInfo = newInfo + progress.progress = 0 + geoMapsFragment.showInfo(newInfo) { + progress.progress = (it * 100.0).toInt() + if (it == 1.0) { + progress.animate().scaleX(0f).setDuration(150).start() + peek.removeAllViews() + peek.addView(newInfo.getLegendView()) + } + } + progress.animate().scaleX(1f).setDuration(50).setStartDelay(300).start() + peek.removeAllViews() + peek.addView(loadingPeek) + } + behavior.state = BottomSheetBehavior.STATE_COLLAPSED + } + + init { + behavior.state = BottomSheetBehavior.STATE_HIDDEN + behavior.setBottomSheetCallback(object : BottomSheetCallback() { + override fun onSlide(view: View, slideOffset: Float) { + } + + override fun onStateChanged(view: View, newState: Int) { + if (BottomSheetBehavior.STATE_SETTLING == newState) { + fab.animate().scaleX(0f).scaleY(0f).setDuration(300).start() + } else if (BottomSheetBehavior.STATE_HIDDEN == newState) { + fab.animate().scaleX(1f).scaleY(1f).setDuration(300).start() + } + } + }) + actvity.find(R.id.elderMapInfo).setOnClickListener(onClick) + actvity.find(R.id.cvdMapInfo).setOnClickListener(onClick) + actvity.find(R.id.disabilityMapInfo).setOnClickListener(onClick) + + progress.max = 100 + progress.animate().scaleX(0f).setDuration(0).start() + + fab.onClick { + behavior.state = BottomSheetBehavior.STATE_COLLAPSED + } + + peek.addView(currentInfo.getLegendView()) + } + + fun GeoMapsInfo.getLegendView(): View { + val view = peek.layoutInflater.inflate(R.layout.maps_info_legend_peek, peek, false) + val legend = view.find(R.id.mapInfoLegend) + val icon = view.find(R.id.mapsInfoIcon) + icon.onClick { behavior.state = BottomSheetBehavior.STATE_EXPANDED } + when (this) { + ELDER -> { + legend.setLegend( + R.color.colorAccentLegacy to R.string.elder_socialist, + R.color.yellow_500 to R.string.elder_home, + R.color.red_500 to R.string.elder_immobilised + ) + icon.setImageDrawable(view.drawable(R.drawable.ic_elder_couple_color_24dp)) + } + Chronic -> { + legend.setLegend( + R.color.colorAccentLegacy to R.string.normal, + R.color.red_500 to R.string.chronic + ) + icon.setImageDrawable(view.drawable(R.drawable.ic_heart_cvd_color_24dp)) + } + Disability -> { + legend.setLegend( + R.color.grey_300 to R.string.normal, + R.color.purple_300 to R.string.disability + ) + icon.setImageDrawable(view.drawable(R.drawable.ic_wheelchair_color_24dp)) + } + } + return view + } + + val loadingPeek: View by lazy { + peek.layoutInflater.inflate(R.layout.maps_info_peek_loading, peek, false) + } +} + +enum class GeoMapsInfo { + NORMAL, ELDER, Chronic, Disability +} diff --git a/ffc/src/main/kotlin/ffc/app/location/LegendView.kt b/ffc/src/main/kotlin/ffc/app/location/LegendView.kt new file mode 100644 index 00000000..ebc4e065 --- /dev/null +++ b/ffc/src/main/kotlin/ffc/app/location/LegendView.kt @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019 NECTEC + * National Electronics and Computer Technology Center, Thailand + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ffc.app.location + +import android.content.Context +import android.support.annotation.ColorRes +import android.support.annotation.StringRes +import android.util.AttributeSet +import android.view.Gravity +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import ffc.android.color +import ffc.app.R +import org.jetbrains.anko.dip + +class LegendView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + init { + orientation = LinearLayout.HORIZONTAL + } + + fun setLegend(vararg colorTextPair: Pair) { + removeAllViews() + val layoutParams = LayoutParams(0, LayoutParams.WRAP_CONTENT, 1f).apply { + gravity = Gravity.CENTER_VERTICAL + } + colorTextPair.forEach { + val item = LegendItem(context).apply { + colorRes = it.first + textRes = it.second + } + addView(item, layoutParams) + } + } +} + +class LegendItem @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.style.AppTheme +) : LinearLayout(context, attrs, defStyleAttr) { + + val colorView = ImageView(context, attrs, defStyleAttr) + val textView = TextView(context, attrs, defStyleAttr) + + var colorRes: Int = -1 + set(@ColorRes value) { + field = value + colorView.setBackgroundColor(color(value)) + } + + var textRes: Int = -1 + set(@StringRes value) { + field = value + textView.setText(value) + } + + init { + orientation = LinearLayout.VERTICAL + + colorView.setBackgroundColor(color(R.color.colorAccent)) + textView.apply { + //textAppearance = android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Body1 + textAlignment = TextView.TEXT_ALIGNMENT_CENTER + } + + addView(colorView, LayoutParams(LayoutParams.MATCH_PARENT, dip(12))) + addView(textView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply { + topMargin = dip(4) + }) + + if (isInEditMode) { + textRes = R.string.app_name + colorRes = R.color.colorAccent + } + } +} diff --git a/ffc/src/main/kotlin/ffc/app/util/Iterable.kt b/ffc/src/main/kotlin/ffc/app/util/Iterable.kt new file mode 100644 index 00000000..a3e48c61 --- /dev/null +++ b/ffc/src/main/kotlin/ffc/app/util/Iterable.kt @@ -0,0 +1,13 @@ +package ffc.app.util + +inline fun Iterable.forEachChunk( + size: Int, + delay: Long = 0, + action: (progress: Double, list: List) -> Unit +) { + val chunked = chunked(size) + chunked.forEachIndexed { index, list -> + Thread.sleep(delay) + action((index + 1) / chunked.size.toDouble(), list) + } +} diff --git a/ffc/src/main/res/drawable/ic_layers_black_24dp.xml b/ffc/src/main/res/drawable/ic_layers_black_24dp.xml new file mode 100644 index 00000000..2de43d21 --- /dev/null +++ b/ffc/src/main/res/drawable/ic_layers_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/ffc/src/main/res/drawable/ic_marker_home_grey_24dp.xml b/ffc/src/main/res/drawable/ic_marker_home_grey_24dp.xml new file mode 100644 index 00000000..8179e16f --- /dev/null +++ b/ffc/src/main/res/drawable/ic_marker_home_grey_24dp.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/ffc/src/main/res/drawable/ic_marker_home_purple_24dp.xml b/ffc/src/main/res/drawable/ic_marker_home_purple_24dp.xml new file mode 100644 index 00000000..afe6889e --- /dev/null +++ b/ffc/src/main/res/drawable/ic_marker_home_purple_24dp.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/ffc/src/main/res/drawable/ic_marker_home_yellow_24dp.xml b/ffc/src/main/res/drawable/ic_marker_home_yellow_24dp.xml new file mode 100644 index 00000000..e4aabc17 --- /dev/null +++ b/ffc/src/main/res/drawable/ic_marker_home_yellow_24dp.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/ffc/src/main/res/drawable/ic_wheelchair_color_24dp.xml b/ffc/src/main/res/drawable/ic_wheelchair_color_24dp.xml new file mode 100644 index 00000000..d6eacc45 --- /dev/null +++ b/ffc/src/main/res/drawable/ic_wheelchair_color_24dp.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + diff --git a/ffc/src/main/res/layout/activity_main_content.xml b/ffc/src/main/res/layout/activity_main_content.xml index e46c8e8f..753e4287 100644 --- a/ffc/src/main/res/layout/activity_main_content.xml +++ b/ffc/src/main/res/layout/activity_main_content.xml @@ -1,5 +1,5 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ffc/src/main/res/values/dimens.xml b/ffc/src/main/res/values/dimens.xml index e064c084..c77712af 100644 --- a/ffc/src/main/res/values/dimens.xml +++ b/ffc/src/main/res/values/dimens.xml @@ -17,6 +17,7 @@ 90dp + 20dp 24dp 24dp @@ -35,4 +36,5 @@ 10dp 16dp 24dp + 72dp diff --git a/ffc/src/main/res/values/strings.xml b/ffc/src/main/res/values/strings.xml index f9bb82ad..94f9e73e 100644 --- a/ffc/src/main/res/values/strings.xml +++ b/ffc/src/main/res/values/strings.xml @@ -128,4 +128,10 @@ ลิขสิทธิ์ การมีส่วนร่วม กรุณาอ่านและทำความเข้าใจ + ติดสังคม + ติดบ้าน + ติดเตียง + ปกติ + โรคเรื้อรัง + พิการ