Exo player fast scroll playing video sound mixed - android

I am using exoplayer for playing videos .And for this we are used Fragment instance with pagerstateadapter and viewpager2.
But when scroll fast previous played video sound listen in background as well as in screen video means mix the sound in same video player.
Please help me how to solve this.
1.State adapter
class StoriesPagerAdapter(
fragment: Fragment,
val onClick1: VideoItemAdapter.OnItemClicked?,
val onlikeClick: VideoItemAdapter.OnLikeCLicked?,
val onFollowClick: VideoItemAdapter.OnFollowCLicked?,
val ontrendingClick: VideoItemAdapter.OnTrendCLicked?,
val oniconCLick: VideoItemAdapter.OnIconClick?) : FragmentStateAdapter(fragment) {
val dataList:MutableList<Gettrendingvideos.Data.Postlist>=mutableListOf()
override fun getItemCount(): Int {
return dataList.size
}
fun addAll(movies: MutableList<Gettrendingvideos.Data.Postlist>) {
for (movie in movies) {
add(movie)
}
}
fun add(moive: Gettrendingvideos.Data.Postlist) {
dataList.add(moive)
notifyItemInserted(dataList.size - 1)
}
override fun createFragment(position: Int): Fragment {
return StoryViewFragment.newInstance(
onClick1,
onlikeClick,
onFollowClick,
ontrendingClick,
oniconCLick,
dataList[position]
)
}}
2 Fragment
class StoryViewFragment : Fragment(), CommentFragment.onCommentCountIncrease {
private var storyUrl: String? = null
private var storiesDataModel: Gettrendingvideos.Data.Postlist? = null
lateinit var mView: View
private var simplePlayer: SimpleExoPlayer? = null
private var cacheDataSourceFactory: CacheDataSourceFactory? = null
private val simpleCache = MainApplication.simpleCache
private var toPlayVideoPosition: Int = -1
lateinit var viewModel: MainViewModel
lateinit var preferences: SecurePreferences
private var bool: Boolean? = false
var onItemClick: VideoItemAdapter.OnItemClicked? = null
var onlikeCLicked: VideoItemAdapter.OnLikeCLicked? = null
var onFollowCLicked: VideoItemAdapter.OnFollowCLicked? = null
var onTrendCLicked: VideoItemAdapter.OnTrendCLicked? = null
var onIconClick: VideoItemAdapter.OnIconClick? = null
lateinit var huserId: String
lateinit var token: String
companion object {
fun newInstance(
itemClicked: VideoItemAdapter.OnItemClicked?,
likeCLicked: VideoItemAdapter.OnLikeCLicked?,
onFollowCLicked: VideoItemAdapter.OnFollowCLicked?,
onTrendCLicked: VideoItemAdapter.OnTrendCLicked?,
onIconClick: VideoItemAdapter.OnIconClick?,
storiesDataModel: Gettrendingvideos.Data.Postlist
) = StoryViewFragment()
.apply {
arguments = Bundle().apply {
putParcelable(Constants.KEY_STORY_DATA, storiesDataModel)
}
this.onItemClick = itemClicked
this.onlikeCLicked = likeCLicked
this.onFollowCLicked = onFollowCLicked
this.onTrendCLicked = onTrendCLicked
this.onIconClick = onIconClick
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
mView = inflater.inflate(
R.layout.layout_main,
container,
false
)
return mView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProviders.of(this, ViewModelFactory(RetrofitBuilder.apiService))
.get(MainViewModel::class.java)
preferences =
SecurePreferences(
requireActivity(),
AppConstants.preferenceName,
AppConstants.USER_DETAILS,
true
)
storiesDataModel = arguments?.getParcelable(Constants.KEY_STORY_DATA)
setData()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (!preferences.getString(AppConstants.USER_ID).equals(null)) {
huserId = preferences.getString(AppConstants.USER_ID)!!
Log.d("TAG", "onActivityCreated: $huserId")
}
}
#SuppressLint("SetTextI18n")
private fun setData() {
Log.d("TAG", "setData: $storiesDataModel")
mView.textview2.text = storiesDataModel?.user_name
mView.like_count.text = storiesDataModel?.total_likes.toString()
comment_count.text = storiesDataModel?.total_comments.toString()
mView.textview.text = storiesDataModel?.type
Glide.with(this).load(storiesDataModel?.user_profile_pic).placeholder(R.drawable.profile).into(mView.image)
if (storiesDataModel?.is_like == 0) {
mView.imageView4.setImageResource(R.drawable.ic_like)
} else {
mView.imageView4.setImageResource(R.drawable.ic_like_red)
}
if (storiesDataModel?.is_following!! == 0) {
mView.textview3.text = "Follow"
} else {
mView.textview3.text = "Following"
}
if (storiesDataModel?.user_id.toString()==preferences.getString(AppConstants.USER_ID)) {
mView.textview3.visibility = View.GONE
}
image.setOnClickListener {
if (preferences.getString(AppConstants.token).equals(null)) {
MainActivity().show(childFragmentManager, "")
} else {
preferences.put(
AppConstants.OtherProfile_UserId,
storiesDataModel?.user_id.toString()
)
}
}
val simplePlayer = getPlayer()
player_view_story.player = simplePlayer player_view_story.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL)
simplePlayer?.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING)
storyUrl = storiesDataModel?.video_url
prepareMedia(storiesDataModel)
}
override fun onPause() {
pauseVideo()
super.onPause()
}
override fun onResume() {
restartVideo()
super.onResume()
}
override fun onDestroy() {
releasePlayer()
super.onDestroy()
}
private fun pausePlayer() {
simplePlayer?.setPlayWhenReady(false)
simplePlayer?.getPlaybackState()
}
private fun startPlayer() {
simplePlayer?.setPlayWhenReady(true)
simplePlayer?.getPlaybackState()
}
private val playerCallback: Player.EventListener? = object : Player.EventListener {
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
}
override fun onPlayerError(error: com.google.android.exoplayer2.ExoPlaybackException?) {
super.onPlayerError(error)
}
}
private fun prepareVideoPlayer() {
simplePlayer = ExoPlayerFactory.newSimpleInstance(context)
cacheDataSourceFactory = CacheDataSourceFactory(
simpleCache,
DefaultHttpDataSourceFactory(
Util.getUserAgent(
context,
"exo"
)
)
)
}
private fun getPlayer(): SimpleExoPlayer? {
if (simplePlayer == null) {
prepareVideoPlayer()
}
return simplePlayer
}
private fun prepareMedia(datamodel: Gettrendingvideos.Data.Postlist?{
val uri = Uri.parse(datamodel?.video_url)
simplePlayer.repeatMode = Player.REPEAT_MODE_ONE
simplePlayer.playWhenReady = true
if (storiesDataModel!!.type == "following") {
following_page.typeface = Typeface.DEFAULT_BOLD
trending_page.setTypeface(null, Typeface.NORMAL)
} else {
following_page.setTypeface(null, Typeface.BOLD)
}
if (storiesDataModel.type == "treading") {
trending_page.typeface = Typeface.DEFAULT_BOLD
following_page.setTypeface(null, Typeface.NORMAL)
} else {
trending_page.setTypeface(null, Typeface.BOLD)
}
if (simplePlayer.playWhenReady == true) {
}
simplePlayer.addListener(playerCallback)
toPlayVideoPosition = -1
}
private fun setArtwork(drawable: Drawable, playerView: PlayerView) {
playerView.useArtwork = true
playerView.defaultArtwork = drawable
}
private fun playVideo() {
simplePlayer.playWhenReady = true
}
private fun restartVideo() {
if (simplePlayer == null) {
prepareMedia(storiesDataModel)
} else {
simplePlayer.seekToDefaultPosition()
simplePlayer.playWhenReady = true
}
}
private fun pauseVideo() {
simplePlayer.playWhenReady = false
}
private fun releasePlayer() {
simplePlayer.stop(true)
simplePlayer.release()
}}

override fun setMenuVisibility(menuVisible: Boolean) {
if (!menuVisible){
simplePlayer?.playWhenReady = false
simplePlayer?.pause()
}
super.setMenuVisibility(menuVisible)
}
JUST ADD THIS IN YOUR StoryViewFragment.

Related

How to make a check for entering the correct city when entering

I have a way where when I enter the name of the city, I substitute the name of the city in the api, and everything works fine, but if I enter a non-real city, then nonsense is put in the api accordingly and the application crashes. I would like to make it so that if the city does not exist, that is, I output an error, then Toast "enter the correct name of the city" appears. Thank you in advance
Код:
const val USE_DEVICE_LOCATION = "USE_DEVICE_LOCATION"
const val CUSTOM_LOCATION = "CUSTOM_LOCATION"
class LocationProviderImpl(
private val fusedLocationProviderClient: FusedLocationProviderClient,
context: Context) : PreferenceProvider(context), LocationProvider {
private val appContext = context.applicationContext
override suspend fun hasLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
val deviceLocationChanged = try {
hasDeviceLocationChanged(lastWeatherLocation)
} catch (e: LocationPermissionNotGrantedException) {
false
}
return deviceLocationChanged || hasCustomLocationChanged(lastWeatherLocation)
}
override suspend fun getPreferredLocationString(): String {
if(isUsingDeviceLocation()) {
try {
val deviceLocation = getLastDeviceLocation()
?: return "${getCustomLocationName()}"
return "${deviceLocation.latitude},${deviceLocation.longitude}"
} catch (e: LocationPermissionNotGrantedException) {
return "${getCustomLocationName()}"
}
}
else {
return "${getCustomLocationName()}"
}
}
private suspend fun hasDeviceLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
if (!isUsingDeviceLocation())
return false
val deviceLocation = getLastDeviceLocation()
?: return false
// Comparing doubles cannot be done with "=="
val comparisonThreshold = 0.03
return Math.abs(deviceLocation.latitude - lastWeatherLocation.lat) > comparisonThreshold &&
Math.abs(deviceLocation.longitude - lastWeatherLocation.lon) > comparisonThreshold
}
private fun hasCustomLocationChanged(lastWeatherLocation: WeatherLocation): Boolean {
if (!isUsingDeviceLocation()) {
val customLocationName = getCustomLocationName()
return customLocationName != lastWeatherLocation.name
}
return false
}
private fun getCustomLocationName(): String? {
try {
return preferences.getString(CUSTOM_LOCATION, null)
}
catch (e: Exception) {
isUsingDeviceLocation()
}
throw LocationPermissionNotGrantedException()
}
private fun isUsingDeviceLocation(): Boolean {
return preferences.getBoolean(USE_DEVICE_LOCATION, true)
}
#SuppressLint("MissingPermission")
private suspend fun getLastDeviceLocation(): Location? {
return (if (hasLocationPermission())
fusedLocationProviderClient.lastLocation.asDeferred()
else {
throw LocationPermissionNotGrantedException()
}).await()
}
private fun hasLocationPermission(): Boolean {
return ContextCompat.checkSelfPermission(appContext,
android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
}
CurrentWeatherFragment
class CurrentWeatherFragment : ScopedFragment(), KodeinAware, SharedPreferences.OnSharedPreferenceChangeListener {
override val kodein by closestKodein()
private val viewModelFactory: CurrentWeatherViewModelFactory by instance()
private lateinit var viewModel: CurrentWeatherViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.current_weather_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
loadBannerAd()
viewModel = ViewModelProvider(this, viewModelFactory)
.get(CurrentWeatherViewModel::class.java)
bindUI()
applyDarkModeSetting()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
private fun loadBannerAd() {
MobileAds.initialize(context) {}
mAdViewCurrent = adView
val adRequest = AdRequest.Builder().build()
mAdViewCurrent.loadAd(adRequest)
mAdViewCurrent.adListener = object: AdListener() {
override fun onAdLoaded() {
}
override fun onAdFailedToLoad(adError : LoadAdError) {
// Code to be executed when an ad request fails.
}
override fun onAdOpened() {
// Code to be executed when an ad opens an overlay that
// covers the screen.
}
override fun onAdClicked() {
// Code to be executed when the user clicks on an ad.
}
override fun onAdClosed() {
}
}
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == "GENDER") {
val prefs = sharedPreferences?.getString(key, "1")
when(prefs?.toInt()) {
1->{
bindUI()
}
2->{
bindUIWomen()
}
}
}
applyDarkModeSetting()
}
override fun onDestroy() {
super.onDestroy()
context?.let {
PreferenceManager.getDefaultSharedPreferences(it)
.registerOnSharedPreferenceChangeListener(this)
}
}
private fun applyDarkModeSetting() {
val sharedPreferences = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
val settingValue = sharedPreferences?.getString("GENDER", null)?.toIntOrNull() ?: 1
val mode = when (settingValue) {
1 -> {bindUI()}
2 -> {bindUIWomen()}
else -> Toast.makeText(context, "Nothing", Toast.LENGTH_LONG).show()
}
}
private fun bindUI() = launch(Dispatchers.Main) {
val currentWeather = viewModel.weather.await()
val weatherLocation = viewModel.weatherLocation.await()
val CurrentWeatherEntries = viewModel.weather.await()
CurrentWeatherEntries.observe(viewLifecycleOwner, Observer { weatherAll ->
if (weatherAll == null){
return#Observer
}
recyclerViewClothes.apply {
layoutManager = LinearLayoutManager(activity)
adapter = ClothesAdapter(weatherAll)
}
})
weatherLocation.observe(viewLifecycleOwner, Observer { location ->
if (location == null) return#Observer
updateLocation(location.name)
updateCityName(location.name)
})
currentWeather.observe(viewLifecycleOwner, Observer {
if(it == null) return#Observer
group_loading.visibility = View.GONE
weatherAll.visibility = View.VISIBLE
updateDateToday()
//updateIsDay(it.isDay)
updateHumidity(it.humidity)
updateTemperature(it.temperature, it.feelsLikeTemperature)
updateCondition(it.conditionText)
updatePressure(it.pressure)
updateWind(it.windSpeed)
updateCloudy(it.cloud)
GlideApp.with(this#CurrentWeatherFragment)
.load("https:${it.conditionIconUrl}")
.into(imageView_condition_icon)
})
refreshApp()
}
private fun List<UnitSpecificCurrentWeatherEntry>.toCurrentWeatherItems() : List<ClothesAdapter> {
return this.map {
ClothesAdapter(it) //ClothesAdapter
}
}
// private fun List<UnitSpecificCurrentWeatherEntry>.toCurrentWeatherItems() : List<ClothesAdapterWomen> {
// return this.map {
// ClothesAdapterWomen(it) //ClothesAdapter
// }
// }
private fun chooseLocalizationUnitAbbreviation(metric: String, imperial: String): String {
return if(viewModel.isMetricUnit) metric else imperial
}
private fun updateLocation(location: String) {
(activity as? AppCompatActivity)?.supportActionBar?.subtitle = getString(R.string.todayTitle)
}
private fun updateDateToday() {
(activity as? AppCompatActivity)?.supportActionBar?.subtitle = getString(R.string.todayTitle)
}
private fun updateCityName(cityName: String) {
textView_cityName.text = cityName
}
}

RecyclerView not binding data notifyDataSetChanged not working when filter data

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'

Blank screen with RecyclerView No adapter attached

I'm tying to parse JSON in recyclerview. App compiles fine but it's outputting empty/blank screen
BlogAdapter.kt
class BlogAdapter(private val blogList: List<Blog>) : RecyclerView.Adapter<BlogAdapter.ViewHolder>() {
override fun getItemCount()= blogList.size
private var mContext: Context? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
this.mContext=parent.context;
return ViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.character_item,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val mBlog = this.blogList[position]
if (mBlog.img != null) {
Glide.with(mContext!!)
.load(mBlog.img)
.into(holder.ivThumbnail)
}
if (mBlog.name != null) {
holder.tvTitle.text = mBlog.name
println("Log: Kabe "+mBlog.name)
}
}
class ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
val ivThumbnail:ImageView = itemView.findViewById(R.id.ivThumbnail);
val tvTitle:TextView = itemView.findViewById(R.id.tvTitle);
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
var mainViewModel: MainViewModel? = null
var mBlogAdapter: BlogAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
getPopularBlog()
swipe_refresh.setOnRefreshListener { getPopularBlog() }
}
private fun getPopularBlog() {
swipe_refresh.isRefreshing = false
mainViewModel!!.allBlog.observe(this, Observer { charactersList ->
prepareRecyclerView(charactersList)
})
}
private fun prepareRecyclerView(blogList: List<Blog>) {
mBlogAdapter = BlogAdapter(blogList)
if (this.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
blogRecyclerView.layoutManager = LinearLayoutManager(this)
} else {
blogRecyclerView.layoutManager = GridLayoutManager(this, 4)
}
blogRecyclerView.itemAnimator = DefaultItemAnimator()
blogRecyclerView.adapter = mBlogAdapter
}
}
My Json file looks like this:
[
{
"id": 1,
"name": "potter",
"img": "https://images.example.com/potter.jpg"
},
{ …}
]
I've created it based on this tutorial: https://itnext.io/kotlin-wrapping-your-head-around-livedata-mutablelivedata-coroutine-networking-and-viewmodel-b552c3a74eec
Any suggestions please
EDIT:
class BlogRepository() {
private var character = mutableListOf<ABCCharacters>()
private var mutableLiveData = MutableLiveData<List<ABCCharacters>>()
val completableJob = Job()
private val coroutineScope = CoroutineScope(Dispatchers.IO + completableJob)
private val thisApiCorService by lazy {
RestApiService.createCorService()
}
fun getMutableLiveData():MutableLiveData<List<ABCCharacters>> {
coroutineScope.launch {
val request = thisApiCorService.getPopularBlog()
withContext(Dispatchers.Main) {
try {
val response = request.await()
val mBlogWrapper = response;
if (/*mBlogWrapper != null &&*/ mBlogWrapper.isNotEmpty()) {
character = mBlogWrapper as MutableList<ABCCharacters>
mutableLiveData.value = character
}
} catch (e: HttpException) {
// Log exception //
} catch (e: Throwable) {
// Log error //)
}
}
}
return mutableLiveData;
}
}
You forget to call notifyDataSetChanged, when you setup your RecyclerView widget. Below the full method call, to make it works.
private fun prepareRecyclerView(blogList: List<Blog>) {
mBlogAdapter = BlogAdapter(blogList)
if (this.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
blogRecyclerView.layoutManager = LinearLayoutManager(this)
} else {
blogRecyclerView.layoutManager = GridLayoutManager(this, 4)
}
blogRecyclerView.itemAnimator = DefaultItemAnimator()
blogRecyclerView.adapter = mBlogAdapter
mBlogAdapter.notifyDataSetChanged()
}
Try using below implementation:
class MainActivity : AppCompatActivity() {
lateinit var mainViewModel: MainViewModel
var mBlogAdapter: BlogAdapter? = null
var blogList: List<Blog> = arrayListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// init your RV here
prepareRecyclerView()
getPopularBlog()
swipe_refresh.setOnRefreshListener { mainViewModel.getAllBlog() }
}
private fun getPopularBlog() {
swipe_refresh.isRefreshing = false
mainViewModel.getAllBlog().observe(this, Observer { charactersList ->
blogList = charactersList
mBlogAdapter?.notifyDataSetChanged()
})
}
private fun prepareRecyclerView() {
mBlogAdapter = BlogAdapter(blogList)
if (this.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
blogRecyclerView.layoutManager = LinearLayoutManager(this)
} else {
blogRecyclerView.layoutManager = GridLayoutManager(this, 4)
}
blogRecyclerView.itemAnimator = DefaultItemAnimator()
blogRecyclerView.adapter = mBlogAdapter
}
}
Modify your view model like below:
class MainViewModel() : ViewModel() {
val characterRepository= BlogRepository()
fun getAllBlog(): MutableLiveData<List<ABCCharacters>> {
return characterRepository.getMutableLiveData()
}
override fun onCleared() {
super.onCleared()
characterRepository.completableJob.cancel()
}
}

android pdfviewer / fragment

417/5000
Hello
I have a pdfview that works perfectly, for against it I can not add it to a fragment I use:
implementation 'com.github.barteksc: android-pdf-viewer: 2.8.2'
implementation 'com.github.barteksc: android-pdf-viewer: 3.1.0-beta 1'
Here is the code of my pdfview and my fragment
public class magasineFragment extends Fragment {
public static magasineFragment newInstance() {
magasineFragment fragment = new magasineFragment();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.pdf_fragment, container, false);
return view;
}
}
next pdf.class
class pdf : AppCompatActivity() {
internal lateinit var pdfView:PDFView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.pdf)
pdfView = findViewById(R.id.pdfView) as PDFView
RetrivePdfStream().execute("http://www.marseillemairie11-12.fr/fileadmin/Images/documents/kiosque/lemag-jan2019.pdf")
}
internal inner class RetrivePdfStream : AsyncTask<String, Void, InputStream>()
{
override fun doInBackground(vararg strings: String): InputStream? {
var inputStream: InputStream? = null
try {
val url = URL(strings[0])
val urlConnection = url.openConnection() as HttpURLConnection
if (urlConnection.responseCode == 200) {
inputStream = BufferedInputStream(urlConnection.inputStream)
}
} catch (e: IOException) {
return null
}
return inputStream
}
override fun onPostExecute(inputStream: InputStream) {
pdfView.fromStream(inputStream).load()
}
}
}
I hope this help you
this code in Kotlin read PDF file from Assets folder
and display it in fragment
class PdfRendererBasicFragment : Fragment(), View.OnClickListener {
private val FILENAME = "table.pdf"
private val STATE_CURRENT_PAGE_INDEX = "current_page_index"
private val TAG = "PdfRendererBasicFragment"
private val INITIAL_PAGE_INDEX = 0
private lateinit var fileDescriptor: ParcelFileDescriptor
private lateinit var pdfRenderer: PdfRenderer
private lateinit var currentPage: PdfRenderer.Page
private lateinit var imageView: ImageView
private lateinit var btnPrevious: Button
private lateinit var btnNext: Button
private var pageIndex: Int = INITIAL_PAGE_INDEX
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
imageView = view.findViewById(R.id.image)
btnPrevious = view.findViewById<Button>(R.id.previous).also { it.setOnClickListener(this) }
btnNext = view.findViewById<Button>(R.id.next).also { it.setOnClickListener(this)}
if (savedInstanceState != null) {
pageIndex = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, INITIAL_PAGE_INDEX)
} else {
pageIndex = INITIAL_PAGE_INDEX
}
}
#SuppressLint("LongLogTag")
override fun onStart() {
super.onStart()
try {
openRenderer(activity)
showPage(pageIndex)
} catch (e: IOException) {
Log.d(TAG, e.toString())
}
}
#SuppressLint("LongLogTag")
override fun onStop() {
try {
closeRenderer()
} catch (e: IOException) {
Log.d(TAG, e.toString())
}
super.onStop()
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(STATE_CURRENT_PAGE_INDEX, currentPage.index)
super.onSaveInstanceState(outState)
}
#Throws(IOException::class)
private fun openRenderer(context: Context?) {
if (context == null) return
val file = File(context.cacheDir, FILENAME)
if (!file.exists()) {
val asset = context.assets.open(FILENAME)
val output = FileOutputStream(file)
val buffer = ByteArray(1024)
var size = asset.read(buffer)
while (size != -1) {
output.write(buffer, 0, size)
size = asset.read(buffer)
}
asset.close()
output.close()
}
fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
pdfRenderer = PdfRenderer(fileDescriptor)
currentPage = pdfRenderer.openPage(pageIndex)
}
#Throws(IOException::class)
private fun closeRenderer() {
currentPage.close()
pdfRenderer.close()
fileDescriptor.close()
}
private fun showPage(index: Int) {
if (pdfRenderer.pageCount <= index) return
currentPage.close()
currentPage = pdfRenderer.openPage(index)
val bitmap = createBitmap(currentPage.width, currentPage.height, Bitmap.Config.ARGB_8888)
currentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
imageView.setImageBitmap(bitmap)
updateUi()
}
private fun updateUi() {
val index = currentPage.index
val pageCount = pdfRenderer.pageCount
btnPrevious.isEnabled = (0 != index)
btnNext.isEnabled = (index + 1 < pageCount)
}
fun getPageCount() = pdfRenderer.pageCount
override fun onClick(view: View) {
when (view.id) {
R.id.previous -> {
showPage(currentPage.index - 1)
}
R.id.next -> {
showPage(currentPage.index + 1)
}
}
}
}

ViewPager with FragmentStatePagerAdapter scrolls before closing

I have a ViewPager with a FragmentStatePagerAdapter to let users scroll through videos using a VideoView. It works fine, but when you press the back button, the viewpager scrolls to the left and briefly shows the previous ViewView before closing the viewpager activity.
I understand the FragmentStatePagerAdapter will cache the fragments/views for better memory management, but it seems odd to show the precious view before closing. Is this normal, or is there any way to make sure a view is completely hidden when it's not the current pager in focus?
Here's the code for my Adapter. Basically I return one of two fragments that creates a view with that photo or video in it.
inner class MyAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
override fun getCount(): Int = photoInfo.size
override fun getItemPosition(`object`: Any?): Int = super.getItemPosition(`object`)
override fun getItem(position: Int): Fragment {
when (photoInfo[position].type) {
PHOTO -> {
return PhotoFragment.newInstance(photoInfo[position])
}
VIDEO-> {
return VideoFragment.newInstance(photoInfo[position])
}
else -> {
return PhotoFragment.newInstance(photoInfo[position])
}
}
}
}
And the videofragment:
class VideoFragment : Fragment(), AnkoLogger {
internal var photo: String? = null
internal var totalSize: Int? = null
internal var thumbnail: String? = null
var player: SimpleExoPlayer? = null
var simpleExoPlayerView: SimpleExoPlayerView? = null
var error = false
var shouldLoop = true
var autoPlay = true
var proxy: HttpProxyCacheServer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
photo = arguments.getString("photo")
thumbnail = arguments.getString("thumbnail")
totalSize = arguments.getInt("size")
shouldLoop = defaultSharedPreferences.getBoolean("loop_webm_preference", true)
autoPlay = defaultSharedPreferences.getBoolean("autplay_webm_preference", true)
proxy = getProxy(activity)
}
override fun onDestroyView() {
player?.release()
super.onDestroyView()
}
override fun onPause() {
super.onPause()
}
fun checkAndSetVolume() {
val isMuted = defaultSharedPreferences.getBoolean("mute_video", false)
when (isMuted) {
true -> {
simpleExoPlayerView?.findViewById<ImageButton>(R.id.exo_mute)?.imageResource = R.drawable.volume_on
player?.volume = 0f
}
false -> {
simpleExoPlayerView?.findViewById<ImageButton>(R.id.exo_mute)?.imageResource = R.drawable.volume_off
player?.volume = 1f
}
}
}
override fun getUserVisibleHint(): Boolean {
return super.getUserVisibleHint()
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (!isVisibleToUser) {
player?.playWhenReady = false
player?.playbackState
player?.seekTo(0)
} else if (isVisible && isVisibleToUser && (proxy?.isCached(photo) == true) && !error) {
checkAndStartAutoplay()
}
}
fun checkAndStartAutoplay() {
checkAndSetVolume()
player?.playWhenReady = autoPlay
player?.playbackState
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
simpleExoPlayerView = SimpleExoPlayerView(context)
val mainHandler = Handler()
val bandwidthMeter = DefaultBandwidthMeter()
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(bandwidthMeter)
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
player = ExoPlayerFactory.newSimpleInstance(context, trackSelector)
val fl = FrameLayout(context)
simpleExoPlayerView?.player = player
simpleExoPlayerView?.setShutterBackgroundColor(Color.TRANSPARENT)
player?.repeatMode = if (shouldLoop) 1 else 0
player?.addListener(object : Player.DefaultEventListener() {
override fun onPlayerError(error: ExoPlaybackException?) {
val tv = TextView(context)
tv.text = getString(android.R.string.VideoView_error_text_unknown)
tv.textColor = Color.WHITE
tv.textAlignment = TextView.TEXT_ALIGNMENT_CENTER
fl.addView(tv, FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER))
this#VideoFragment.error = true
}
override fun onLoadingChanged(isLoading: Boolean) {
super.onLoadingChanged(isLoading)
if (!isLoading) {
if (this#VideoFragment.isVisible && this#VideoFragment.userVisibleHint) {
checkAndStartAutoplay()
}
}
}
})
val proxyUrl = proxy?.getProxyUrl(photo)
val dataSourceFactory = DefaultDataSourceFactory(context, Util.getUserAgent(context, "Omnichan"), bandwidthMeter)
val videoSource = ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(proxyUrl))
player?.prepare(videoSource)
fl.addView(simpleExoPlayerView, FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER))
simpleExoPlayerView?.findViewById<ImageButton>(R.id.exo_mute)?.setOnClickListener {
val isMuted = defaultSharedPreferences.getBoolean("mute_video", false)
defaultSharedPreferences.edit().putBoolean("mute_video", !isMuted).apply()
checkAndSetVolume()
}
return fl
}
companion object {
internal fun newInstance(photoInfo: PhotoInfo): VideoFragment {
val f = VideoFragment()
val args = Bundle()
args.putString("photo", photoInfo.photoUrl)
args.putString("thumbnail", photoInfo.thumbnailUrl)
f.arguments = args
return f
}
private var sharedProxy: HttpProxyCacheServer? = null
private fun newProxy(context: Context): HttpProxyCacheServer {
return HttpProxyCacheServer.Builder(context)
.maxCacheSize((1024 * 1024 * 256).toLong()) // 256 Mb for cache
.build()
}
fun getProxy(context: Context): HttpProxyCacheServer {
return sharedProxy ?: newProxy(context)
}
}
}

Categories

Resources