25 Commits

Author SHA1 Message Date
Michachatz
2c1913896d Merge pull request #29 from Michatec/renovate/androidx.media3-media3-datasource-okhttp-1.x
Update dependency androidx.media3:media3-datasource-okhttp to v1.9.1
2026-01-30 18:56:34 +01:00
Michachatz
026e18ae22 Merge pull request #30 from Michatec/renovate/androidx.media3-media3-exoplayer-1.x
Update dependency androidx.media3:media3-exoplayer to v1.9.1
2026-01-30 18:56:18 +01:00
renovate[bot]
3b6ebe5e1b Update dependency androidx.media3:media3-exoplayer to v1.9.1 2026-01-30 17:55:55 +00:00
Michachatz
26eab4c64c Merge pull request #31 from Michatec/renovate/androidx.media3-media3-exoplayer-hls-1.x
Update dependency androidx.media3:media3-exoplayer-hls to v1.9.1
2026-01-30 18:55:43 +01:00
renovate[bot]
75b3deb210 Update dependency androidx.media3:media3-exoplayer-hls to v1.9.1 2026-01-30 17:55:23 +00:00
renovate[bot]
96389a5c81 Update dependency androidx.media3:media3-datasource-okhttp to v1.9.1 2026-01-30 17:55:19 +00:00
Michachatz
1544c07938 Merge pull request #32 from Michatec/renovate/androidx.media3-media3-session-1.x
Update dependency androidx.media3:media3-session to v1.9.1
2026-01-30 18:54:56 +01:00
Michachatz
65e9d1fed4 Merge pull request #33 from Michatec/renovate/androidx.navigation-navigation-fragment-ktx-2.x
Update dependency androidx.navigation:navigation-fragment-ktx to v2.9.7
2026-01-30 18:54:45 +01:00
renovate[bot]
9bfc1661b8 Update dependency androidx.navigation:navigation-fragment-ktx to v2.9.7 2026-01-30 17:54:21 +00:00
Michachatz
9a379675bf Merge pull request #34 from Michatec/renovate/androidx.navigation-navigation-ui-ktx-2.x
Update dependency androidx.navigation:navigation-ui-ktx to v2.9.7
2026-01-30 18:53:49 +01:00
renovate[bot]
529e359f7f Update dependency androidx.navigation:navigation-ui-ktx to v2.9.7 2026-01-30 17:52:58 +00:00
Michachatz
fc3a1f767a Merge pull request #35 from Michatec/renovate/androidx.activity-activity-ktx-1.x
Update dependency androidx.activity:activity-ktx to v1.12.3
2026-01-30 18:52:45 +01:00
Michachatz
9197e5c2a9 Merge pull request #36 from Michatec/renovate/androidx.work-work-runtime-ktx-2.x
Update dependency androidx.work:work-runtime-ktx to v2.11.1
2026-01-30 18:52:34 +01:00
Michachatz
5920327283 Merge pull request #37 from Michatec/renovate/gradle-9.x
Update Gradle to v9.3.1
2026-01-30 18:52:22 +01:00
renovate[bot]
769cbb505f Update Gradle to v9.3.1 2026-01-29 16:34:13 +00:00
renovate[bot]
1f5d61759c Update dependency androidx.work:work-runtime-ktx to v2.11.1 2026-01-29 04:41:58 +00:00
renovate[bot]
5b1d6d96c7 Update dependency androidx.activity:activity-ktx to v1.12.3 2026-01-29 04:41:54 +00:00
renovate[bot]
606154cfb3 Update dependency androidx.media3:media3-session to v1.9.1 2026-01-26 17:46:05 +00:00
Michatec
9b5c7e3c04 - New version Initialized 2026-01-25 17:07:30 +01:00
Michatec
4466654e92 - Fix unused import 2026-01-25 16:33:45 +01:00
Michatec
b2de7bd534 - Progress Bar added
- CollectionAdapter.kt updated
- File download optimized
- Housekeeping updated
2026-01-25 16:33:17 +01:00
Michatec
d3dfcb98f9 - Layout Changes
- HLS media extraction
2026-01-25 16:08:22 +01:00
Michachatz
0adb906438 Aktualisieren von provider_paths.xml 2026-01-22 06:55:40 +01:00
Michachatz
49e63d3aaa Aktualisieren von shortcuts.xml 2026-01-22 06:55:08 +01:00
Michatec
f892a137ce - Fix .yml 2026-01-21 18:14:38 +01:00
13 changed files with 139 additions and 68 deletions

View File

@@ -51,6 +51,10 @@ jobs:
- name: Check APK path - name: Check APK path
run: ls -R app/build/outputs/apk run: ls -R app/build/outputs/apk
- name: Zipalign APK
run: |
/usr/local/lib/android/sdk/build-tools/34.0.0/zipalign -v -p 4 ${{ env.APK_PATH }} app-release-aligned.apk
- name: Sign APK - name: Sign APK
env: env:
SIGN_CERT: ${{ secrets.SIGN_CERT }} SIGN_CERT: ${{ secrets.SIGN_CERT }}
@@ -58,15 +62,10 @@ jobs:
run: | run: |
echo "$SIGN_CERT" | base64 -d > cert.der echo "$SIGN_CERT" | base64 -d > cert.der
echo "$SIGN_KEY" | base64 -d > key.der echo "$SIGN_KEY" | base64 -d > key.der
mv ${{ env.APK_PATH }} app-release.apk ${{ env.APKSIGNER }} sign --key key.der --cert cert.der app-release-aligned.apk
${{ env.APKSIGNER }} sign --key key.der --cert cert.der app-release.apk
rm cert.der key.der rm cert.der key.der
- name: Zipalign APK
run: |
/usr/local/lib/android/sdk/build-tools/34.0.0/zipalign -v -p 4 app-release.apk app-release-aligned.apk
mv app-release-aligned.apk app-release.apk mv app-release-aligned.apk app-release.apk
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v6
with: with:

View File

@@ -19,8 +19,8 @@ android {
applicationId 'com.michatec.radio' applicationId 'com.michatec.radio'
minSdk 28 minSdk 28
targetSdk 36 targetSdk 36
versionCode 140 versionCode 141
versionName '14' versionName '14.1'
resourceConfigurations += ['en', 'de', 'el', 'nl', 'pl', 'ru','uk', 'ja', 'da', 'fr'] resourceConfigurations += ['en', 'de', 'el', 'nl', 'pl', 'ru','uk', 'ja', 'da', 'fr']
} }
@@ -60,17 +60,17 @@ dependencies {
// AndroidX Stuff // // AndroidX Stuff //
implementation 'androidx.core:core-ktx:1.17.0' implementation 'androidx.core:core-ktx:1.17.0'
implementation 'androidx.activity:activity-ktx:1.12.2' implementation 'androidx.activity:activity-ktx:1.12.3'
implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0'
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.media:media:1.7.1' implementation 'androidx.media:media:1.7.1'
implementation 'androidx.media3:media3-exoplayer:1.9.0' implementation 'androidx.media3:media3-exoplayer:1.9.1'
implementation 'androidx.media3:media3-exoplayer-hls:1.9.0' implementation 'androidx.media3:media3-exoplayer-hls:1.9.1'
implementation 'androidx.media3:media3-session:1.9.0' implementation 'androidx.media3:media3-session:1.9.1'
implementation 'androidx.media3:media3-datasource-okhttp:1.9.0' implementation 'androidx.media3:media3-datasource-okhttp:1.9.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.9.6' implementation 'androidx.navigation:navigation-fragment-ktx:2.9.7'
implementation 'androidx.navigation:navigation-ui-ktx:2.9.6' implementation 'androidx.navigation:navigation-ui-ktx:2.9.7'
implementation 'androidx.work:work-runtime-ktx:2.11.0' implementation 'androidx.work:work-runtime-ktx:2.11.1'
// Volley HTTP request // // Volley HTTP request //
implementation 'com.android.volley:volley:1.2.1' implementation 'com.android.volley:volley:1.2.1'

View File

@@ -24,7 +24,6 @@ import androidx.navigation.ui.NavigationUI
import androidx.navigation.ui.navigateUp import androidx.navigation.ui.navigateUp
import com.michatec.radio.helpers.AppThemeHelper import com.michatec.radio.helpers.AppThemeHelper
import com.michatec.radio.helpers.FileHelper import com.michatec.radio.helpers.FileHelper
import com.michatec.radio.helpers.ImportHelper
import com.michatec.radio.helpers.PreferencesHelper import com.michatec.radio.helpers.PreferencesHelper
@@ -41,18 +40,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)
@@ -471,24 +496,25 @@ class CollectionAdapter(
} else if (holder is StationViewHolder) { } else if (holder is StationViewHolder) {
// get station from position // get station from position
collection.stations[holder.bindingAdapterPosition] val station: Station = collection.stations[holder.bindingAdapterPosition]
for (data in payloads) { for (data in payloads) {
when (data as Int) { when (data as Int) {
Keys.HOLDER_UPDATE_COVER -> { Keys.HOLDER_UPDATE_COVER -> {
// todo implement setStationImage(holder, station)
setStarredIcon(holder, station)
} }
Keys.HOLDER_UPDATE_NAME -> { Keys.HOLDER_UPDATE_NAME -> {
// todo implement setStationName(holder, station)
} }
Keys.HOLDER_UPDATE_PLAYBACK_STATE -> { Keys.HOLDER_UPDATE_PLAYBACK_STATE -> {
// todo implement 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)
} }
} }
} }
@@ -575,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
@@ -600,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 {
@@ -672,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

@@ -20,6 +20,8 @@ import androidx.media3.common.Metadata
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.extractor.metadata.icy.IcyHeaders import androidx.media3.extractor.metadata.icy.IcyHeaders
import androidx.media3.extractor.metadata.icy.IcyInfo import androidx.media3.extractor.metadata.icy.IcyInfo
import androidx.media3.extractor.metadata.id3.Id3Frame
import androidx.media3.extractor.metadata.id3.TextInformationFrame
import com.michatec.radio.Keys import com.michatec.radio.Keys
import kotlin.math.min import kotlin.math.min
@@ -37,28 +39,51 @@ object AudioHelper {
/* Extract audio stream metadata */ /* Extract audio stream metadata */
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
fun getMetadataString(metadata: Metadata): String { fun getMetadataString(metadata: Metadata): String {
var metadataString = String() var title = ""
var artist = ""
var album = ""
for (i in 0 until metadata.length()) { for (i in 0 until metadata.length()) {
// extract IceCast metadata // extract IceCast metadata
when (val entry = metadata.get(i)) { when (val entry = metadata.get(i)) {
is IcyInfo -> { is IcyInfo -> {
metadataString = entry.title.toString() title = entry.title.toString()
} }
is IcyHeaders -> { is IcyHeaders -> {
Log.i(TAG, "icyHeaders:" + entry.name + " - " + entry.genre) Log.i(TAG, "icyHeaders:" + entry.name + " - " + entry.genre)
} }
is Id3Frame -> {
when (entry) {
is TextInformationFrame -> {
when (entry.id) {
"TIT2" -> title = entry.values.getOrNull(0) ?: "" // Title
"TPE1" -> artist = entry.values.getOrNull(0) ?: "" // Artist
"TALB" -> album = entry.values.getOrNull(0) ?: "" // Album
}
}
else -> {
Log.d(TAG, "Unhandled ID3 frame: ${entry.javaClass.simpleName}")
}
}
}
else -> { else -> {
Log.w(TAG, "Unsupported metadata received (type = ${entry.javaClass.simpleName})") Log.w(TAG, "Unsupported metadata received (type = ${entry.javaClass.simpleName})")
} }
} }
// TODO implement HLS metadata extraction (Id3Frame / PrivFrame) }
// https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/metadata/Metadata.Entry.html // Build metadata string
var metadataString = title
if (artist.isNotEmpty() && title.isNotEmpty()) {
metadataString = "$artist - $title"
}
if (album.isNotEmpty() && metadataString.isNotEmpty()) {
metadataString += " ($album)"
} }
// ensure a max length of the metadata string // ensure a max length of the metadata string
if (metadataString.isNotEmpty()) { if (metadataString.isNotEmpty()) {
metadataString = metadataString.substring(0, min(metadataString.length, Keys.DEFAULT_MAX_LENGTH_OF_METADATA_ENTRY)) metadataString = metadataString.take(min(metadataString.length, Keys.DEFAULT_MAX_LENGTH_OF_METADATA_ENTRY))
} }
return metadataString return metadataString
} }

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

@@ -14,6 +14,7 @@
package com.michatec.radio.ui package com.michatec.radio.ui
import android.annotation.SuppressLint
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
@@ -131,6 +132,7 @@ data class LayoutHolder(var rootView: View) {
/* Updates the player views */ /* Updates the player views */
@SuppressLint("DefaultLocale")
fun updatePlayerViews(context: Context, station: Station, isPlaying: Boolean) { fun updatePlayerViews(context: Context, station: Station, isPlaying: Boolean) {
// set default metadata views, when playback has stopped // set default metadata views, when playback has stopped
@@ -164,12 +166,20 @@ data class LayoutHolder(var rootView: View) {
// show only the codec when the bitrate is at "0" from radio-browser.info API // show only the codec when the bitrate is at "0" from radio-browser.info API
station.codec station.codec
} else { } else {
val kiloBytesPerSecond = station.bitrate / 8F
val dataRateString = if (kiloBytesPerSecond >= 1000) {
String.format("%.2f mb/s", kiloBytesPerSecond / 1000F)
} else {
String.format("%.0f kb/s", kiloBytesPerSecond)
}
// show the bitrate and codec if the result is available in the radio-browser.info API // show the bitrate and codec if the result is available in the radio-browser.info API
buildString { buildString {
append(station.codec) append(station.codec)
append(" | ") append(" | ")
append(station.bitrate) append(station.bitrate)
append("kbps") append("kbps")
append(" | ")
append(dataRateString)
} }
} }
} else { } else {

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"

View File

@@ -2,7 +2,7 @@
<paths> <paths>
<external-files-path <external-files-path
name="my_images" name="my_images"
path="Android/data/com.michatec.urlradio/files/Pictures" /> path="Android/data/com.michatec.radio/files/Pictures" />
<external-path <external-path
name="external_files" name="external_files"
path="." /> path="." />

View File

@@ -10,7 +10,7 @@
android:shortcutShortLabel="@string/shortcut_last_station_short_label"> android:shortcutShortLabel="@string/shortcut_last_station_short_label">
<intent <intent
android:action="com.jamal2367.urlradio.action.START" android:action="com.michatec.radio.action.START"
android:targetClass="com.michatec.radio.MainActivity" android:targetClass="com.michatec.radio.MainActivity"
android:targetPackage="com.michatec.radio"> android:targetPackage="com.michatec.radio">
<extra <extra

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME