Google Map GroundOverlay doesn't display the overlay image.
There was no error or any sort. (At least not in the log.)
The code was copied from Google IO 2019 app.
MapFragment File
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mapView.getMapAsync {
it.mapType = GoogleMap.MAP_TYPE_NORMAL
it.addGroundOverlay(
GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.kirirom_map_overlay))
.positionFromBounds(viewModel.resortLocationBounds)
)
}
}
MapViewModel File
val resortLocationBounds: LatLngBounds = LatLngBounds(BuildConfig.MAP_VIEWPORT_BOUND_SW, BuildConfig.MAP_VIEWPORT_BOUND_NE)
References:
Full MapFragment file:
package kh.edu.kit.chain.app.vkclub.features.maps
import android.Manifest
import android.app.Dialog
import android.content.pm.PackageManager
import android.os.Bundle
import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.addCallback
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.view.updatePaddingRelative
import androidx.core.widget.NestedScrollView
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.MapView
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.GroundOverlayOptions
import com.google.android.gms.maps.model.LatLng
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.maps.android.data.geojson.GeoJsonLayer
import kh.edu.kit.chain.app.vkclub.R
import kh.edu.kit.chain.app.vkclub.databinding.MapsFragmentBinding
import kh.edu.kit.chain.app.vkclub.functions.doOnApplyWindowInsets
import kh.edu.kit.chain.app.vkclub.shared.BottomSheetBehavior
import kh.edu.kit.chain.app.vkclub.utils.getDrawableResourceForIcon
import org.koin.android.viewmodel.ext.android.viewModel
class MapsFragment : Fragment() {
companion object {
const val MIN_TIME: Long = 400
const val MIN_DISTANCE: Float = 1000F
private const val MAPVIEW_BUNDLE_KEY = "MapViewBundleKey"
private const val REQUEST_LOCATION_PERMISSION = 1
private const val FRAGMENT_MY_LOCATION_RATIONALE = "my_location_rationale"
// Threshold for when the marker description reaches maximum alpha. Should be a value
// between 0 and 1, inclusive, coinciding with a point between the bottom sheet's
// collapsed (0) and expanded (1) states.
private const val ALPHA_TRANSITION_END = 0.5f
// Threshold for when the marker description reaches minimum alpha. Should be a value
// between 0 and 1, inclusive, coinciding with a point between the bottom sheet's
// collapsed (0) and expanded (1) states.
private const val ALPHA_TRANSITION_START = 0.1f
}
private val viewModel: MapsViewModel by viewModel()
private var mapViewBundle: Bundle? = null
private lateinit var mapView: MapView
private lateinit var binding: MapsFragmentBinding
private lateinit var bottomSheetBehavior: BottomSheetBehavior<*>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY)
}
requireActivity().onBackPressedDispatcher.addCallback(this) {
onBackPressed()
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = MapsFragmentBinding.inflate(inflater, container, false).apply {
lifecycleOwner = viewLifecycleOwner
viewModel = this#MapsFragment.viewModel
}
mapView = binding.map.apply {
onCreate(mapViewBundle)
}
if (savedInstanceState == null) {
viewModel.setMapVariant(MapVariant.DAY)
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bottomSheetBehavior = BottomSheetBehavior.from(binding.bottomSheet)
val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback {
override fun onStateChanged(bottomSheet: View, newState: Int) {
val rotation = when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> 0f
BottomSheetBehavior.STATE_COLLAPSED -> 180f
BottomSheetBehavior.STATE_HIDDEN -> 180f
else -> return
}
binding.expandIcon.animate().rotationX(rotation).start()
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
}
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallback)
binding.bottomSheet.post {
val state = bottomSheetBehavior.state
val slideOffset = when (state) {
BottomSheetBehavior.STATE_EXPANDED -> 1f
BottomSheetBehavior.STATE_COLLAPSED -> 0f
else -> -1f // BottomSheetBehavior.STATE_HIDDEN
}
bottomSheetCallback.onStateChanged(binding.bottomSheet, state)
bottomSheetCallback.onSlide(binding.bottomSheet, slideOffset)
}
val originalPeekHeight = bottomSheetBehavior.peekHeight
binding.root.doOnApplyWindowInsets { _, insets, _ ->
binding.map.getMapAsync {
it.setPadding(0, 0, 0, insets.systemWindowInsetBottom)
}
binding.descriptionScrollview.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
val gestureInsets = insets.systemGestureInsets
bottomSheetBehavior.peekHeight = gestureInsets.bottom + originalPeekHeight
}
binding.clickable.setOnClickListener {
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
} else {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
binding.descriptionScrollview.setOnScrollChangeListener { v: NestedScrollView, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int ->
binding.sheetHeaderShadow.isActivated = v.canScrollVertically(-1)
}
mapView.getMapAsync { googleMap ->
googleMap.apply {
setOnMapClickListener { viewModel.dismissFeatureDetails() }
setOnCameraMoveListener {
viewModel.onZoomChanged(googleMap.cameraPosition.zoom)
}
enableMyLocation(false)
}
}
viewModel.mapVariant.observe(viewLifecycleOwner, Observer {
mapView.getMapAsync { googleMap ->
googleMap.clear()
viewModel.loadMapFeatures(googleMap)
}
})
viewModel.geoJsonLayer.observe(viewLifecycleOwner, Observer {
updateMarkers(it ?: return#Observer)
})
viewModel.selectedMarkerInfo.observe(viewLifecycleOwner, Observer {
updateInfoSheet(it ?: return#Observer)
})
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mapView.getMapAsync {
it.mapType = GoogleMap.MAP_TYPE_NORMAL
it.addGroundOverlay(
GroundOverlayOptions()
.image(BitmapDescriptorFactory.fromResource(R.drawable.kirirom_map_overlay))
.positionFromBounds(viewModel.resortLocationBounds)
)
}
}
private fun updateInfoSheet(markerInfo: MarkerInfo) {
val iconRes = getDrawableResourceForIcon(binding.markerIcon.context, markerInfo.iconName)
binding.markerIcon.apply {
setImageResource(iconRes)
visibility = if (iconRes == 0) View.GONE else View.VISIBLE
}
binding.markerTitle.text = markerInfo.title
binding.markerSubtitle.apply {
text = markerInfo.subtitle
isVisible = !markerInfo.subtitle.isNullOrEmpty()
}
val description = Html.fromHtml(markerInfo.description ?: "")
val hasDescription = description.isNotEmpty()
binding.markerDescription.apply {
text = description
isVisible = hasDescription
}
binding.expandIcon.isVisible = hasDescription
binding.clickable.isVisible = hasDescription
}
private fun onBackPressed(): Boolean {
if (::bottomSheetBehavior.isInitialized &&
bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED
) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
return true
}
return false
}
private fun updateMarkers(geoJsonLayer: GeoJsonLayer) {
geoJsonLayer.addLayerToMap()
geoJsonLayer.setOnFeatureClickListener { feature ->
viewModel.requestHighlightFeature(feature.id.split(",")[0])
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val mapViewBundle = outState.getBundle(MAPVIEW_BUNDLE_KEY)
?: Bundle().apply { putBundle(MAPVIEW_BUNDLE_KEY, this) }
mapView.onSaveInstanceState(mapViewBundle)
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
viewModel.onMapDestroyed()
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
private fun requestLocationPermission() {
val context = context ?: return
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
) {
return
}
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
MyLocationRationaleFragment()
.show(childFragmentManager, FRAGMENT_MY_LOCATION_RATIONALE)
return
}
requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_LOCATION_PERMISSION) {
if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
enableMyLocation()
} else {
MyLocationRationaleFragment()
.show(childFragmentManager, FRAGMENT_MY_LOCATION_RATIONALE)
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
private fun enableMyLocation(requestPermission: Boolean = false) {
val context = context ?: return
when {
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED -> {
mapView.getMapAsync {
it.isMyLocationEnabled = true
}
viewModel.optIntoMyLocation()
}
requestPermission -> requestLocationPermission()
else -> viewModel.optIntoMyLocation(false)
}
}
class MyLocationRationaleFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return MaterialAlertDialogBuilder(context)
.setMessage(R.string.my_location_rationale)
.setPositiveButton(android.R.string.ok) { _, _ ->
parentFragment!!.requestPermissions(
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_LOCATION_PERMISSION
)
}
.setNegativeButton(android.R.string.cancel, null) // Give up
.create()
}
}
}
Full MapViewModel file:
package kh.edu.kit.chain.app.vkclub.features.maps
import androidx.lifecycle.*
import com.google.android.gms.maps.CameraUpdate
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.maps.android.data.geojson.GeoJsonFeature
import com.google.maps.android.data.geojson.GeoJsonLayer
import com.google.maps.android.data.geojson.GeoJsonPoint
import kh.edu.kit.chain.app.vkclub.BuildConfig
import kh.edu.kit.chain.app.vkclub.R
import kh.edu.kit.chain.app.vkclub.domain.map.GeoJsonData
import kh.edu.kit.chain.app.vkclub.domain.map.LoadGeoJsonFeaturesUseCase
import kh.edu.kit.chain.app.vkclub.domain.map.LoadGeoJsonParams
import kh.edu.kit.chain.app.vkclub.functions.Event
import kh.edu.kit.chain.app.vkclub.functions.Result
class MapsViewModel(
private val loadGeoJsonFeaturesUseCase: LoadGeoJsonFeaturesUseCase
) : ViewModel() {
val resortLocationBounds: LatLngBounds = LatLngBounds(BuildConfig.MAP_VIEWPORT_BOUND_SW, BuildConfig.MAP_VIEWPORT_BOUND_NE)
val groundOverlayData = Pair(resortLocationBounds, R.drawable.kirirom_map_overlay)
private val _mapVariant = MutableLiveData<MapVariant>()
val mapVariant = Transformations.distinctUntilChanged(_mapVariant)
private val _mapCenterEvent = MutableLiveData<Event<CameraUpdate>>()
val mapCenterEvent: LiveData<Event<CameraUpdate>>
get() = _mapCenterEvent
private val loadGeoJsonResult = MutableLiveData<Result<GeoJsonData>>()
private val _geoJsonLayer = MediatorLiveData<GeoJsonLayer>()
val geoJsonLayer: LiveData<GeoJsonLayer>
get() = _geoJsonLayer
private val featureLookup: MutableMap<String, GeoJsonFeature> = mutableMapOf()
private var hasLoadedFeature = false
private var requestedFeatureId: String? = null
private val focusZoomLevel = BuildConfig.MAP_CAMERA_FOCUS_ZOOM
private var currentZoomLevel = 16
private val _bottomSheetStateEvent = MediatorLiveData<Event<Int>>()
val bottomSheetStateEvent: LiveData<Event<Int>>
get() = _bottomSheetStateEvent
private val _selectedMarkerInfo = MutableLiveData<MarkerInfo>()
val selectedMarkerInfo: LiveData<MarkerInfo>
get() = _selectedMarkerInfo
init {
_geoJsonLayer.addSource(loadGeoJsonResult) { result ->
if (result is Result.Success) {
hasLoadedFeature = true
setMapFeatures(result.data.featureMap)
_geoJsonLayer.value = result.data.geoJsonLayer
}
}
_bottomSheetStateEvent.addSource(mapVariant) {
dismissFeatureDetails()
}
}
fun setMapVariant(variant: MapVariant) {
_mapVariant.value = variant
}
fun onMapDestroyed() {
hasLoadedFeature = false
featureLookup.clear()
_geoJsonLayer.value = null
}
fun loadMapFeatures(googleMap: GoogleMap) {
val variant = _mapVariant.value ?: return
loadGeoJsonFeaturesUseCase(
LoadGeoJsonParams(googleMap, variant.markersResId),
loadGeoJsonResult
)
}
private fun setMapFeatures(features: Map<String, GeoJsonFeature>) {
featureLookup.clear()
featureLookup.putAll(features)
updateFeaturesVisibility(currentZoomLevel.toFloat())
val featureId = requestedFeatureId ?: return
requestedFeatureId = null
highlightFeature(featureId)
}
fun onZoomChanged(zoom: Float) {
val zoomInt = zoom.toInt()
if (currentZoomLevel != zoomInt) {
currentZoomLevel = zoomInt
updateFeaturesVisibility(zoom)
}
}
private fun updateFeaturesVisibility(zoom: Float) {
val selectedId = selectedMarkerInfo.value?.id
featureLookup.values.forEach { feature ->
if (feature.id != selectedId) {
val minZoom = feature.getProperty("minZoom")?.toFloatOrNull() ?: 0f
feature.pointStyle.isVisible = zoom >= minZoom
}
}
}
fun requestHighlightFeature(featureId: String) {
if (hasLoadedFeature) {
highlightFeature(featureId)
} else {
requestedFeatureId = featureId
}
}
private fun highlightFeature(featureId: String) {
val feature = featureLookup[featureId] ?: return
val geometry = feature.geometry as? GeoJsonPoint ?: return
val update = CameraUpdateFactory.newLatLngZoom(geometry.coordinates, focusZoomLevel)
_mapCenterEvent.value = Event(update)
val title = feature.getProperty("title")
_selectedMarkerInfo.value = MarkerInfo(
featureId,
title,
feature.getProperty("subtitle"),
feature.getProperty("description"),
feature.getProperty("icon")
)
_bottomSheetStateEvent.value = Event(BottomSheetBehavior.STATE_COLLAPSED)
}
fun dismissFeatureDetails() {
_bottomSheetStateEvent.value = Event(BottomSheetBehavior.STATE_HIDDEN)
_selectedMarkerInfo.value = null
}
fun optIntoMyLocation(optIn: Boolean = true) {
}
}
data class MarkerInfo(
val id: String,
val title: String,
val subtitle: String?,
val description: String?,
val iconName: String?
)
It turned out that the overlay was added successfully but it was clear away after the variant changed.
Related
I have a timer activity. That works great. Now i want to convert that timer into a fragment so I can use it inside a tabLayout.
Now I get some errors inside my PrefUtilStartTimerFrag. With all the "context" I get the error:
Type mismatch.
Required:
Context!
Found:
TabStartTimerFragment
First, this is my Timer fragment Kotlin file:
import android.media.MediaPlayer
import android.os.Bundle
import android.os.CountDownTimer
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.fotf.klimaatambitiegame.util.PrefUtilStartTimerFrag
import kotlinx.android.synthetic.main.fragment_tab_start_timer.*
class TabStartTimerFragment : Fragment() {
enum class TimerState {
Stopped, Paused, Running
}
private lateinit var timer: CountDownTimer
private var timerLengthSeconds: Int = 30
private var timerState = TimerState.Stopped
private var secondsRemaining = 0
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_tab_start_timer, container, false)
}
// val fab_start = findViewById<Button>(R.id.fab_startfrag)
// val fab_pause = findViewById<Button>(R.id.fab_pausefrag)
// val fab_stop = findViewById<Button>(R.id.fab_stopfrag)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
fab_startfrag.setOnClickListener {
startTimer()
timerState = TabStartTimerFragment.TimerState.Running
updateButtons()
}
fab_pausefrag.setOnClickListener {
timer.cancel()
timerState = TabStartTimerFragment.TimerState.Paused
updateButtons()
}
fab_stopfrag.setOnClickListener {
timer.cancel()
onTimerFinished()
updateButtons()
}
}
override fun onResume() {
super.onResume()
initTimer()
}
override fun onPause() {
super.onPause()
if (timerState == TabStartTimerFragment.TimerState.Running) {
timer.cancel()
} else if (timerState == TabStartTimerFragment.TimerState.Paused) {
}
PrefUtilStartTimerFrag.setPreviousTimerLengthSeconds(timerLengthSeconds, this)
PrefUtilStartTimerFrag.setSecondsRemaining(secondsRemaining, this)
PrefUtilStartTimerFrag.setTimerState(timerState, this)
}
fun initTimer() {
timerState = PrefUtilStartTimerFrag.getTimerState(this)
if (timerState == TabStartTimerFragment.TimerState.Stopped)
setNewTimerLength()
else
setPreviousTimerLength()
secondsRemaining = if (timerState == TabStartTimerFragment.TimerState.Running || timerState == TabStartTimerFragment.TimerState.Paused)
PrefUtilStartTimerFrag.getSecondsRemaining(this).toInt()
else
timerLengthSeconds
if (timerState == TabStartTimerFragment.TimerState.Running)
startTimer()
updateButtons()
updateCountdownUI()
}
private fun onTimerFinished() {
//var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
timerState = TabStartTimerFragment.TimerState.Stopped
setNewTimerLength()
progress_countdown.progress = 0
PrefUtilStartTimerFrag.setSecondsRemaining(timerLengthSeconds, this)
secondsRemaining = timerLengthSeconds
updateButtons()
updateCountdownUI()
}
private fun startTimer() {
var mp = MediaPlayer.create(context, R.raw.elephant)
timerState = TabStartTimerFragment.TimerState.Running
timer = object : CountDownTimer((secondsRemaining * 1000).toLong(), 1000) {
override fun onFinish() {
onTimerFinished()
mp.start()
}
override fun onTick(millisUntilFinished: Long) {
secondsRemaining = (millisUntilFinished / 1000).toInt()
updateCountdownUI()
}
}.start()
}
private fun setNewTimerLength() {
//var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
var lengthInMinutes = PrefUtilStartTimerFrag.getTimerLength(this)
timerLengthSeconds = ((lengthInMinutes * 60L).toInt())
progress_countdown.max = timerLengthSeconds.toInt()
}
private fun setPreviousTimerLength() {
//var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
timerLengthSeconds = PrefUtilStartTimerFrag.getPreviousTimerLengthSeconds(this).toInt()
progress_countdown.max = timerLengthSeconds.toInt()
}
private fun updateCountdownUI() {
//var progress_countdown = findViewById<ProgressBar>(R.id.progress_countdown)
// val textView_Countdown = findViewById<TextView>(R.id.timer_textview)
val minutesUntilFinished = secondsRemaining / 60
val secondsInMinutesUntilFinished = secondsRemaining - minutesUntilFinished * 60
val secondsStr = secondsInMinutesUntilFinished.toString()
timer_textviewfrag.text = "$minutesUntilFinished:${
if (secondsStr.length == 2) secondsStr
else "0" + secondsStr}"
progress_countdown.progress = (timerLengthSeconds - secondsRemaining).toInt()
}
private fun updateButtons() {
//val fab_start = findViewById<Button>(R.id.fab_start)
//val fab_pause = findViewById<Button>(R.id.fab_pause)
//val fab_stop = findViewById<Button>(R.id.fab_stop)
when (timerState) {
TabStartTimerFragment.TimerState.Running -> {
fab_startfrag.isEnabled = false
fab_pausefrag.isEnabled = true
fab_stopfrag.isEnabled = true
}
TabStartTimerFragment.TimerState.Stopped -> {
fab_startfrag.isEnabled = true
fab_pausefrag.isEnabled = false
fab_stopfrag.isEnabled = false
}
TabStartTimerFragment.TimerState.Paused -> {
fab_startfrag.isEnabled = true
fab_pausefrag.isEnabled = false
fab_stopfrag.isEnabled = true
}
}
}
}
Then, this is my PrefUtilStartTimerFrag file:
import android.content.Context
import android.preference.PreferenceManager
import com.fotf.klimaatambitiegame.StadKaartActivity
import com.fotf.klimaatambitiegame.TabStartTimerFragment
class PrefUtilStartTimerFrag {
companion object {
fun getTimerLength(context: TabStartTimerFragment): Double {
//placeholder
return 0.5
}
//private var defValue: Long
private const val PREVIOUS_TIMER_LENGTH_SECONDS_ID = "com.resoconder.timer.previous_timer_length"
fun getPreviousTimerLengthSeconds(context: TabStartTimerFragment): Long {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) //<- Error Type mismatch. Required: Context!
return preferences.getLong(PREVIOUS_TIMER_LENGTH_SECONDS_ID, 0)
}
fun setPreviousTimerLengthSeconds(seconds: Int, context: TabStartTimerFragment) {
val editor = PreferenceManager.getDefaultSharedPreferences(context).edit() //<- Error Type mismatch. Required: Context!
editor.putLong(PREVIOUS_TIMER_LENGTH_SECONDS_ID, seconds.toLong())
editor.apply()
}
private const val TIMER_STATE_ID = "com.resocoder.timer.timer_state"
fun getTimerState(context: TabStartTimerFragment): TabStartTimerFragment.TimerState {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) //<- Error Type mismatch. Required: Context!
val ordinal = preferences.getInt(TIMER_STATE_ID, 0)
return TabStartTimerFragment.TimerState.values()[ordinal]
}
fun setTimerState(state: TabStartTimerFragment.TimerState, context: TabStartTimerFragment) {
val editor = PreferenceManager.getDefaultSharedPreferences(context).edit() //<- Error Type mismatch. Required: Context!
val ordinal = state.ordinal
editor.putInt(TIMER_STATE_ID, ordinal)
editor.apply()
}
private const val SECONDS_REMAINING_ID = "com.resoconder.timer.previous_timer_length"
fun getSecondsRemaining(context: TabStartTimerFragment): Long {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) //<- Error Type mismatch. Required: Context!
return preferences.getLong(SECONDS_REMAINING_ID, 0)
}
fun setSecondsRemaining(seconds: Int, context: TabStartTimerFragment) {
val editor = PreferenceManager.getDefaultSharedPreferences(context).edit() //<- Error Type mismatch. Required: Context!
editor.putLong(SECONDS_REMAINING_ID, seconds.toLong())
editor.apply()
}
}
}
Now how can I fix these errors?
I have integrated mesibo chat and tried to integrate the mesibo push-notification but not receiving the notification. I had set up all the things related push notification and already success integrate with the backend also.
Not sure why i can't receive notification from mesibo related new chat and new call.
This is my code:
package com.project.bucynapp.ui.message
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.mesibo.api.Mesibo.*
import com.mesibo.calls.api.MesiboCall
import com.project.bucynapp.R
import com.project.bucynapp.models.*
import com.project.bucynapp.ui.message.adapter.ChatListAdapter
import com.project.bucynapp.ui.message.presenter.ChatListPresenter
import com.project.bucynapp.ui.message.view.ChatListView
import com.project.bucynapp.utils.*
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_chat_list.*
import kotlinx.android.synthetic.main.app_bar.toolbar
import kotlinx.android.synthetic.main.app_bar_chat_list.*
import kotlinx.android.synthetic.main.loading_view.*
class ChatListActivity : AppCompatActivity(), View.OnClickListener, ChatListView,
MessageListener, ConnectionListener, SyncListener {
private lateinit var presenter: ChatListPresenter
private lateinit var chatListAdapter: ChatListAdapter
private var chatList: MutableList<ChatModel> = mutableListOf()
private val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
private lateinit var readSession: ReadDbSession
private var userMesibo: MesiboAccountData? = null
var userProfile: UserProfile? = null
private var imageProfile: String? = null
private var nameProfile: String? = null
private var userId: Int = 0
private var email: String? = null
companion object {
private const val USER_ID = "user_id"
private const val IMAGE_PROFILE = "img_profile"
private const val NAME_PROFILE = "name_profile"
private val TAG = ChatListActivity::class.java.canonicalName
fun startActivity(
context: Context,
userId: Int?,
imageProfile: String,
nameProfile: String
) {
Intent(context, ChatListActivity::class.java).apply {
putExtra(USER_ID, userId)
putExtra(IMAGE_PROFILE, imageProfile)
putExtra(NAME_PROFILE, nameProfile)
context.startActivity(this)
}
}
}
private val message: String
get() = edtSendChat.text.toString()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_list)
initToolbar()
userMesibo = ApplicationPrefs.get(Constant.MESIBO_USER)
presenter = ChatListPresenter(this)
userId = intent.getIntExtra(USER_ID, 0)
imageProfile = intent.getStringExtra(IMAGE_PROFILE)
nameProfile = intent.getStringExtra(NAME_PROFILE)
chatListAdapter = ChatListAdapter(chatList)
rvChatList.adapter = chatListAdapter
rvChatList.layoutManager = layoutManager
rvChatList.addItemDecoration(DefaultItemDecoration(spacing = 10.dp, includeEdge = true))
tvName.text = nameProfile
Picasso.get().load(imageProfile)
.error(R.drawable.com_facebook_profile_picture_blank_square)
.placeholder(R.drawable.com_facebook_profile_picture_blank_square).into(imgProfile)
presenter.getEmailUser(userId)
}
private fun initToolbar() {
setSupportActionBar(toolbar)
val backArrow = ContextCompat.getDrawable(this, R.drawable.ic_back_black)
supportActionBar?.setHomeAsUpIndicator(backArrow)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
tvSeeProfile.setOnClickListener(this)
imgCalling.setOnClickListener(this)
imgVideoCall.setOnClickListener(this)
imgSendChat.setOnClickListener(this)
tilChat.setStartIconOnClickListener {
NotMatchActivity.startActivity(this)
}
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
override fun getChatListSuccess(response: MutableList<DataAttributes>) {
}
override fun getChatListFailed(message: String) {
}
override fun successPost(response: SuccessModel?) {
}
override fun failedPost(message: String) {
shortToast(message)
}
override fun onGetEmailUser(data: UserEmailResponse?) {
email = data?.email
startMesibo()
email?.let { loadFromDb(it) }
}
override fun onLoading(isShow: Boolean) {
if (isShow) {
rvChatList.gone()
loadingView.visible()
} else {
rvChatList.visible()
loadingView.gone()
}
}
override fun onNoData(msg: String?) {
shortToast(msg.toString())
}
override fun onBadRequest(msg: String?) {
shortToast(msg.toString())
}
override fun onUnauthorized(msg: String?) {
shortToast(msg.toString())
badToken()
}
override fun onClick(v: View?) {
when (v) {
imgSendChat -> if (message.isNotBlank()) onSendMessage()
tvSeeProfile -> {
UserProfileActivity.startActivity(this, userId)
}
imgCalling -> MesiboCall.getInstance().callUi(this, email, false)
imgVideoCall -> MesiboCall.getInstance().callUi(this, email, true)
}
}
override fun Mesibo_onMessage(p0: MessageParams?, p1: ByteArray?): Boolean {
val type: Int = if (p0?.isIncoming == true) 0 else 1
val msg = String(p1!!)
chatList.add(
ChatModel(
id = p0!!.mid,
msg = msg,
date = p0.ts,
type = type,
status = p0.status
)
)
chatListAdapter.notifyItemInserted(chatList.size)
layoutManager.scrollToPositionWithOffset(chatList.size - 1, 0)
return true
}
override fun Mesibo_onMessageStatus(p0: MessageParams?) {
chatList.find { p0?.mid == it.id }?.status = p0?.status
chatListAdapter.notifyDataSetChanged()
Log.i("TAG", "Mesibo_onMessageStatus: ${p0?.status}}")
}
override fun Mesibo_onActivity(p0: MessageParams?, p1: Int) {
Log.i("TAG", "Mesibo_onActivity: $p1")
when (p1) {
ACTIVITY_ONLINE -> {
imgDotOnline.visible()
imgDotOffline.gone()
Log.i(TAG, "MESIBO_ACTIVITY: activity on")
}
ACTIVITY_TYPING -> Log.i(TAG, "MESIBO_ACTIVITY: user typing")
else -> {
imgDotOnline.gone()
imgDotOffline.visible()
Log.i(TAG, "Mesibo_onActivity: $p1")
}
}
}
override fun Mesibo_onLocation(p0: MessageParams?, p1: Location?) {}
override fun Mesibo_onFile(p0: MessageParams?, p1: FileInfo?) {}
override fun Mesibo_onConnectionStatus(p0: Int) {
when (p0) {
STATUS_ONLINE -> {
setPushToken(ApplicationPrefs.tokenFcm)
tvConnectionStatus.gone()
Log.d(TAG, "MESIBO_CONNECTION_STATUS: online")
}
STATUS_OFFLINE -> {
tvConnectionStatus.gone()
Log.d(TAG, "MESIBO_CONNECTION_STATUS: offline")
}
STATUS_CONNECTING -> {
tvConnectionStatus.visible()
tvConnectionStatus.text = getString(R.string.connecting)
Log.d(TAG, "MESIBO_CONNECTION_STATUS: offline")
}
STATUS_CONNECTFAILURE, STATUS_NONETWORK -> {
tvConnectionStatus.visible()
tvConnectionStatus.text = getString(R.string.mesibo_connect_fail_msg)
}
else -> {
Log.d(TAG, "MESIBO_CONNECTION_STATUS: $p0")
Log.d(TAG, "MESIBO_TOKEN: ${userMesibo?.token}")
}
}
}
override fun Mesibo_onSync(p0: Int) {
if (p0 <= 0) return
readSession.read(p0)
}
private fun onSendMessage() {
val p = MessageParams()
p.profile = userProfile
p.peer = email
p.mid = random()
p.flag = FLAG_DELIVERYRECEIPT or FLAG_READRECEIPT
sendMessage(p, p.mid, message)
chatList.add(
ChatModel(
id = p.mid,
msg = edtSendChat.text.toString(),
date = getTimestamp(),
type = 1,
status = 0
)
)
chatListAdapter.notifyItemInserted(chatList.lastIndex)
layoutManager.scrollToPositionWithOffset(chatList.size - 1, 0)
edtSendChat.text?.clear()
}
private fun loadFromDb(address: String) {
setAppInForeground(this, ChatListActivity.hashCode(), true)
readSession = ReadDbSession(address, this)
readSession.enableReadReceipt(true)
readSession.enableCalls(false)
readSession.enableIncomingCalls(false)
readSession.enableMissedCalls(false)
readSession.enableOutgoingCalls(false)
readSession.enableFifo(true)
readSession.read(500)
}
private fun startMesibo() {
addListener(this)
setSecureConnection(true)
setAccessToken(userMesibo?.token)
setDatabase("db_mesibo", 0)
start()
userProfile = UserProfile()
userProfile?.address = email
setUserProfile(userProfile, true)
}
}
Any clue about how to resolve and debug?
this is my env:
Mesibo AP = 2.7.0
Build tools = 29.0.0
compile SDK versions = 30
appid = com.project.bucynapp
Thanks!
Have you tried the custom scripts or mesibo webhook to debug the issue? Have you referred to the Troubleshooting section in the mesibo push-notification document?
https://mesibo.com/documentation/api/push-notifications/
Unless you post logs and steps you have taken, we have no clue what is happening.
I would like to create and store new users also update the existing users in the following code
What code needs to be added to strore new users in a SQLitedatabase
I have a sqllitehelper class
which has adduser,updateuser,and readuser methods
From what i understand ,the signinfragment activity stores the instance of the logged in user and
if the instance exists then its loaded.When we logout we basically have to make a new user and we login
i would like to create,store,update users using an SQLite database.
package com.google.samples.apps.topeka.fragment
import android.annotation.TargetApi
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteDatabase
import android.os.Build
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.v4.app.ActivityOptionsCompat
import android.support.v4.app.Fragment
import android.support.v4.util.Pair
import android.support.v4.view.ViewCompat
import android.support.v4.view.animation.FastOutSlowInInterpolator
import android.text.Editable
import android.text.TextWatcher
import android.transition.Transition
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.EditText
import android.widget.GridView
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import com.google.samples.apps.topeka.activity.SignInActivity
import com.google.samples.apps.topeka.adapter.AvatarAdapter
import com.google.samples.apps.topeka.base.R
import com.google.samples.apps.topeka.helper.ActivityLaunchHelper
import com.google.samples.apps.topeka.helper.ApiLevelHelper
import com.google.samples.apps.topeka.helper.DefaultLogin
import com.google.samples.apps.topeka.helper.TAG
import com.google.samples.apps.topeka.helper.TransitionHelper
import com.google.samples.apps.topeka.helper.isLoggedIn
import com.google.samples.apps.topeka.helper.login
import com.google.samples.apps.topeka.helper.onLayoutChange
import com.google.samples.apps.topeka.helper.onSmartLockResult
import com.google.samples.apps.topeka.model.Avatar
import com.google.samples.apps.topeka.model.Player
import com.google.samples.apps.topeka.persistence.PPlayer
import com.google.samples.apps.topeka.widget.TextWatcherAdapter
import com.google.samples.apps.topeka.widget.TransitionListenerAdapter
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;
/**
* Enable selection of an [Avatar] and user name.
*/
class SignInFragment : Fragment() {
private var firstNameView: EditText? = null
private var lastInitialView: EditText? = null
private var doneFab: FloatingActionButton? = null
private var avatarGrid: GridView? = null
private var firstName = ""
private var lastInitial= ""
private var avatar = ""
private val edit by lazy { arguments?.getBoolean(ARG_EDIT, false) ?: false }
private var selectedAvatarView: View? = null
private var player: Player? = null
private var selectedAvatar: Avatar? = null
var a = getContext()
override fun onCreate(savedInstanceState: Bundle?) {
var a = context
val resources = context!!.resources
var ss = TopekaDatabaseHelper(requireActivity())
val newValues = ContentValues().apply {
// Sets the values of each column and inserts the value.
// The arguments to the "put"
// method are "column name" and "value"
}
if (savedInstanceState != null) {
val avatarIndex = savedInstanceState.getInt(KEY_SELECTED_AVATAR_INDEX)
if (avatarIndex != GridView.INVALID_POSITION) {
selectedAvatar = Avatar.values()[avatarIndex]
}
}
activity?.run {
if (isLoggedIn()) {
navigateToCategoryActivity()
Toast.makeText(requireContext(),"old", LENGTH_LONG)
} else {
maketext("new player")
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
super.onCreate(savedInstanceState)
}
/**
* Called when logged in successfully.
*/
private fun onSuccessfulLogin(player: Player) {
if (login != DefaultLogin) return
this.player = player
if (edit) {
with(player) {
firstNameView?.setText(player.firstName)
lastInitialView?.run {
setText(player.lastInitial)
requestFocus()
setSelection(length())
var db = TopekaDatabaseHelper(context)
db.adduser(player.firstName,player.lastInitial)
maketext("saved new")
}
this#SignInFragment.player = player.also {
if (activity != null)
login.savePlayer(activity!!, this, { selectAvatar(it.avatar!!) })
maketext("saved new")
}
}
} else {
Toast.makeText(requireContext(),"new", LENGTH_LONG)
navigateToCategoryActivity()
}
}
private fun maketext(ss:String){
Toast.makeText(requireContext(),ss,LENGTH_LONG)
}
private fun navigateToCategoryActivity() {
activity?.run {
ActivityLaunchHelper.launchCategorySelection(this)
supportFinishAfterTransition()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
activity?.onSmartLockResult(
requestCode,
resultCode,
data,
success = {
player = it
initContents()
navigateToCategoryActivity()
},
failure = {
activity?.run {
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
)
super.onActivityResult(requestCode, resultCode, data)
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val contentView = inflater.inflate(R.layout.fragment_sign_in, container, false)
contentView.onLayoutChange {
avatarGrid?.apply {
adapter = AvatarAdapter(activity!!)
onItemClickListener = AdapterView.OnItemClickListener { _, view, position, _ ->
selectedAvatarView = view
selectedAvatar = Avatar.values()[position]
// showing the floating action button if input data is valid
showFab()
}
numColumns = calculateSpanCount()
selectedAvatar?.run { selectAvatar(this) }
}
}
return contentView
}
/**
* Calculates spans for avatars dynamically.
* #return The recommended amount of columns.
*/
private fun calculateSpanCount(): Int {
val avatarSize = resources.getDimensionPixelSize(R.dimen.size_fab)
val avatarPadding = resources.getDimensionPixelSize(R.dimen.spacing_double)
return (avatarGrid?.width ?: 0) / (avatarSize + avatarPadding)
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(KEY_SELECTED_AVATAR_INDEX, (avatarGrid?.checkedItemPosition ?: 0))
super.onSaveInstanceState(outState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
firstNameView = view.findViewById<EditText>(R.id.first_name)
lastInitialView = view.findViewById<EditText>(R.id.last_initial)
doneFab = view.findViewById<FloatingActionButton>(R.id.done)
avatarGrid = view.findViewById<GridView>(R.id.avatars)
if (edit || (player != null && player!!.valid())) {
initContentViews()
initContents()
}
hideEmptyView()
super.onViewCreated(view, savedInstanceState)
}
private fun hideEmptyView() {
view?.run {
findViewById<View>(R.id.empty).visibility = View.GONE
findViewById<View>(R.id.content).visibility = View.VISIBLE
}
}
private fun initContentViews() {
val textWatcher = object : TextWatcher by TextWatcherAdapter {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
// hiding the floating action button if text is empty
if (s.isEmpty()) {
doneFab?.hide()
}
}
// showing the floating action button if avatar is selected and input data is valid
override fun afterTextChanged(s: Editable) {
if (isAvatarSelected() && isInputDataValid()) doneFab?.show()
}
}
firstNameView?.addTextChangedListener(textWatcher)
lastInitialView?.addTextChangedListener(textWatcher)
doneFab?.setOnClickListener {
if (it.id == R.id.done) {
val first = firstNameView?.text?.toString()
val last = lastInitialView?.text?.toString()
activity?.run {
val toSave = player?.apply {
// either update the existing player object
firstName = first
lastInitial = last
avatar = selectedAvatar
} ?: Player(first, last, selectedAvatar) /* or create a new one */
login.savePlayer(this, toSave) {
Toast.makeText(this,"done",LENGTH_LONG)
Log.d(TAG, "Saving login info successful.")
}
}
}
removeDoneFab {
performSignInWithTransition(selectedAvatarView
?: avatarGrid?.getChildAt(selectedAvatar!!.ordinal))
}
}
}
private fun removeDoneFab(endAction: () -> Unit) {
ViewCompat.animate(doneFab)
.scaleX(0f)
.scaleY(0f)
.setInterpolator(FastOutSlowInInterpolator())
.withEndAction(endAction)
.start()
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun performSignInWithTransition(v: View? = null) {
if (v == null || ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) {
// Don't run a transition if the passed view is null
activity?.run {
navigateToCategoryActivity()
}
return
}
if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
activity?.run {
window.sharedElementExitTransition.addListener(object :
Transition.TransitionListener by TransitionListenerAdapter {
override fun onTransitionEnd(transition: Transition) {
finish()
}
})
val pairs = TransitionHelper.createSafeTransitionParticipants(this, true,
Pair(v, getString(R.string.transition_avatar)))
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, *pairs)
ActivityLaunchHelper.launchCategorySelection(this, options)
}
}
}
private fun initContents() {
player?.run {
valid().let {
firstNameView?.setText(firstName)
lastInitialView?.setText(lastInitial)
avatar?.run { selectAvatar(this) }
}
}
}
private fun isAvatarSelected() = selectedAvatarView != null || selectedAvatar != null
private fun selectAvatar(avatar: Avatar) {
selectedAvatar = avatar
avatarGrid?.run {
requestFocusFromTouch()
setItemChecked(avatar.ordinal, true)
}
showFab()
}
private fun showFab() {
if (isInputDataValid()) doneFab?.show()
}
private fun isInputDataValid() =
firstNameView?.text?.isNotEmpty() == true &&
lastInitialView?.text?.isNotEmpty() == true &&
selectedAvatar != null
companion object {
private const val ARG_EDIT = "EDIT"
private const val KEY_SELECTED_AVATAR_INDEX = "selectedAvatarIndex"
fun newInstance(edit: Boolean = false): SignInFragment {
return SignInFragment().apply {
arguments = Bundle().apply {
putBoolean(ARG_EDIT, edit)
}
}
}
}
}
I have two screens first one has recycler view list of data and searchView above it that's filter data in this recycler, the view Model code of the first fragment
class MscInspectionViewModel(val activity: LaunchActivity, val mRootView: MscInspectFragment) :
BaseViewModel(),
SwipeRefreshLayout.OnRefreshListener {
val toolBarTitle: MutableLiveData<String> = MutableLiveData()
private val getDataError = MutableLiveData<Boolean>()
var listType = MutableLiveData<Int>()
val hint = MutableLiveData<String>()
private var isRefreshing: Boolean = false
private var mSharedPreferences: SharedPreferences? = null
val dataListAdapter = ContainersUnderCheckAdapter(activity)
val backClickListener = View.OnClickListener { activity.supportFragmentManager.popBackStack() }
val filterDataByTab = object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
when (tab!!.text) {
activity.resources.getString(R.string.cidPending) -> {
listType.value = 0
getPendingData()
}
activity.resources.getString(R.string.cidDone) -> {
listType.value = 1
getDoneData()
}
}
}
}
val filterData = object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
if (query.length > 2) {
val mQuery = Utility(activity).switchArabicNumerals(query)
dataListAdapter.getFilter(3, listType.value!!).filter(mQuery)
} else {
errorMessage.value = activity.resources.getString(R.string.addCorrectNumber)
}
return true
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.length > 2) {
val mQuery = Utility(activity).switchArabicNumerals(newText)
dataListAdapter.getFilter(3, listType.value!!).filter(mQuery)
}
return false;
}
}
val closeImgListener = View.OnClickListener {
mRootView.svSearchMSC.setQuery("", true)
if (listType.value == 1) {
dataListAdapter.getFilter(1, listType.value!!).filter("ANY")
} else if (listType.value == 0) {
dataListAdapter.getFilter(2, listType.value!!).filter("PENDING")
}
}
init {
listType.value = 0
mSharedPreferences = getDefaultSharedPreferences(activity.applicationContext)
toolBarTitle.value = activity.resources.getString(R.string.mscInspectTitle)
hint.value = activity.resources.getString(R.string.msc_search)
getData()
}
fun getData() {
onRetrievePostListStart()
subscription = apiAccount.getContainersUnderCheck(
"getContainersUnderCheck",
mSharedPreferences!!.getString(Constants.CFID, "")!!,
mSharedPreferences!!.getString(Constants.CFTOKEN, "")!!
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe {}
.doOnTerminate {}
.subscribe({ result ->
result?.let {
if (result.ResponseCode != null && result.ResponseCode.trim() != "000") {
onRetrievePostListError(result.ResponseMessage)
} else {
result.ContainersData?.let { it1 -> onRetrievePostListSuccess(it1) }
}
}
}, { throwable ->
android.util.Log.e("getDataInquiry", throwable.message!!)
onRetrievePostListError(activity.resources.getString(R.string.general_error))
})
}
private fun getPendingData() {
val query = mRootView.svSearchMSC.query.toString()
if (query == "") {
dataListAdapter.getFilter(2, listType.value!!).filter("PENDING")
} else {
if (query.length > 2) {
dataListAdapter.getFilter(3, listType.value!!).filter(query)
} else {
errorMessage.value = activity.resources.getString(R.string.addCorrectNumber)
}
}
}
private fun getDoneData() {
val query = mRootView.svSearchMSC.query.toString()
if (query == "") {
dataListAdapter.getFilter(1, listType.value!!).filter("ANY")
} else {
if (query.length > 2) {
dataListAdapter.getFilter(3, listType.value!!).filter(query)
} else {
errorMessage.value = activity.resources.getString(R.string.addCorrectNumber)
}
}
}
private fun onRetrievePostListStart() {
loading.value = true
}
private fun onRetrievePostListFinish() {
loading.value = false
isRefreshing = false
}
private fun onRetrievePostListSuccess(containersData: List<ContainersData>) {
onRetrievePostListFinish()
dataListAdapter.updateInquiryAdapter(containersData as ArrayList<ContainersData>)
if (listType.value == 1) {
dataListAdapter.getFilter(1, listType.value!!).filter("ANY")
} else if (listType.value == 0) {
dataListAdapter.getFilter(2, listType.value!!).filter("PENDING")
}
}
private fun onRetrievePostListError(message: String?) {
onRetrievePostListFinish()
getDataError.value = true
errorMessage.value = message
}
override fun onCleared() {
super.onCleared()
subscription.dispose()
}
override fun onRefresh() {
isRefreshing = true
getData()
}
}
adapter is :
class ContainersUnderCheckAdapter(val activity: LaunchActivity) :
RecyclerView.Adapter<ContainersUnderCheckAdapter.ViewHolder>() {
private lateinit var mDataSet: ArrayList<ContainersData>
private lateinit var mDataSetFiltered: ArrayList<ContainersData>
fun updateInquiryAdapter(dataSet: ArrayList<ContainersData>) {
mDataSet = ArrayList()
mDataSet.clear()
mDataSet.addAll(dataSet)
mDataSetFiltered = mDataSet
getFilter(2, 1).filter("PENDING")
// notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding: ContianerItemFieldLayoutBinding = DataBindingUtil
.inflate(
LayoutInflater.from(parent.context),
R.layout.contianer_item_field_layout,
parent,
false
)
return ViewHolder(binding, activity)
}
override fun getItemCount(): Int {
return if (::mDataSetFiltered.isInitialized) mDataSetFiltered.size else 0
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(mDataSetFiltered[position])
}
operator fun get(position: Int): ContainersData {
return mDataSetFiltered.get(position)
}
/**
* #filterType :
* IF 1 : filter on Data Type RJCTD + APPROVED
* 2 : filter on Data Type PENDING
* 3 :
*/
fun getFilter(filterType: Int, listType: Int): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
val charString = charSequence.toString()
mDataSetFiltered = if (charString.isEmpty()) {
mDataSet
} else {
val filteredList = ArrayList<ContainersData>()
for (row in mDataSet) {
when (filterType) {
1 -> {
if (row.status == "RJCTD" || row.status == "APPROVED") {
filteredList.add(row)
}
}
2 -> {
if (row.status == charString) {
filteredList.add(row)
}
}
3 -> {
when (listType) {
0 -> {
if ((row.CID!!.contains(charString.toUpperCase(Locale.ROOT)) || row.TN!!.contains(
charSequence
) || row.PN!!.contains(charSequence)) && row.status == "PENDING"
) {
filteredList.add(row)
}
}
1 -> {
if ((row.CID!!.contains(charString.toUpperCase(Locale.ROOT)) || row.TN!!.contains(
charSequence
) || row.PN!!.contains(charSequence)) && row.status != "PENDING"
) {
filteredList.add(row)
}
}
}
}
}
}
filteredList
}
val filterResults = FilterResults()
filterResults.values = mDataSetFiltered
return filterResults
}
override fun publishResults(
charSequence: CharSequence,
filterResults: FilterResults
) {
if (::mDataSetFiltered.isInitialized) {
mDataSetFiltered = try {
filterResults.values as ArrayList<ContainersData>
} catch (e: Exception) {
Log.e("mDataSetFiltered",e.message!!)
ArrayList()
}
when (filterType) {
1->{
mDataSetFiltered.sortWith(Comparator { p0, p1 -> p1!!.UpdateDate.compareTo(p0!!.UpdateDate) })
}
2->{
mDataSetFiltered.sortWith(Comparator { p0, p1 -> p0!!.ID!!.compareTo(p1.ID!!) })
}
}
}
// refresh the list with filtered data
notifyDataSetChanged()
}
}
}
class ViewHolder(
private val binding: ContianerItemFieldLayoutBinding,
val activity: LaunchActivity
) : RecyclerView.ViewHolder(binding.root) {
private val viewModel = MscInspectionListViewModel(activity)
fun bind(data: ContainersData) {
viewModel.bind(data)
binding.viewModel = viewModel
}
}
}
any data in this recycler on click go to fragment has tow recycler first one to show data, the second one to pick Images
the second-page code
class MSCDataFragment : Fragment() {
lateinit var rootView: View
lateinit var activity: LaunchActivity
lateinit var utility: Utility
lateinit var loadingView: LoadingView
private lateinit var viewModel: MSCDataViewModel
private lateinit var binding: FragmentMscdataBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (getActivity() != null) {
activity = getActivity() as LaunchActivity
utility = Utility(activity)
loadingView = LoadingView(activity)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_mscdata, container, false)
rootView = binding.root
initial()
return rootView
}
private fun initial() {
viewModel = ViewModelProvider(
this, ViewModelFactory(
activity,
arguments!!.getSerializable("Data") as ContainersData
)
).get(MSCDataViewModel::class.java)
binding.viewModel = viewModel
// binding.imgList.layoutManager = GridLayoutManager(activity, 3)
binding.containerInfo.layoutManager = LinearLayoutManager(activity)
binding.openCIDNotValid.typeface =
Typeface.createFromAsset(activity.assets, "Bahij_Janna-Regular.ttf")
binding.openCIDNotValid.setOnCheckedChangeListener(viewModel.onOpenCidNotValidListener)
viewModel.loading.observe(this, Observer { loading ->
loading?.let {
if (it) {
loadingView.show()
} else {
loadingView.dismiss()
}
}
})
viewModel.errorMessage.observe(this, Observer { msg ->
msg?.let {
utility.ShowToast(msg)
}
})
viewModel.imagesAdapters2.observe(this, Observer { msg ->
msg?.let {
binding.imgList.apply {
layoutManager = GridLayoutManager(activity, 3)
adapter = it
}
}
})
rootView.toolbar_Back.setOnClickListener(viewModel.backClickListener)
binding.btnAddImages.setOnClickListener(viewModel.pickImages)
binding.successContianer.setOnClickListener(viewModel.correctContainer)
binding.damagedContianer.setOnClickListener(viewModel.wrongContainer)
}
}
the view model is :
class MSCDataViewModel(val activity: LaunchActivity, val containersData: ContainersData) :
BaseViewModel(), GetImagesListener {
#Inject
lateinit var restApiAccount: RestApiAccount
val toolBarTitle: MutableLiveData<String> = MutableLiveData()
val ButtonText: MutableLiveData<String> = MutableLiveData()
var openCIDNotValidVisibility = MutableLiveData<Int>()
private val getDataError = MutableLiveData<Boolean>()
val btnImagesVisibility = MutableLiveData<Int>()
var imgeNoteVisibility = MutableLiveData<Int>()
var successVisibility = MutableLiveData<Int>()
var damagedVisibility = MutableLiveData<Int>()
var notesVisibility = MutableLiveData<Int>()
val btnVisibility = MutableLiveData<Int>()
var canNotOpen = MutableLiveData<Int>()
private val images = ArrayList<Image>()
var utility = Utility(activity)
private var CURRENTINDEX = 0
private var mSharedPreferences: SharedPreferences? = null
val DataListAdapter = ContainerDataAdapter(activity)
var imagesAdapter = ContainerImagesAdapter(activity, containersData.status!!, ArrayList())
val imagesAdapters2 = MutableLiveData<ContainerImagesAdapter2>()
val userInfo: UserInfo
val backClickListener = View.OnClickListener { activity.supportFragmentManager.popBackStack() }
val pickImages = View.OnClickListener {
pickImages()
}
val correctContainer = View.OnClickListener {}
val onOpenCidNotValidListener =
CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
successVisibility.value = View.GONE
canNotOpen.value = 1
} else {
canNotOpen.value = 0
successVisibility.value = View.VISIBLE
}
}
val wrongContainer = View.OnClickListener {}
var mscNotes: ObservableField<String> = ObservableField("")
init {
canNotOpen.value = 0
mSharedPreferences =
PreferenceManager.getDefaultSharedPreferences(activity.applicationContext)
toolBarTitle.value = containersData.CID
ButtonText.value = activity.resources.getString(R.string.cleanContianer)
userInfo = utility.readObjectFromSharedPreferences(
mSharedPreferences,
Constants.USER_INFO_KEY,
UserInfo::class.java
) as UserInfo
openCIDNotValidVisibility.value = View.GONE
fillData()
}
private fun fillData() {
val data: LinkedHashMap<String, String> = containersData.data!!
val captionsMap = utility.readObjectFromSharedPreferences(
mSharedPreferences, Constants.CAPTIONS_MAP_KEY,
HashMap::class.java
) as HashMap<String, String>
if (containersData.data.size > 0) {
val list = ArrayList<KeyValueModel>()
for (inside in data.keys) {
val ky = captionsMap[inside]
val value = data[inside].toString()
ky?.let { KeyValueModel(it, value) }?.let { list.add(it) }
}
DataListAdapter.updateInquiryAdapter(list)
} else {
errorMessage.value = activity.resources.getString(R.string.no_data)
}
if (containersData.ImageList != null && containersData.ImageList.isNotEmpty()) {
imagesAdapter.updateContainerImagesAdapter(containersData.ImageList)
}
}
private fun pickImages() {
activity.setCallBack(this)
val pictureDialog: AlertDialog
val builder = activity.let { AlertDialog.Builder(it) }
val dialogView = View.inflate(activity, R.layout.choose_camera_method, null)
builder.setView(dialogView)
val nafithPopupContainer = dialogView.findViewById<RelativeLayout>(R.id.RLTitle)
nafithPopupContainer.setBackgroundColor(
ContextCompat.getColor(
activity,
R.color.mainColor
)
)
val popUpGallery = dialogView.findViewById<LinearLayout>(R.id.PopupGellary)
val popUpCamera = dialogView.findViewById<LinearLayout>(R.id.PopupCamera)
pictureDialog = builder.create()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Objects.requireNonNull<Window>(pictureDialog.window)
.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
} else {
if (pictureDialog.window != null) {
pictureDialog.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
}
popUpGallery.setOnClickListener {
fromGallery()
pictureDialog.dismiss()
}
popUpCamera.setOnClickListener {
fromCamera()
pictureDialog.dismiss()
}
val popupClose = dialogView.findViewById<ImageView>(R.id.popupClose)
popupClose.setOnClickListener { pictureDialog.dismiss() }
pictureDialog.show()
}
private fun fromGallery() {
ImagePicker.create(activity)
.toolbarImageTitle(activity.resources.getString(R.string.get_image))
.toolbarArrowColor(ContextCompat.getColor(activity, R.color.colorWhite))
.showCamera(false)
.limit(6)
.start()
}
private fun fromCamera() {
ImagePicker.cameraOnly().start(activity)
}
override fun onGetImage(image: Image) {
imgeNoteVisibility.value = View.GONE
imagesAdapter.updateContainerImagesAdapter(image)
images.add(image)
}
override fun addingImagesDone(mImages: MutableList<Image>) {
images.clear()
images.addAll(mImages)
imgeNoteVisibility.value = View.GONE
val listString :ArrayList<String> = ArrayList()
for (i in mImages.indices){
listString.add(mImages[i].path)
}
imagesAdapters2.value = ContainerImagesAdapter2(activity,containersData.status!!,listString)
imagesAdapters2.value!!.notifyItemRangeChanged(0,listString.size)
}
override fun onImgDelete(image: String) {
var x = 0
try {
for (i in 0 until images.size) {
x = i
if (images[i].path == image) {
images.remove(images[i])
}
}
} catch (e: Exception) {
Log.e("errorImages", e.message!!)
Log.e("xx", x.toString())
}
}
private fun onRetrievePostListStart() {
loading.value = true
}
private fun onRetrievePostListFinish() {
loading.value = false
}
private fun onRetrievePostListSuccess(msg: String?) {
onRetrievePostListFinish()
}
private fun onRetrievePostListError(message: String?) {
onRetrievePostListFinish()
getDataError.value = true
errorMessage.value = message
}
}
Adapter code is :
class ContainerImagesAdapter2() : RecyclerView.Adapter<ContainerImagesAdapter2.ViewHolder>() {
var status: String = ""
lateinit var activity: LaunchActivity
lateinit var utility: Utility
constructor(
mActivity: LaunchActivity,
mStatus: String,
pathsList: ArrayList<String>
) : this() {
activity = mActivity
pathsDataSet = pathsList
status = mStatus
utility = Utility(activity)
}
private var pathsDataSet: ArrayList<String> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding: ContianerImageFieldBinding = DataBindingUtil
.inflate(
LayoutInflater.from(parent.context),
R.layout.contianer_image_field,
parent,
false
)
return ViewHolder(binding, activity)
}
override fun getItemCount(): Int {
return pathsDataSet.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindPath(pathsDataSet[position], position)
}
inner class ViewHolder(
private val binding: ContianerImageFieldBinding,
val activity: LaunchActivity
) : RecyclerView.ViewHolder(binding.root) {
private val viewModel = MscImagesListViewModel(activity)
fun bindPath(data: String, position: Int) {
viewModel.bindPath(data)
binding.viewModel = viewModel
if (status != "PENDING") {
binding.closeImg.visibility = View.GONE
}
binding.closeImg.setOnClickListener {}
binding.mainImg.setOnClickListener {
val fragment = FullImageFragment()
val bundle = Bundle()
val list = ArrayList<String>()
for (item in 0 until pathsDataSet.size) {
list.add(pathsDataSet[item])
}
bundle.putSerializable("ImageList", list)
bundle.putInt("Position", position)
fragment.arguments = bundle
activity.supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment).addToBackStack(fragment.tag)
.commit()
}
}
}
}
if you filter data using search view in the first-page and pick images in the second page , list of picked images doesn't appear, if you going to the second page without filtering data everything ok
solve Problem found
Just Update constraint-layout library in gradle dependencies to version '2.0.0-beta4'
package com.shivamkapila.echo.fragments
import android.app.Activity
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.media.AudioManager
import android.media.MediaPlayer
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.util.Log
import android.view.*
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import android.widget.Toast
import com.cleveroad.audiovisualization.AudioVisualization
import com.cleveroad.audiovisualization.DbmHandler
import com.cleveroad.audiovisualization.GLAudioVisualizationView
import com.shivamkapila.echo.CurrentSongHelper
import com.shivamkapila.echo.R
import com.shivamkapila.echo.Songs
import com.shivamkapila.echo.activities.MainActivity
import com.shivamkapila.echo.databases.EchoDatabase
import com.shivamkapila.echo.utils.SeekBarController
import java.util.*
import java.util.concurrent.TimeUnit
class SongPlayingFragment : Fragment() {
object Statified {
var myActivity: Activity? = null
var mediaPlayer: MediaPlayer? = null
var startTimeNext: TextView? = null
var endTimeNext: TextView? = null
var playPauseImageButton: ImageButton? = null
var previousImageButton: ImageButton? = null
var nextImageButton: ImageButton? = null
var loopImageButton: ImageButton? = null
var seekbar: SeekBar? = null
var songArtistView: TextView? = null
var songTitleView: TextView? = null
var shuffleImageButton: ImageButton? = null
var check: Boolean = true
var _currentPosition: Int = 0
var fetchSongs: ArrayList<Songs>? = null
var currentSongHelper: CurrentSongHelper? = null
var audioVisualization: AudioVisualization? = null
var glView: GLAudioVisualizationView? = null
var fab: ImageButton? = null
var favoriteContent: EchoDatabase? = null
var counter: Int = 0
var mSensorManager: SensorManager? = null
var mSensorListener: SensorEventListener? = null
var MY_PREFS_NAME = "ShakeFeature"
var back: String? = null
var updateSongTime = object : Runnable {
override fun run() {
try {
val getCurrent = Statified.mediaPlayer?.getCurrentPosition()
startTimeNext?.setText(String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(getCurrent?.toLong() as Long),
TimeUnit.MILLISECONDS.toSeconds(getCurrent?.toLong() as Long) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(getCurrent?.toLong() as Long))))
seekbar?.setProgress(getCurrent?.toInt() as Int)
Statified.check = true
Handler().postDelayed(this, 1000)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
object Staticated {
var MY_PREFS_SHUFFLE = "Shuffle feature"
var MY_PREFS_LOOP = "Loop feature"
fun onSongComplete() {
if (Statified.currentSongHelper?.isShuffle as Boolean) {
playNext("PlayNextLikeNormalShuffle")
Statified.currentSongHelper?.isPlaying = true
} else {
if (Statified.currentSongHelper?.isLoop as Boolean) {
Statified.currentSongHelper?.isPlaying = true
var nextSong = Statified.fetchSongs?.get(Statified._currentPosition)
Statified.currentSongHelper?.songPath = nextSong?.songData
Statified.currentSongHelper?.songTitle = nextSong?.songTitle
Statified.currentSongHelper?.songArtist = nextSong?.artist
Statified.currentSongHelper?.songId = nextSong?.songID as Long
Statified.currentSongHelper?.currentPosition = Statified._currentPosition
updateTextViews(Statified.currentSongHelper?.songTitle as String, Statified.currentSongHelper?.songArtist as String)
Statified.mediaPlayer?.reset()
try {
Statified.mediaPlayer?.setDataSource(Statified.myActivity, Uri.parse(Statified.currentSongHelper?.songPath) as Uri)
Statified.mediaPlayer?.prepare()
Statified.mediaPlayer?.start()
processInformation(Statified.mediaPlayer as MediaPlayer)
} catch (e: Exception) {
e.printStackTrace()
}
} else {
playNext("PlayNextNormal")
Statified.currentSongHelper?.isPlaying = true
}
}
if (Statified.favoriteContent?.checkifIdExists(Statified.currentSongHelper?.songId?.toInt() as Int) as Boolean) {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_on))
} else {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_off))
}
}
fun updateTextViews(songTitle: String, songArtist: String) {
var songTitleUpdated = songTitle
var songArtistUpdated = songArtist
if (songTitle.equals("<unknown>", true)) {
songTitleUpdated = "unknown"
}
if (songArtist.equals("<unknown>", true)) {
songArtistUpdated = "unknown"
}
Statified.songTitleView?.setText(songTitleUpdated)
Statified.songArtistView?.setText(songArtistUpdated)
}
fun processInformation(mediaPlayer: MediaPlayer) {
val finalTime = mediaPlayer.duration
val startTime = mediaPlayer.currentPosition
Statified.seekbar?.max = finalTime
Statified.startTimeNext?.setText(String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(startTime.toLong()),
TimeUnit.MILLISECONDS.toSeconds(startTime.toLong()) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(startTime.toLong()))))
Statified.endTimeNext?.setText(String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(finalTime.toLong()),
TimeUnit.MILLISECONDS.toSeconds(finalTime.toLong()) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(finalTime.toLong()))))
Statified.seekbar?.setProgress(startTime)
Handler().postDelayed(Statified.updateSongTime, 1000)
}
fun playNext(check: String) {
if (check.equals("PlayNextNormal", true)) {
Statified._currentPosition = Statified._currentPosition + 1
} else if (check.equals("PlayNextLikeNormalShuffle", true)) {
var randomObject = Random()
var randomPosition = randomObject.nextInt(Statified.fetchSongs?.size?.plus(1) as Int)
Statified._currentPosition = randomPosition
}
if (Statified._currentPosition == Statified.fetchSongs?.size) {
Statified._currentPosition = 0
}
Statified.currentSongHelper?.isLoop = false
var nextSong = Statified.fetchSongs?.get(Statified._currentPosition)
Statified.currentSongHelper?.songPath = nextSong?.songData
Statified.currentSongHelper?.songTitle = nextSong?.songTitle
Statified.currentSongHelper?.songArtist = nextSong?.artist
Statified.currentSongHelper?.songId = nextSong?.songID as Long
Statified.currentSongHelper?.currentPosition = Statified._currentPosition
var editorLoop = Statified.myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)?.edit()
Statified.currentSongHelper?.isLoop = false
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
editorLoop?.putBoolean("feature", false)
editorLoop?.apply()
if (Statified.currentSongHelper?.isPlaying as Boolean) {
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
} else {
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.play_icon)
}
updateTextViews(Statified.currentSongHelper?.songTitle as String, Statified.currentSongHelper?.songArtist as String)
Statified.mediaPlayer?.reset()
try {
Statified.mediaPlayer?.setDataSource(Statified.myActivity, Uri.parse(Statified.currentSongHelper?.songPath) as Uri)
Statified.mediaPlayer?.prepare()
Statified.mediaPlayer?.start()
Staticated.processInformation(Statified.mediaPlayer as MediaPlayer)
processInformation(Statified.mediaPlayer as MediaPlayer)
} catch (e: Exception) {
e.printStackTrace()
}
if (Statified.favoriteContent?.checkifIdExists(Statified.currentSongHelper?.songId?.toInt() as Int) as Boolean) {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_on))
} else {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_off))
}
}
fun playPrevious() {
Statified._currentPosition = Statified._currentPosition - 1
if (Statified._currentPosition == -1) {
Statified._currentPosition = 0
}
if (Statified.currentSongHelper?.isPlaying as Boolean) {
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
} else {
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.play_icon)
}
Statified.currentSongHelper?.isLoop = false
var nextSong = Statified.fetchSongs?.get(Statified._currentPosition)
Statified.currentSongHelper?.songPath = nextSong?.songData
Statified.currentSongHelper?.songTitle = nextSong?.songTitle
Statified.currentSongHelper?.songArtist = nextSong?.artist
Statified.currentSongHelper?.songId = nextSong?.songID as Long
Statified.currentSongHelper?.currentPosition = Statified._currentPosition
Staticated.updateTextViews(Statified.currentSongHelper?.songTitle as String, Statified.currentSongHelper?.songArtist as String)
Statified.mediaPlayer?.reset()
try {
Statified.mediaPlayer?.setDataSource(Statified.myActivity, Uri.parse(Statified.currentSongHelper?.songPath) as Uri)
Statified.mediaPlayer?.prepare()
Statified.mediaPlayer?.start()
Staticated.processInformation(Statified.mediaPlayer as MediaPlayer)
processInformation(Statified.mediaPlayer as MediaPlayer)
} catch (e: Exception) {
e.printStackTrace()
}
if (Statified.favoriteContent?.checkifIdExists(Statified.currentSongHelper?.songId?.toInt() as Int) as Boolean) {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_on))
} else {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_off))
}
}
}
var mAcceleration: Float = 0f
var mAccelerationCurrent: Float = 0f
var mAccelerationLast: Float = 0f
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater!!.inflate(R.layout.fragment_song_playing, container, false)
setHasOptionsMenu(true)
activity.title = "Now Playing"
Statified.seekbar = view?.findViewById(R.id.seekBar)
Statified.startTimeNext = view?.findViewById(R.id.startTime)
Statified.endTimeNext = view?.findViewById(R.id.endTime)
Statified.playPauseImageButton = view?.findViewById(R.id.playPauseButton)
Statified.nextImageButton = view?.findViewById(R.id.nextButton)
Statified.previousImageButton = view?.findViewById(R.id.previousButton)
Statified.loopImageButton = view?.findViewById(R.id.loopButton)
Statified.shuffleImageButton = view?.findViewById(R.id.shuffleButton)
Statified.songArtistView = view?.findViewById(R.id.songArtist)
Statified.songTitleView = view?.findViewById(R.id.songTitle)
Statified.glView = view?.findViewById(R.id.visualizer_view)
Statified.fab = view?.findViewById(R.id.favoriteIcon)
Statified.fab?.alpha = 0.8f
return view
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Statified.audioVisualization = Statified.glView as AudioVisualization
}
override fun onAttach(context: Context?) {
super.onAttach(context)
Statified.myActivity = context as Activity
}
override fun onAttach(activity: Activity?) {
super.onAttach(activity)
Statified.myActivity = activity
}
override fun onResume() {
super.onResume()
Statified.audioVisualization?.onResume()
Statified.mSensorManager?.registerListener(Statified.mSensorListener, Statified.mSensorManager?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL)
}
override fun onPause() {
Statified.audioVisualization?.onPause()
Statified.mSensorManager?.unregisterListener(Statified.mSensorListener)
super.onPause()
}
override fun onDestroyView() {
super.onDestroyView()
Statified.audioVisualization?.release()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Statified.currentSongHelper = CurrentSongHelper()
Statified.currentSongHelper?.isPlaying = true
Statified.currentSongHelper?.isLoop = false
Statified.currentSongHelper?.isShuffle = false
Statified.favoriteContent = EchoDatabase(Statified.myActivity)
var path: String? = null
var _songTitle: String? = null
var _songArtist: String? = null
var songId: Long = 0
var fromFavBottomBar: String? = null
var fromMainScreenBottomBar: String? = null
try {
path = arguments.getString("path")
_songTitle = arguments.getString("songTitle")
_songArtist = arguments.getString("songArtist")
songId = arguments.getInt("songId").toLong()
Statified._currentPosition = arguments.getInt("songPosition")
Statified.fetchSongs = arguments.getParcelableArrayList("songData")
Statified.currentSongHelper?.songPath = path
Statified.currentSongHelper?.songTitle = _songTitle
Statified.currentSongHelper?.songArtist = _songArtist
Statified.currentSongHelper?.songId = songId
Statified.currentSongHelper?.currentPosition = Statified._currentPosition
fromFavBottomBar = arguments.get("FavBottomBar") as? String
fromMainScreenBottomBar = arguments.get("MainScreenBottomBar") as? String
Staticated.updateTextViews(Statified.currentSongHelper?.songTitle as String, Statified.currentSongHelper?.songArtist as String)
} catch (e: Exception) {
e.printStackTrace()
}
if (fromFavBottomBar != null) {
Statified.mediaPlayer = FavoriteFragment.Statified.mediaPlayer
Staticated.processInformation(Statified.mediaPlayer as MediaPlayer)
} else if (fromMainScreenBottomBar != null) {
Statified.mediaPlayer = MainScreenFragment.Statified.mediaPlayer
Staticated.processInformation(Statified.mediaPlayer as MediaPlayer)
} else {
Statified.mediaPlayer = MediaPlayer()
Statified.mediaPlayer?.setAudioStreamType(AudioManager.STREAM_MUSIC)
try {
Statified.mediaPlayer?.setDataSource(Statified.myActivity, Uri.parse(path) as Uri)
Statified.mediaPlayer?.prepare()
} catch (e: Exception) {
e.printStackTrace()
}
Statified.mediaPlayer?.start()
Staticated.processInformation(Statified.mediaPlayer as MediaPlayer)
}
Staticated.processInformation(Statified.mediaPlayer as MediaPlayer)
if (Statified.mediaPlayer?.isPlaying as Boolean) {
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
} else {
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.play_icon)
}
Statified.mediaPlayer?.setOnCompletionListener {
Staticated.onSongComplete()
}
clickHandler()
var visualizationHandler = DbmHandler.Factory.newVisualizerHandler(Statified.myActivity as Context, 0)
Statified.audioVisualization?.linkTo(visualizationHandler)
var prefsForShuffle = Statified.myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)
var isShuffleAllowed = prefsForShuffle?.getBoolean("feature", false)
if (isShuffleAllowed as Boolean) {
Statified.currentSongHelper?.isShuffle = true
Statified.currentSongHelper?.isLoop = false
Statified.shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_icon)
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
} else {
Statified.currentSongHelper?.isShuffle = false
Statified.shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
}
var prefsForLoop = Statified.myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)
var isLoopAllowed = prefsForLoop?.getBoolean("feature", false)
if (isLoopAllowed as Boolean) {
Statified.currentSongHelper?.isShuffle = false
Statified.currentSongHelper?.isLoop = true
Statified.shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_icon)
} else {
Statified.currentSongHelper?.isLoop = false
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
}
if (Statified.favoriteContent?.checkifIdExists(Statified.currentSongHelper?.songId?.toInt() as Int) as Boolean) {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_on))
} else {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_off))
}
seekbarHandler()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Statified.mSensorManager = Statified.myActivity?.getSystemService(Context.SENSOR_SERVICE) as SensorManager
mAcceleration = 0.0f
mAccelerationCurrent = SensorManager.GRAVITY_EARTH
mAccelerationLast = SensorManager.GRAVITY_EARTH
bindShakeListener()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.song_playing_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onPrepareOptionsMenu(menu: Menu?) {
super.onPrepareOptionsMenu(menu)
val item: MenuItem? = menu?.findItem(R.id.action_redirect)
item?.isVisible = true
val item2: MenuItem? = menu?.findItem(R.id.action_sort)
item2?.isVisible = false
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
R.id.action_redirect -> {
var pos = 0
if (Statified.back.equals("Favorite", true)) {
pos = 0
}
if (Statified.back.equals("MainScreen", true)) {
pos = 1
}
if (pos == 1) {
val mainScreenFragment = MainScreenFragment()
(context as MainActivity).supportFragmentManager
.beginTransaction()
.replace(R.id.details_fragment, mainScreenFragment)
.commit()
}
if (pos == 0) {
val favoriteFragment = FavoriteFragment()
(context as MainActivity).supportFragmentManager
.beginTransaction()
.replace(R.id.details_fragment, favoriteFragment)
.commit()
}
return false
}
}
return false
}
fun clickHandler() {
Statified.fab?.setOnClickListener({
if (Statified.favoriteContent?.checkifIdExists(Statified.currentSongHelper?.songId?.toInt() as Int) as Boolean) {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_off))
Statified.favoriteContent?.deleteFavourite(Statified.currentSongHelper?.songId?.toInt() as Int)
Toast.makeText(Statified.myActivity, "Removed from favorites", Toast.LENGTH_SHORT).show()
} else {
Statified.fab?.setImageDrawable(ContextCompat.getDrawable(Statified.myActivity, R.drawable.favorite_on))
Statified.favoriteContent?.storeAsFavorite(Statified.currentSongHelper?.songId?.toInt(), Statified.currentSongHelper?.songArtist,
Statified.currentSongHelper?.songTitle, Statified.currentSongHelper?.songPath)
Toast.makeText(Statified.myActivity, "Added to Favorites", Toast.LENGTH_SHORT).show()
}
})
Statified.shuffleImageButton?.setOnClickListener({
var editorShuffle = Statified.myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)?.edit()
var editorLoop = Statified.myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)?.edit()
if (Statified.currentSongHelper?.isShuffle as Boolean) {
Statified.currentSongHelper?.isShuffle = false
Statified.shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
editorShuffle?.putBoolean("feature", false)
editorShuffle?.apply()
} else {
Statified.currentSongHelper?.isLoop = false
Statified.currentSongHelper?.isShuffle = true
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
Statified.shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_icon)
editorShuffle?.putBoolean("feature", true)
editorShuffle?.apply()
editorLoop?.putBoolean("feature", false)
editorLoop?.apply()
}
})
Statified.nextImageButton?.setOnClickListener({
Statified.currentSongHelper?.isPlaying = true
if (Statified.currentSongHelper?.isLoop as Boolean) {
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
}
if (Statified.currentSongHelper?.isShuffle as Boolean) {
Staticated.playNext("PlayNextLikeNormalShuffle")
} else {
Staticated.playNext("PlayNextNormal")
}
})
Statified.previousImageButton?.setOnClickListener({
Statified.currentSongHelper?.isPlaying = true
if (Statified.currentSongHelper?.isLoop as Boolean) {
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
}
Staticated.playPrevious()
})
Statified.loopImageButton?.setOnClickListener({
var editorShuffle = Statified.myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)?.edit()
var editorLoop = Statified.myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)?.edit()
if (Statified.currentSongHelper?.isLoop as Boolean) {
Statified.currentSongHelper?.isLoop = false
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
editorLoop?.putBoolean("feature", false)
editorLoop?.apply()
} else {
Statified.currentSongHelper?.isLoop = true
Statified.currentSongHelper?.isShuffle = false
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_icon)
Statified.shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
editorLoop?.putBoolean("feature", true)
editorLoop?.apply()
editorShuffle?.putBoolean("feature", false)
editorShuffle?.apply()
}
})
Statified.playPauseImageButton?.setOnClickListener({
if (Statified.mediaPlayer?.isPlaying as Boolean) {
Statified.mediaPlayer?.pause()
Statified.currentSongHelper?.isPlaying = false
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.play_icon)
} else {
Statified.mediaPlayer?.start()
Statified.currentSongHelper?.isPlaying = true
Statified.playPauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
Staticated.processInformation(Statified.mediaPlayer as MediaPlayer)
}
})
}
fun bindShakeListener() {
Statified.mSensorListener = object : SensorEventListener {
override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
}
override fun onSensorChanged(p0: SensorEvent) {
val x = p0.values[0]
val y = p0.values[1]
val z = p0.values[2]
mAccelerationLast = mAccelerationCurrent
mAccelerationCurrent = Math.sqrt(((x * x + y * y + z * z).toDouble())).toFloat()
val delta = mAccelerationCurrent - mAccelerationLast
mAcceleration = mAcceleration * 0.9f + delta
if (mAcceleration > 12) {
println("11111")
val prefs = Statified.myActivity?.getSharedPreferences(Statified.MY_PREFS_NAME, Context.MODE_PRIVATE)
val isAllowed = prefs?.getBoolean("feature", false)
if (isAllowed as Boolean && Statified.check == true) {
Statified.currentSongHelper?.isPlaying = true
if (Statified.currentSongHelper?.isLoop as Boolean) {
Statified.loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
}
if (Statified.currentSongHelper?.isShuffle as Boolean) {
Staticated.playNext("PlayNextLikeNormalShuffle")
} else {
Staticated.playNext("PlayNextNormal")
}
Statified.check = false
}
}
}
}
}
fun seekbarHandler() {
val seekbarListener = SeekBarController()
Statified.seekbar?.setOnSeekBarChangeListener(seekbarListener)
}
Let try this ,
This is java code Just u can convert to kotlin it will work fine.
In your Activity
Declare a static variable
public static boolean IS_MUSIC_SCREEN = false;
Implement this method
#Override
public void onBackPressed() {
if (IS_MUSIC_SCREEN) {
IS_MUSIC_SCREEN=false;
startActivity(new Activity(this,MainActivity.class));
}else{
super.onBackPressed();
}
}
In your Fragment,
IS_MUSIC_SCREEN is true set in onCreateView
Like this ,
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_song_playing, container, false);
MainActivity.IS_MUSIC_SCREEN =true;
return view;
}
A simple approach would be to initialise a BackHandler mechanism with the Fragment. I have such an approach with my BaseFragment class that would return a boolean to true if the back action is to be handled by the fragment instead of activity. For this you can have a custom LifecycleAdapter:
interface LifecycleAdapter {
fun onBackPressed() : Boolean = false
// add other methods like onActivityResult or similar
// if needed that is to be delegated to the fragment
}
Now in the BaseActivity you would have 2 functions one for addingFragment and a register function for MutableList<WeakReference<LifecycleAdapter>>
open class BaseActivity : AppCompatActivity() { // which ever type
protected open val lifecycleReferrals : MutableList<WeakReference<LifecycleAdapter>> = mutableListOf()
fun addFragment(fragment: BaseFragment,
#IdRes containerId: Int = R.id.fragment_container,
replace: Boolean = true,
addToBackstack: Boolean = false) {
supportFragmentManager?.beginTransaction()?.run {
if (addToBackstack){
addToBackStack(fragment.javaClass.simpleName)
}
if (replace) {
replace(containerId, fragment) // add tag when needed
} else {
add(containerId, fragment)
}
registerLifecycleReferrals(fragment)
commit()
}
}
fun registerLifecycleReferrals(adapter: LifecycleAdapter){
lifecycleReferrals.add(WeakReference(adapter))
}
override fun onBackPressed() {
if (lifecycleReferrals.none { it.get()?.onBackPressed(0) == true }) {
super.onBackPressed()
}
}
}
when ever you need a any class accessing the controller methods like onBackPressed() you can implement the interface in the required class and call registerLifecycleReferrals(obj) from the activity.
Now your base fragment class would be:
open class BaseFragment : Fragment(), LifecycleAdapter{
// have parent level constructs and implementation
// that would serve you well across the entire project
}
and your current fragment can be:
class SongPlayingFragment : BaseFragment() {
// do all fragment inits and override methods
override fun onBackPressed(): Boolean {
if (Statified.currentSongHelper?.isPlaying == true) {
// handle the call and switch to MainScreenActivity
context?.apply {
startActivity<MainScreenActivity>() // anko extension
return true
}
}
return super.onBackPressed()
}
}
Note: The adapters are weak referenced in the BaseActivity class because if the Fragment undergoes a destruction process it can be easily freed up by the GC and list wouldn't withhold the reference to it.