mirror of
https://github.com/Michatec/Radio.git
synced 2026-01-31 07:20:40 +00:00
- Update the libary gson. - Deleted some unuseful Code. - added some locals to locales config.
750 lines
30 KiB
Kotlin
750 lines
30 KiB
Kotlin
/*
|
|
* CollectionAdapter.kt
|
|
* Implements the CollectionAdapter class
|
|
* A CollectionAdapter is a custom adapter providing station card views for a RecyclerView
|
|
*
|
|
* This file is part of
|
|
* TRANSISTOR - Radio App for Android
|
|
*
|
|
* Copyright (c) 2015-22 - Y20K.org
|
|
* Licensed under the MIT-License
|
|
* http://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
|
|
package com.michatec.radio.collection
|
|
|
|
import android.annotation.SuppressLint
|
|
import android.content.Context
|
|
import android.content.SharedPreferences
|
|
import android.text.Editable
|
|
import android.text.TextWatcher
|
|
import android.view.LayoutInflater
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.view.inputmethod.EditorInfo
|
|
import android.widget.ImageView
|
|
import android.widget.TextView
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import androidx.cardview.widget.CardView
|
|
import androidx.constraintlayout.widget.Group
|
|
import androidx.core.net.toUri
|
|
import androidx.core.view.isGone
|
|
import androidx.core.view.isVisible
|
|
import androidx.lifecycle.LifecycleOwner
|
|
import androidx.lifecycle.ViewModelProvider
|
|
import androidx.navigation.findNavController
|
|
import androidx.recyclerview.widget.DiffUtil
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
import com.google.android.material.button.MaterialButton
|
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
|
import com.google.android.material.textfield.TextInputEditText
|
|
import com.michatec.radio.Keys
|
|
import com.michatec.radio.R
|
|
import com.michatec.radio.core.Collection
|
|
import com.michatec.radio.core.Station
|
|
import com.michatec.radio.helpers.*
|
|
import kotlinx.coroutines.*
|
|
import kotlinx.coroutines.Dispatchers.IO
|
|
import kotlinx.coroutines.Dispatchers.Main
|
|
import java.util.*
|
|
|
|
|
|
/*
|
|
* CollectionAdapter class
|
|
*/
|
|
class CollectionAdapter(
|
|
private val context: Context,
|
|
private val collectionAdapterListener: CollectionAdapterListener
|
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), UpdateHelper.UpdateHelperListener {
|
|
|
|
/* Main class variables */
|
|
private lateinit var collectionViewModel: CollectionViewModel
|
|
private var collection: Collection = Collection()
|
|
private var editStationsEnabled: Boolean = PreferencesHelper.loadEditStationsEnabled()
|
|
private var editStationStreamsEnabled: Boolean = PreferencesHelper.loadEditStreamUrisEnabled()
|
|
private var expandedStationUuid: String = PreferencesHelper.loadStationListStreamUuid()
|
|
private var expandedStationPosition: Int = -1
|
|
var isExpandedForEdit: Boolean = false
|
|
|
|
|
|
/* Listener Interface */
|
|
interface CollectionAdapterListener {
|
|
fun onPlayButtonTapped(stationUuid: String)
|
|
fun onAddNewButtonTapped()
|
|
fun onChangeImageButtonTapped(stationUuid: String)
|
|
}
|
|
|
|
|
|
/* Overrides onAttachedToRecyclerView */
|
|
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
|
super.onAttachedToRecyclerView(recyclerView)
|
|
// create view model and observe changes in collection view model
|
|
collectionViewModel =
|
|
ViewModelProvider(context as AppCompatActivity)[CollectionViewModel::class.java]
|
|
observeCollectionViewModel(context as LifecycleOwner)
|
|
// start listening for changes in shared preferences
|
|
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
|
}
|
|
|
|
|
|
/* Overrides onDetachedFromRecyclerView */
|
|
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
|
super.onDetachedFromRecyclerView(recyclerView)
|
|
// stop listening for changes in shared preferences
|
|
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
|
}
|
|
|
|
|
|
/* Overrides onCreateViewHolder */
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
|
|
|
return when (viewType) {
|
|
Keys.VIEW_TYPE_ADD_NEW -> {
|
|
// get view, put view into holder and return
|
|
val v = LayoutInflater.from(parent.context)
|
|
.inflate(R.layout.card_add_new_station, parent, false)
|
|
AddNewViewHolder(v)
|
|
}
|
|
else -> {
|
|
// get view, put view into holder and return
|
|
val v = LayoutInflater.from(parent.context)
|
|
.inflate(R.layout.card_station, parent, false)
|
|
StationViewHolder(v)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Implement the method to handle item move */
|
|
fun onItemMove(fromPosition: Int, toPosition: Int) {
|
|
// Do nothing if in "edit" mode
|
|
if (isExpandedForEdit) {
|
|
return
|
|
}
|
|
|
|
val stationList = collection.stations
|
|
val stationCount = stationList.size
|
|
|
|
if (fromPosition !in 0 until stationCount || toPosition !in 0 until stationCount) {
|
|
return
|
|
}
|
|
|
|
val fromStation = stationList[fromPosition]
|
|
val toStation = stationList[toPosition]
|
|
|
|
if (fromStation.starred != toStation.starred) {
|
|
// Prevent moving a starred item into non-starred area or vice versa
|
|
return
|
|
}
|
|
|
|
// Move within the same group (either starred or non-starred)
|
|
Collections.swap(stationList, fromPosition, toPosition)
|
|
|
|
// Update the value of expandedStationPosition if necessary
|
|
expandedStationPosition = if (fromPosition == expandedStationPosition) toPosition else expandedStationPosition
|
|
|
|
// Notify the adapter about the item move
|
|
notifyItemMoved(fromPosition, toPosition)
|
|
}
|
|
|
|
|
|
/* Implement the method to handle item dismissal */
|
|
fun onItemDismiss(position: Int) {
|
|
// Remove the item at the given position from your data collection
|
|
collection.stations.removeAt(position)
|
|
notifyItemRemoved(position)
|
|
}
|
|
|
|
|
|
/* Method for saving the collection after the drag-and-drop operation */
|
|
fun saveCollectionAfterDragDrop() {
|
|
// Save the collection after the dragging is completed
|
|
CollectionHelper.saveCollection(context, collection)
|
|
}
|
|
|
|
|
|
/* Overrides onBindViewHolder */
|
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
|
when (holder) {
|
|
// CASE ADD NEW CARD
|
|
is AddNewViewHolder -> {
|
|
// get reference to StationViewHolder
|
|
val addNewViewHolder: AddNewViewHolder = holder
|
|
addNewViewHolder.addNewStationView.setOnClickListener {
|
|
// show the add station dialog
|
|
collectionAdapterListener.onAddNewButtonTapped()
|
|
}
|
|
addNewViewHolder.settingsButtonView.setOnClickListener {
|
|
it.findNavController().navigate(R.id.settings_destination)
|
|
}
|
|
}
|
|
// CASE STATION CARD
|
|
is StationViewHolder -> {
|
|
// get station from position
|
|
val station: Station = collection.stations[position]
|
|
|
|
// get reference to StationViewHolder
|
|
val stationViewHolder: StationViewHolder = holder
|
|
|
|
// set up station views
|
|
setStarredIcon(stationViewHolder, station)
|
|
setStationName(stationViewHolder, station)
|
|
setStationImage(stationViewHolder, station)
|
|
setStationButtons(stationViewHolder, station)
|
|
setEditViews(stationViewHolder, station)
|
|
|
|
// show / hide edit views
|
|
when (expandedStationPosition) {
|
|
// show edit views
|
|
position -> {
|
|
stationViewHolder.stationNameView.isVisible = false
|
|
stationViewHolder.playButtonView.isGone = true
|
|
stationViewHolder.stationStarredView.isGone = true
|
|
stationViewHolder.editViews.isVisible = true
|
|
if (editStationStreamsEnabled) {
|
|
stationViewHolder.stationUriEditView.isVisible = true
|
|
stationViewHolder.stationUriEditView.imeOptions =
|
|
EditorInfo.IME_ACTION_DONE
|
|
} else {
|
|
stationViewHolder.stationUriEditView.isGone = true
|
|
stationViewHolder.stationNameEditView.imeOptions =
|
|
EditorInfo.IME_ACTION_DONE
|
|
}
|
|
}
|
|
// hide edit views
|
|
else -> {
|
|
stationViewHolder.stationNameView.isVisible = true
|
|
//stationViewHolder.playButtonView.isVisible = true
|
|
stationViewHolder.stationStarredView.isVisible = station.starred
|
|
stationViewHolder.editViews.isGone = true
|
|
stationViewHolder.stationUriEditView.isGone = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Overrides onStationUpdated from UpdateHelperListener */
|
|
override fun onStationUpdated(
|
|
collection: Collection,
|
|
positionPriorUpdate: Int,
|
|
positionAfterUpdate: Int
|
|
) {
|
|
// check if position has changed after update and move stations around if necessary
|
|
if (positionPriorUpdate != positionAfterUpdate && positionPriorUpdate != -1 && positionAfterUpdate != -1) {
|
|
notifyItemMoved(positionPriorUpdate, positionAfterUpdate)
|
|
notifyItemChanged(positionPriorUpdate)
|
|
}
|
|
// update station (e.g. name)
|
|
notifyItemChanged(positionAfterUpdate)
|
|
}
|
|
|
|
|
|
/* Sets the station name view */
|
|
private fun setStationName(stationViewHolder: StationViewHolder, station: Station) {
|
|
stationViewHolder.stationNameView.text = station.name
|
|
}
|
|
|
|
|
|
/* Sets the edit views */
|
|
private fun setEditViews(stationViewHolder: StationViewHolder, station: Station) {
|
|
stationViewHolder.stationNameEditView.setText(station.name, TextView.BufferType.EDITABLE)
|
|
stationViewHolder.stationUriEditView.setText(
|
|
station.getStreamUri(),
|
|
TextView.BufferType.EDITABLE
|
|
)
|
|
stationViewHolder.stationUriEditView.addTextChangedListener(object : TextWatcher {
|
|
override fun afterTextChanged(s: Editable?) {
|
|
handleStationUriInput(stationViewHolder, s, station.getStreamUri())
|
|
}
|
|
|
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
|
})
|
|
stationViewHolder.cancelButton.setOnClickListener {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
toggleEditViews(position, station.uuid)
|
|
UiHelper.hideSoftKeyboard(context, stationViewHolder.stationNameEditView)
|
|
}
|
|
stationViewHolder.saveButton.setOnClickListener {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
toggleEditViews(position, station.uuid)
|
|
saveStation(
|
|
station,
|
|
position,
|
|
stationViewHolder.stationNameEditView.text.toString(),
|
|
stationViewHolder.stationUriEditView.text.toString()
|
|
)
|
|
UiHelper.hideSoftKeyboard(context, stationViewHolder.stationNameEditView)
|
|
}
|
|
stationViewHolder.placeOnHomeScreenButton.setOnClickListener {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
ShortcutHelper.placeShortcut(context, station)
|
|
toggleEditViews(position, station.uuid)
|
|
UiHelper.hideSoftKeyboard(context, stationViewHolder.stationNameEditView)
|
|
}
|
|
stationViewHolder.stationImageChangeView.setOnClickListener {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
collectionAdapterListener.onChangeImageButtonTapped(station.uuid)
|
|
stationViewHolder.adapterPosition
|
|
toggleEditViews(position, station.uuid)
|
|
UiHelper.hideSoftKeyboard(context, stationViewHolder.stationNameEditView)
|
|
}
|
|
}
|
|
|
|
|
|
/* Shows / hides the edit view for a station */
|
|
@SuppressLint("NotifyDataSetChanged")
|
|
private fun toggleEditViews(position: Int, stationUuid: String) {
|
|
when (stationUuid) {
|
|
// CASE: this station's edit view is already expanded
|
|
expandedStationUuid -> {
|
|
isExpandedForEdit = false
|
|
// reset currently expanded info (both uuid and position)
|
|
saveStationListExpandedState()
|
|
// update station view
|
|
notifyItemChanged(position)
|
|
}
|
|
// CASE: this station's edit view is not yet expanded
|
|
else -> {
|
|
isExpandedForEdit = true
|
|
// remember previously expanded position
|
|
val previousExpandedStationPosition: Int = expandedStationPosition
|
|
// if station was expanded - collapse it
|
|
if (previousExpandedStationPosition > -1 && previousExpandedStationPosition < collection.stations.size)
|
|
notifyItemChanged(previousExpandedStationPosition)
|
|
// store current station as the expanded one
|
|
saveStationListExpandedState(position, stationUuid)
|
|
// update station view
|
|
notifyDataSetChanged()
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Toggles the starred icon */
|
|
private fun setStarredIcon(stationViewHolder: StationViewHolder, station: Station) {
|
|
when (station.starred) {
|
|
true -> {
|
|
if (station.imageColor != -1) {
|
|
// stationViewHolder.stationCardView.setCardBackgroundColor(station.imageColor)
|
|
stationViewHolder.stationStarredView.setColorFilter(station.imageColor)
|
|
}
|
|
stationViewHolder.stationStarredView.isVisible = true
|
|
}
|
|
false -> stationViewHolder.stationStarredView.isGone = true
|
|
}
|
|
}
|
|
|
|
|
|
/* Sets the station image view */
|
|
private fun setStationImage(stationViewHolder: StationViewHolder, station: Station) {
|
|
if (station.imageColor != -1) {
|
|
stationViewHolder.stationImageView.setBackgroundColor(station.imageColor)
|
|
}
|
|
stationViewHolder.stationImageView.setImageBitmap(
|
|
ImageHelper.getStationImage(
|
|
context,
|
|
station.smallImage
|
|
)
|
|
)
|
|
stationViewHolder.stationImageView.contentDescription =
|
|
"${context.getString(R.string.descr_player_station_image)}: ${station.name}"
|
|
}
|
|
|
|
|
|
/* Sets up a station's play and edit buttons */
|
|
private fun setStationButtons(stationViewHolder: StationViewHolder, station: Station) {
|
|
when (station.isPlaying) {
|
|
true -> stationViewHolder.playButtonView.visibility = View.VISIBLE
|
|
false -> stationViewHolder.playButtonView.visibility = View.INVISIBLE
|
|
}
|
|
stationViewHolder.stationCardView.setOnClickListener {
|
|
collectionAdapterListener.onPlayButtonTapped(station.uuid)
|
|
}
|
|
stationViewHolder.playButtonView.setOnClickListener {
|
|
collectionAdapterListener.onPlayButtonTapped(station.uuid)
|
|
}
|
|
stationViewHolder.stationNameView.setOnClickListener {
|
|
collectionAdapterListener.onPlayButtonTapped(station.uuid)
|
|
}
|
|
stationViewHolder.stationStarredView.setOnClickListener {
|
|
collectionAdapterListener.onPlayButtonTapped(station.uuid)
|
|
}
|
|
stationViewHolder.stationImageView.setOnClickListener {
|
|
collectionAdapterListener.onPlayButtonTapped(station.uuid)
|
|
}
|
|
stationViewHolder.playButtonView.setOnLongClickListener {
|
|
if (editStationsEnabled) {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
toggleEditViews(position, station.uuid)
|
|
return@setOnLongClickListener true
|
|
} else {
|
|
return@setOnLongClickListener false
|
|
}
|
|
}
|
|
stationViewHolder.stationNameView.setOnLongClickListener {
|
|
if (editStationsEnabled) {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
toggleEditViews(position, station.uuid)
|
|
return@setOnLongClickListener true
|
|
} else {
|
|
return@setOnLongClickListener false
|
|
}
|
|
}
|
|
stationViewHolder.stationStarredView.setOnLongClickListener {
|
|
if (editStationsEnabled) {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
toggleEditViews(position, station.uuid)
|
|
return@setOnLongClickListener true
|
|
} else {
|
|
return@setOnLongClickListener false
|
|
}
|
|
}
|
|
stationViewHolder.stationImageView.setOnLongClickListener {
|
|
if (editStationsEnabled) {
|
|
val position: Int = stationViewHolder.adapterPosition
|
|
toggleEditViews(position, station.uuid)
|
|
return@setOnLongClickListener true
|
|
} else {
|
|
return@setOnLongClickListener false
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Checks if stream uri input is valid */
|
|
private fun handleStationUriInput(
|
|
stationViewHolder: StationViewHolder,
|
|
s: Editable?,
|
|
streamUri: String
|
|
) {
|
|
if (editStationStreamsEnabled) {
|
|
val input: String = s.toString()
|
|
if (input == streamUri) {
|
|
// enable save button
|
|
stationViewHolder.saveButton.isEnabled = true
|
|
} else {
|
|
// 1. disable save button
|
|
stationViewHolder.saveButton.isEnabled = false
|
|
// 2. check for valid station uri - and re-enable button
|
|
if (input.startsWith("http")) {
|
|
// detect content type on background thread
|
|
CoroutineScope(IO).launch {
|
|
val deferred: Deferred<NetworkHelper.ContentType> =
|
|
async(Dispatchers.Default) {
|
|
NetworkHelper.detectContentTypeSuspended(input)
|
|
}
|
|
// wait for result
|
|
val contentType: String =
|
|
deferred.await().type.lowercase(Locale.getDefault())
|
|
// CASE: stream address detected
|
|
if (Keys.MIME_TYPES_MPEG.contains(contentType) or
|
|
Keys.MIME_TYPES_OGG.contains(contentType) or
|
|
Keys.MIME_TYPES_AAC.contains(contentType) or
|
|
Keys.MIME_TYPES_HLS.contains(contentType)
|
|
) {
|
|
// re-enable save button
|
|
withContext(Main) {
|
|
stationViewHolder.saveButton.isEnabled = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Overrides onBindViewHolder */
|
|
override fun onBindViewHolder(
|
|
holder: RecyclerView.ViewHolder,
|
|
position: Int,
|
|
payloads: List<Any>
|
|
) {
|
|
|
|
if (payloads.isEmpty()) {
|
|
// call regular onBindViewHolder method
|
|
onBindViewHolder(holder, position)
|
|
|
|
} else if (holder is StationViewHolder) {
|
|
// get station from position
|
|
collection.stations[holder.getAdapterPosition()]
|
|
|
|
for (data in payloads) {
|
|
when (data as Int) {
|
|
Keys.HOLDER_UPDATE_COVER -> {
|
|
// todo implement
|
|
}
|
|
Keys.HOLDER_UPDATE_NAME -> {
|
|
// todo implement
|
|
}
|
|
Keys.HOLDER_UPDATE_PLAYBACK_STATE -> {
|
|
// todo implement
|
|
}
|
|
Keys.HOLDER_UPDATE_PLAYBACK_PROGRESS -> {
|
|
// todo implement
|
|
}
|
|
Keys.HOLDER_UPDATE_DOWNLOAD_STATE -> {
|
|
// todo implement
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Overrides getItemViewType */
|
|
override fun getItemViewType(position: Int): Int {
|
|
return when (isPositionFooter(position)) {
|
|
true -> Keys.VIEW_TYPE_ADD_NEW
|
|
false -> Keys.VIEW_TYPE_STATION
|
|
}
|
|
}
|
|
|
|
|
|
/* Overrides getItemCount */
|
|
override fun getItemCount(): Int {
|
|
// +1 ==> the add station card
|
|
return collection.stations.size + 1
|
|
}
|
|
|
|
|
|
/* Removes a station from collection */
|
|
fun removeStation(context: Context, position: Int) {
|
|
val newCollection = collection.deepCopy()
|
|
// delete images assets
|
|
CollectionHelper.deleteStationImages(context, newCollection.stations[position])
|
|
// remove station from collection
|
|
newCollection.stations.removeAt(position)
|
|
collection = newCollection
|
|
// update list
|
|
notifyItemRemoved(position)
|
|
// save collection and broadcast changes
|
|
CollectionHelper.saveCollection(context, newCollection)
|
|
}
|
|
|
|
|
|
/* Toggles starred status of a station */
|
|
fun toggleStarredStation(context: Context, position: Int) {
|
|
// update view (reset "swipe" state of station card)
|
|
notifyItemChanged(position)
|
|
// mark starred
|
|
val stationUuid: String = collection.stations[position].uuid
|
|
collection.stations[position].apply { starred = !starred }
|
|
// sort collection
|
|
collection = CollectionHelper.sortCollection(collection)
|
|
// update list
|
|
notifyItemMoved(position, CollectionHelper.getStationPosition(collection, stationUuid))
|
|
// save collection and broadcast changes
|
|
CollectionHelper.saveCollection(context, collection)
|
|
}
|
|
|
|
|
|
/* Saves edited station */
|
|
private fun saveStation(
|
|
station: Station,
|
|
position: Int,
|
|
stationName: String,
|
|
streamUri: String
|
|
) {
|
|
// update station name and stream uri
|
|
collection.stations.forEach {
|
|
if (it.uuid == station.uuid) {
|
|
if (stationName.isNotEmpty()) {
|
|
it.name = stationName
|
|
it.nameManuallySet = true
|
|
}
|
|
if (streamUri.isNotEmpty()) {
|
|
it.streamUris[0] = streamUri
|
|
}
|
|
}
|
|
}
|
|
// sort and save collection
|
|
collection = CollectionHelper.sortCollection(collection)
|
|
// update list
|
|
val newPosition: Int = CollectionHelper.getStationPosition(collection, station.uuid)
|
|
if (position != newPosition && newPosition != -1) {
|
|
notifyItemMoved(position, newPosition)
|
|
notifyItemChanged(position)
|
|
}
|
|
// save collection and broadcast changes
|
|
CollectionHelper.saveCollection(context, collection)
|
|
}
|
|
|
|
|
|
// /* Initiates update of a station's information */ // todo move to CollectionHelper
|
|
// private fun updateStation(context: Context, station: Station) {
|
|
// if (station.radioBrowserStationUuid.isNotEmpty()) {
|
|
// // get updated station from radio browser - results are handled by onRadioBrowserSearchResults
|
|
// val radioBrowserSearch: RadioBrowserSearch = RadioBrowserSearch(context, this)
|
|
// radioBrowserSearch.searchStation(context, station.radioBrowserStationUuid, Keys.SEARCH_TYPE_BY_UUID)
|
|
// } else if (station.remoteStationLocation.isNotEmpty()) {
|
|
// // download playlist // todo check content type detection is necessary here
|
|
// DownloadHelper.downloadPlaylists(context, arrayOf(station.remoteStationLocation))
|
|
// } else {
|
|
// Log.w(TAG, "Unable to update station: ${station.name}.")
|
|
// }
|
|
// }
|
|
|
|
|
|
/* Determines if position is last */
|
|
private fun isPositionFooter(position: Int): Boolean {
|
|
return position == collection.stations.size
|
|
}
|
|
|
|
|
|
/* Updates the station list - redraws the views with changed content */
|
|
@SuppressLint("NotifyDataSetChanged")
|
|
private fun updateRecyclerView(oldCollection: Collection, newCollection: Collection) {
|
|
collection = newCollection
|
|
if (oldCollection.stations.size == 0 && newCollection.stations.size > 0) {
|
|
// data set has been initialized - redraw the whole list
|
|
notifyDataSetChanged()
|
|
} else {
|
|
// calculate differences between current collection and new collection - and inform this adapter about the changes
|
|
val diffResult =
|
|
DiffUtil.calculateDiff(CollectionDiffCallback(oldCollection, newCollection), true)
|
|
diffResult.dispatchUpdatesTo(this@CollectionAdapter)
|
|
}
|
|
}
|
|
|
|
|
|
/* Updates and saves state of expanded station edit view in list */
|
|
private fun saveStationListExpandedState(
|
|
position: Int = -1,
|
|
stationStreamUri: String = String()
|
|
) {
|
|
expandedStationUuid = stationStreamUri
|
|
expandedStationPosition = position
|
|
PreferencesHelper.saveStationListStreamUuid(expandedStationUuid)
|
|
}
|
|
|
|
|
|
/* Observe view model of station collection*/
|
|
private fun observeCollectionViewModel(owner: LifecycleOwner) {
|
|
collectionViewModel.collectionLiveData.observe(owner) { newCollection ->
|
|
updateRecyclerView(collection, newCollection)
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Defines the listener for changes in shared preferences
|
|
*/
|
|
private val sharedPreferenceChangeListener =
|
|
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
|
when (key) {
|
|
Keys.PREF_EDIT_STATIONS -> editStationsEnabled =
|
|
PreferencesHelper.loadEditStationsEnabled()
|
|
Keys.PREF_EDIT_STREAMS_URIS -> editStationStreamsEnabled =
|
|
PreferencesHelper.loadEditStreamUrisEnabled()
|
|
}
|
|
}
|
|
/*
|
|
* End of declaration
|
|
*/
|
|
|
|
|
|
/*
|
|
* Inner class: ViewHolder for the Add New Station action
|
|
*/
|
|
private inner class AddNewViewHolder(listItemAddNewLayout: View) :
|
|
RecyclerView.ViewHolder(listItemAddNewLayout) {
|
|
val addNewStationView: ExtendedFloatingActionButton =
|
|
listItemAddNewLayout.findViewById(R.id.card_add_new_station)
|
|
val settingsButtonView: ExtendedFloatingActionButton =
|
|
listItemAddNewLayout.findViewById(R.id.card_settings)
|
|
}
|
|
/*
|
|
* End of inner class
|
|
*/
|
|
|
|
|
|
/*
|
|
* Inner class: ViewHolder for a station
|
|
*/
|
|
private inner class StationViewHolder(stationCardLayout: View) :
|
|
RecyclerView.ViewHolder(stationCardLayout) {
|
|
val stationCardView: CardView = stationCardLayout.findViewById(R.id.station_card)
|
|
val stationImageView: ImageView = stationCardLayout.findViewById(R.id.station_icon)
|
|
val stationNameView: TextView = stationCardLayout.findViewById(R.id.station_name)
|
|
val stationStarredView: ImageView = stationCardLayout.findViewById(R.id.starred_icon)
|
|
|
|
// val menuButtonView: ImageView = stationCardLayout.findViewById(R.id.menu_button)
|
|
val playButtonView: ImageView = stationCardLayout.findViewById(R.id.playback_button)
|
|
val editViews: Group = stationCardLayout.findViewById(R.id.default_edit_views)
|
|
val stationImageChangeView: ImageView =
|
|
stationCardLayout.findViewById(R.id.change_image_view)
|
|
val stationNameEditView: TextInputEditText =
|
|
stationCardLayout.findViewById(R.id.edit_station_name)
|
|
val stationUriEditView: TextInputEditText =
|
|
stationCardLayout.findViewById(R.id.edit_stream_uri)
|
|
val placeOnHomeScreenButton: MaterialButton =
|
|
stationCardLayout.findViewById(R.id.place_on_home_screen_button)
|
|
val cancelButton: MaterialButton = stationCardLayout.findViewById(R.id.cancel_button)
|
|
val saveButton: MaterialButton = stationCardLayout.findViewById(R.id.save_button)
|
|
}
|
|
/*
|
|
* End of inner class
|
|
*/
|
|
|
|
|
|
/*
|
|
* Inner class: DiffUtil.Callback that determines changes in data - improves list performance
|
|
*/
|
|
private inner class CollectionDiffCallback(
|
|
val oldCollection: Collection,
|
|
val newCollection: Collection
|
|
) : DiffUtil.Callback() {
|
|
|
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
|
val oldStation: Station = oldCollection.stations[oldItemPosition]
|
|
val newStation: Station = newCollection.stations[newItemPosition]
|
|
return oldStation.uuid == newStation.uuid
|
|
}
|
|
|
|
override fun getOldListSize(): Int {
|
|
return oldCollection.stations.size
|
|
}
|
|
|
|
override fun getNewListSize(): Int {
|
|
return newCollection.stations.size
|
|
}
|
|
|
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
|
val oldStation: Station = oldCollection.stations[oldItemPosition]
|
|
val newStation: Station = newCollection.stations[newItemPosition]
|
|
|
|
// compare relevant contents of a station
|
|
if (oldStation.isPlaying != newStation.isPlaying) return false
|
|
if (oldStation.uuid != newStation.uuid) return false
|
|
if (oldStation.starred != newStation.starred) return false
|
|
if (oldStation.name != newStation.name) return false
|
|
if (oldStation.stream != newStation.stream) return false
|
|
if (oldStation.remoteImageLocation != newStation.remoteImageLocation) return false
|
|
if (oldStation.remoteStationLocation != newStation.remoteStationLocation) return false
|
|
if (!oldStation.streamUris.containsAll(newStation.streamUris)) return false
|
|
if (oldStation.imageColor != newStation.imageColor) return false
|
|
if (FileHelper.getFileSize(context, oldStation.image.toUri()) != FileHelper.getFileSize(
|
|
context,
|
|
newStation.image.toUri()
|
|
)
|
|
) return false
|
|
if (FileHelper.getFileSize(
|
|
context,
|
|
oldStation.smallImage.toUri()
|
|
) != FileHelper.getFileSize(context, newStation.smallImage.toUri())
|
|
) return false
|
|
|
|
// none of the above -> contents are the same
|
|
return true
|
|
}
|
|
}
|
|
/*
|
|
* End of inner class
|
|
*/
|
|
}
|