- Progress Bar added

- CollectionAdapter.kt updated
- File download optimized
- Housekeeping updated
This commit is contained in:
Michatec
2026-01-25 16:33:17 +01:00
parent d3dfcb98f9
commit b2de7bd534
6 changed files with 75 additions and 38 deletions

View File

@@ -41,18 +41,6 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// house-keeping: determine if edit stations is enabled by default todo: remove in 2023
if (PreferencesHelper.isHouseKeepingNecessary()) {
// house-keeping 1: remove hard coded default image
ImportHelper.removeDefaultStationImageUris(this)
// house-keeping 2: if existing user detected, enable Edit Stations by default
if (PreferencesHelper.loadCollectionSize() != -1) {
// existing user detected - enable Edit Stations by default
PreferencesHelper.saveEditStationsEnabled(true)
}
PreferencesHelper.saveHouseKeepingNecessaryState()
}
// set up views // set up views
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)

View File

@@ -24,6 +24,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.ImageView import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.cardview.widget.CardView import androidx.cardview.widget.CardView
@@ -193,6 +194,8 @@ class CollectionAdapter(
setStationImage(stationViewHolder, station) setStationImage(stationViewHolder, station)
setStationButtons(stationViewHolder, station) setStationButtons(stationViewHolder, station)
setEditViews(stationViewHolder, station) setEditViews(stationViewHolder, station)
setPlaybackProgress(stationViewHolder, station)
setDownloadProgress(stationViewHolder, station)
// show / hide edit views // show / hide edit views
when (expandedStationPosition) { when (expandedStationPosition) {
@@ -248,6 +251,28 @@ class CollectionAdapter(
} }
/* Sets the playback progress view */
private fun setPlaybackProgress(stationViewHolder: StationViewHolder, station: Station) {
if (station.bufferingProgress > 0) {
stationViewHolder.bufferingProgress.progress = station.bufferingProgress
stationViewHolder.bufferingProgress.isVisible = true
} else {
stationViewHolder.bufferingProgress.isGone = true
}
}
/* Sets the download progress view */
private fun setDownloadProgress(stationViewHolder: StationViewHolder, station: Station) {
if (station.downloadProgress > 0) {
stationViewHolder.downloadProgress.progress = station.downloadProgress
stationViewHolder.downloadProgress.isVisible = true
} else {
stationViewHolder.downloadProgress.isGone = true
}
}
/* Sets the edit views */ /* Sets the edit views */
private fun setEditViews(stationViewHolder: StationViewHolder, station: Station) { private fun setEditViews(stationViewHolder: StationViewHolder, station: Station) {
stationViewHolder.stationNameEditView.setText(station.name, TextView.BufferType.EDITABLE) stationViewHolder.stationNameEditView.setText(station.name, TextView.BufferType.EDITABLE)
@@ -486,10 +511,10 @@ class CollectionAdapter(
setStationButtons(holder, station) setStationButtons(holder, station)
} }
Keys.HOLDER_UPDATE_PLAYBACK_PROGRESS -> { Keys.HOLDER_UPDATE_PLAYBACK_PROGRESS -> {
// todo implement setPlaybackProgress(holder, station)
} }
Keys.HOLDER_UPDATE_DOWNLOAD_STATE -> { Keys.HOLDER_UPDATE_DOWNLOAD_STATE -> {
// todo implement setDownloadProgress(holder, station)
} }
} }
} }
@@ -576,21 +601,6 @@ class CollectionAdapter(
} }
// /* 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 */ /* Determines if position is last */
private fun isPositionFooter(position: Int): Boolean { private fun isPositionFooter(position: Int): Boolean {
return position == collection.stations.size return position == collection.stations.size
@@ -601,7 +611,7 @@ class CollectionAdapter(
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
private fun updateRecyclerView(oldCollection: Collection, newCollection: Collection) { private fun updateRecyclerView(oldCollection: Collection, newCollection: Collection) {
collection = newCollection collection = newCollection
if (oldCollection.stations.size == 0 && newCollection.stations.size > 0) { if (oldCollection.stations.isEmpty() && newCollection.stations.isNotEmpty()) {
// data set has been initialized - redraw the whole list // data set has been initialized - redraw the whole list
notifyDataSetChanged() notifyDataSetChanged()
} else { } else {
@@ -673,6 +683,8 @@ class CollectionAdapter(
val stationImageView: ImageView = stationCardLayout.findViewById(R.id.station_icon) val stationImageView: ImageView = stationCardLayout.findViewById(R.id.station_icon)
val stationNameView: TextView = stationCardLayout.findViewById(R.id.station_name) val stationNameView: TextView = stationCardLayout.findViewById(R.id.station_name)
val stationStarredView: ImageView = stationCardLayout.findViewById(R.id.starred_icon) val stationStarredView: ImageView = stationCardLayout.findViewById(R.id.starred_icon)
val bufferingProgress: ProgressBar = stationCardLayout.findViewById(R.id.buffering_progress)
val downloadProgress: ProgressBar = stationCardLayout.findViewById(R.id.download_progress)
// val menuButtonView: ImageView = stationCardLayout.findViewById(R.id.menu_button) // val menuButtonView: ImageView = stationCardLayout.findViewById(R.id.menu_button)
val playButtonView: ImageView = stationCardLayout.findViewById(R.id.playback_button) val playButtonView: ImageView = stationCardLayout.findViewById(R.id.playback_button)

View File

@@ -48,7 +48,9 @@ data class Station(
@Expose var radioBrowserStationUuid: String = String(), @Expose var radioBrowserStationUuid: String = String(),
@Expose var radioBrowserChangeUuid: String = String(), @Expose var radioBrowserChangeUuid: String = String(),
@Expose var bitrate: Int = 0, @Expose var bitrate: Int = 0,
@Expose var codec: String = String() @Expose var codec: String = String(),
@Expose var bufferingProgress: Int = 0,
@Expose var downloadProgress: Int = 0
) : Parcelable { ) : Parcelable {
@@ -79,6 +81,12 @@ data class Station(
} }
/* Getter for media type */
fun getMediaType(): String {
return streamContent
}
/* Creates a deep copy of a Station */ /* Creates a deep copy of a Station */
fun deepCopy(): Station { fun deepCopy(): Station {
return Station( return Station(
@@ -101,7 +109,9 @@ data class Station(
radioBrowserStationUuid = radioBrowserStationUuid, radioBrowserStationUuid = radioBrowserStationUuid,
radioBrowserChangeUuid = radioBrowserChangeUuid, radioBrowserChangeUuid = radioBrowserChangeUuid,
bitrate = bitrate, bitrate = bitrate,
codec = codec codec = codec,
bufferingProgress = bufferingProgress,
downloadProgress = downloadProgress
) )
} }
} }

View File

@@ -688,7 +688,6 @@ object CollectionHelper {
/* Creates a MediaItem with MediaMetadata for a single radio station - used to prepare player */ /* Creates a MediaItem with MediaMetadata for a single radio station - used to prepare player */
fun buildMediaItem(context: Context, station: Station): MediaItem { fun buildMediaItem(context: Context, station: Station): MediaItem {
// todo implement HLS MediaItems
// put uri in RequestMetadata - credit: https://stackoverflow.com/a/70103460 // put uri in RequestMetadata - credit: https://stackoverflow.com/a/70103460
val requestMetadata = MediaItem.RequestMetadata.Builder().apply { val requestMetadata = MediaItem.RequestMetadata.Builder().apply {
setMediaUri(station.getStreamUri().toUri()) setMediaUri(station.getStreamUri().toUri())
@@ -713,7 +712,7 @@ object CollectionHelper {
setMediaId(station.uuid) setMediaId(station.uuid)
setRequestMetadata(requestMetadata) setRequestMetadata(requestMetadata)
setMediaMetadata(mediaMetadata) setMediaMetadata(mediaMetadata)
//setMimeType(station.getMediaType()) setMimeType(station.getMediaType())
setUri(station.getStreamUri().toUri()) setUri(station.getStreamUri().toUri())
}.build() }.build()
} }

View File

@@ -417,16 +417,14 @@ object FileHelper {
/* Reads InputStream from file uri and returns it as String */ /* Reads InputStream from file uri and returns it as String */
private fun readTextFileFromFile(context: Context): String { private fun readTextFileFromFile(context: Context): String {
// todo read https://commonsware.com/blog/2016/03/15/how-consume-content-uri.html
// https://developer.android.com/training/secure-file-sharing/retrieve-info
// check if file exists // check if file exists
val file = File(context.getExternalFilesDir(Keys.FOLDER_COLLECTION), Keys.COLLECTION_FILE) val file = File(context.getExternalFilesDir(Keys.FOLDER_COLLECTION), Keys.COLLECTION_FILE)
if (!file.exists() || !file.canRead()) { if (!file.exists() || !file.canRead()) {
return String() return String()
} }
// read until last line reached // read until last line reached
val stream: InputStream = file.inputStream() val uri = Uri.fromFile(file)
val stream: InputStream = context.contentResolver.openInputStream(uri) ?: return String()
val reader = BufferedReader(InputStreamReader(stream)) val reader = BufferedReader(InputStreamReader(stream))
val builder: StringBuilder = StringBuilder() val builder: StringBuilder = StringBuilder()
reader.forEachLine { reader.forEachLine {

View File

@@ -31,6 +31,21 @@
app:shapeAppearanceOverlay="@style/RoundedCorners" app:shapeAppearanceOverlay="@style/RoundedCorners"
app:srcCompat="@drawable/ic_default_station_image_72dp" /> app:srcCompat="@drawable/ic_default_station_image_72dp" />
<ProgressBar
android:id="@+id/download_progress"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="4dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:progressTint="@color/player_button_background"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/station_icon"
app:layout_constraintStart_toStartOf="@+id/station_icon"
app:layout_constraintTop_toTopOf="@+id/station_icon"
tools:visibility="visible" />
<com.google.android.material.imageview.ShapeableImageView <com.google.android.material.imageview.ShapeableImageView
android:id="@+id/change_image_view" android:id="@+id/change_image_view"
android:layout_width="0dp" android:layout_width="0dp"
@@ -155,6 +170,21 @@
app:layout_constraintEnd_toStartOf="@+id/save_button" app:layout_constraintEnd_toStartOf="@+id/save_button"
app:layout_constraintTop_toTopOf="@+id/save_button" /> app:layout_constraintTop_toTopOf="@+id/save_button" />
<ProgressBar
android:id="@+id/buffering_progress"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="4dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="4dp"
android:progressTint="@color/player_button_background"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Group <androidx.constraintlayout.widget.Group
android:id="@+id/default_edit_views" android:id="@+id/default_edit_views"
android:layout_width="0dp" android:layout_width="0dp"