Skip to content

Instantly share code, notes, and snippets.

@jayesh83
Created August 25, 2021 09:05
Show Gist options
  • Save jayesh83/0dbfe7ac7b036c44a4f3db25ec567aa3 to your computer and use it in GitHub Desktop.
Save jayesh83/0dbfe7ac7b036c44a4f3db25ec567aa3 to your computer and use it in GitHub Desktop.
package com.nascent.pcmc.ui.home
import android.annotation.SuppressLint
import android.content.pm.ApplicationInfo
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.nascent.pcmc.R
import com.nascent.pcmc.databinding.FragmentHomeBinding
import com.nascent.pcmc.model.BuildingPinInfoModel
import com.nascent.pcmc.ui.DialogPinInformation
import com.nascent.pcmc.utils.ViewUtils.Companion.log
import com.nascent.pcmc.utils.toast
import org.json.JSONObject
import kotlin.random.Random
class HomeFragment : Fragment() {
private val homeViewModel: HomeViewModel by activityViewModels()
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// observeAndLoadMapGrids()
}
private fun observeAndLoadMapGrids() {
homeViewModel.mapConfig.observe(viewLifecycleOwner) {
setupAndLoadMap() // loading map only when map config is ready to be used
}
}
@SuppressLint("SetJavaScriptEnabled")
private fun setupAndLoadMap() {
binding.webView.apply {
if (0 != context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE)
WebView.setWebContentsDebuggingEnabled(true)
settings.allowContentAccess = true
settings.allowFileAccess = true
addJavascriptInterface(WebAppInterface(), "appInterface")
settings.javaScriptEnabled = true
settings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
settings.allowFileAccessFromFileURLs = true
webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
plotUserGeneratedBuildings()
}
}
loadUrl("file:///${context.filesDir}/map/index.html")
}
}
private fun plotUserGeneratedBuildings() {
homeViewModel.userGeneratedNewBuildings.observe(viewLifecycleOwner) {
val userGeneratedBuildingsData = it.map { building ->
JSONObject()
.put("gis_id", building.gisId)
.put("lat", building.buildingLatitude)
.put("lon", building.buildingLongitude)
}
binding.webView.loadUrl("javascript:PlotOldGeneratedBuilding('${userGeneratedBuildingsData}')")
}
}
override fun onStart() {
super.onStart()
checkAuthentication()
observeAndLoadMapGrids()
}
private fun checkAuthentication() {
if (!homeViewModel.isUserLoggedIn()) {
findNavController().navigate(HomeFragmentDirections.actionNavHomeToNavLogin())
}
}
fun showPinInformation(pinInfo: BuildingPinInfoModel) {
val dialog = DialogPinInformation(pinInfo)
dialog.show(parentFragmentManager, "DialogPinInformation")
}
inner class WebAppInterface {
@JavascriptInterface
fun getBuildingInfo(data: String?) { // called from map's js, when user touches on any building
if (data != null) {
try {
val pinInfoJson = JSONObject(data)
val buildingPinInfo = BuildingPinInfoModel(
gisId = pinInfoJson.getString("building_id"),
buildingName = pinInfoJson.optString("building_name", "-"),
gutNo = pinInfoJson.getString("gut_no"),
wardNo = pinInfoJson.getString("prbhag")
)
showPinInformation(buildingPinInfo)
log(data)
} catch (ex: Exception) {
toast(getString(R.string.couldnt_fetch_building_info))
ex.printStackTrace()
}
}
}
@JavascriptInterface
fun getNewGeneratedBuilding(data: String?) { // called from map's js, when user creates new building footprint
if (data != null) {
try {
log(data)
val pinInfoJson = JSONObject(data)
val gutNo = pinInfoJson.getString("gut_no")
val wardNo = pinInfoJson.getString("prbhag")
val buildingPinInfo = BuildingPinInfoModel(
gisId = generateGisId(gutNo, wardNo),
buildingName = "-",
gutNo = gutNo,
wardNo = wardNo,
buildingLatitude = pinInfoJson.getString("lat"),
buildingLongitude = pinInfoJson.getString("lon"),
isGeneratedBuilding = true
)
showPinInformation(buildingPinInfo)
} catch (ex: Exception) {
toast(getString(R.string.couldnt_fetch_building_info))
ex.printStackTrace()
}
}
}
@JavascriptInterface
fun showNewGeneratedBuilding(gisId: String?) { // called from map's js, when user taps on newly created building footprint
if (gisId != null) {
homeViewModel.getNewBuildingDetails(gisId)?.let { pinInfoModel ->
showPinInformation(pinInfoModel)
} ?: toast(getString(R.string.couldnt_fetch_building_info))
}
}
@JavascriptInterface
fun getGridsInMap(): String { // called by js to fetch currently assigned grid names and bbox (zoom level) info.
val mapConfig = homeViewModel.mapConfig.value
if (mapConfig == null) {
toast(getString(R.string.map_render_problem))
return ""
}
return mapConfig.toString()
}
private fun generateGisId(gutNo: String, wardNo: String): String {
/** e.g. GIS ID: 8-10-2-R20-3-4225 **/
val strBuilder = StringBuilder("${gutNo}-${wardNo}")
.append('-')
.append(Random.nextInt(1, 11))
.append('-')
.append(('A'..'Z').random())
.append(Random.nextInt(10, 21))
.append('-')
.append(Random.nextInt(1, 11))
.append('-')
.append(Random.nextInt(1000, 9999))
return strBuilder.toString()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment