10 Commits

Author SHA1 Message Date
d293e3bcfe feat: dep updates 2025-12-07 19:34:07 +01:00
CappielloAntonio
9cf62c8c0c gradle: update gradle build tools 2025-01-31 11:05:39 +01:00
CappielloAntonio
330556ec33 Merge remote-tracking branch 'origin/main' 2025-01-31 10:32:53 +01:00
CappielloAntonio
4c8c5ce120 gradle: dependencies update 2025-01-31 10:32:39 +01:00
CappielloAntonio
55ae9a8442 fix: added missing decorators 2025-01-31 10:32:00 +01:00
CappielloAntonio
f8a53c7db2 Update README.md 2024-12-31 16:55:21 +01:00
CappielloAntonio
b58cae1ecd Update README.md 2024-12-31 16:51:37 +01:00
CappielloAntonio
e305f20811 fix: updated workflow 2024-12-31 12:54:28 +01:00
CappielloAntonio
c8c1bcfd3e fix: null checking 2024-12-30 17:23:55 +01:00
CappielloAntonio
e1c96d278f fix: null checking 2024-12-30 17:20:13 +01:00
18 changed files with 52 additions and 39 deletions

View File

@@ -52,7 +52,7 @@ jobs:
BUILD_TOOLS_VERSION: ${{ env.BUILD_TOOL_VERSION }} BUILD_TOOLS_VERSION: ${{ env.BUILD_TOOL_VERSION }}
- name: Make artifact - name: Make artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: app-release-signed name: app-release-signed
path: ${{steps.sign_apk.outputs.signedReleaseFile}} path: ${{steps.sign_apk.outputs.signedReleaseFile}}

1
.idea/gradle.xml generated
View File

@@ -13,7 +13,6 @@
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
</set> </set>
</option> </option>
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings> </GradleProjectSettings>
</option> </option>
</component> </component>

3
.idea/misc.xml generated
View File

@@ -192,7 +192,8 @@
</map> </map>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK"> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@@ -8,6 +8,8 @@
<p align="center"> <p align="center">
<a href="https://github.com/CappielloAntonio/tempo/releases"><img src="https://i.ibb.co/q0mdc4Z/get-it-on-github.png" width="200"></a> <a href="https://github.com/CappielloAntonio/tempo/releases"><img src="https://i.ibb.co/q0mdc4Z/get-it-on-github.png" width="200"></a>
</p>
<p align="center">
<a href="https://f-droid.org/packages/com.cappielloantonio.notquitemy.tempo"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" width="200"></a> <a href="https://f-droid.org/packages/com.cappielloantonio.notquitemy.tempo"><img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" width="200"></a>
<a href="https://apt.izzysoft.de/fdroid/index/apk/com.cappielloantonio.tempo"><img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" width="200"></a> <a href="https://apt.izzysoft.de/fdroid/index/apk/com.cappielloantonio.tempo"><img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" width="200"></a>
</p> </p>
@@ -18,6 +20,8 @@ Tempo does not rely on magic algorithms to decide what you should listen to. Ins
**If you find Tempo useful, please consider starring the project on GitHub. It would mean a lot to me and help promote the app to a wider audience.** **If you find Tempo useful, please consider starring the project on GitHub. It would mean a lot to me and help promote the app to a wider audience.**
**Use the Github version of the app for full Android Auto and Chromecast support.**
## Features ## Features
- **Subsonic Integration**: Tempo seamlessly integrates with your Subsonic server, providing you with easy access to your entire music collection on the go. - **Subsonic Integration**: Tempo seamlessly integrates with your Subsonic server, providing you with easy access to your entire music collection on the go.
- **Sleek and Intuitive UI**: Enjoy a clean and user-friendly interface designed to enhance your music listening experience, tailored to your preferences and listening history. - **Sleek and Intuitive UI**: Enjoy a clean and user-friendly interface designed to enhance your music listening experience, tailored to your preferences and listening history.
@@ -29,6 +33,7 @@ Tempo does not rely on magic algorithms to decide what you should listen to. Ins
- **Scrobbling Integration**: Optionally integrate Tempo with Last.fm to scrobble your played tracks, gather music insights, and further personalize your music recommendations, if supported by your Subsonic server. - **Scrobbling Integration**: Optionally integrate Tempo with Last.fm to scrobble your played tracks, gather music insights, and further personalize your music recommendations, if supported by your Subsonic server.
- **Podcasts and Radio**: If your Subsonic server supports it, listen to podcasts and radio shows directly within Tempo, expanding your audio entertainment options. - **Podcasts and Radio**: If your Subsonic server supports it, listen to podcasts and radio shows directly within Tempo, expanding your audio entertainment options.
- **Transcoding Support**: Activate transcoding of tracks on your Subsonic server, allowing you to set a transcoding profile for optimized streaming directly from the app. This feature requires support from your Subsonic server. - **Transcoding Support**: Activate transcoding of tracks on your Subsonic server, allowing you to set a transcoding profile for optimized streaming directly from the app. This feature requires support from your Subsonic server.
- **Android Auto Support**: Enjoy your favorite music on the go with full Android Auto integration, allowing you to seamlessly control and listen to your tracks directly from your mobile device while driving.
<p align="center"> <p align="center">
<img src="mockup/feat/1_screenshot.png" width=200> <img src="mockup/feat/1_screenshot.png" width=200>

View File

@@ -3,15 +3,14 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-parcelize'
android { android {
compileSdk 35
buildToolsVersion = '35.0.0' buildToolsVersion = '35.0.0'
defaultConfig { defaultConfig {
minSdkVersion 24 minSdkVersion 24
targetSdk 35 targetSdk 35
versionCode 25 versionCode 26
versionName '3.8.1' versionName '3.9.0'
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
@@ -74,37 +73,37 @@ dependencies {
implementation files('../libs/lib-decoder-ffmpeg-release.aar') implementation files('../libs/lib-decoder-ffmpeg-release.aar')
// AndroidX // AndroidX
implementation 'androidx.constraintlayout:constraintlayout:2.2.0' implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0' implementation 'androidx.coordinatorlayout:coordinatorlayout:1.3.0'
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.8.5' implementation 'androidx.navigation:navigation-fragment-ktx:2.9.6'
implementation 'androidx.navigation:navigation-ui-ktx:2.8.5' implementation 'androidx.navigation:navigation-ui-ktx:2.9.6'
implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation 'androidx.recyclerview:recyclerview:1.4.0'
implementation 'androidx.room:room-runtime:2.6.1' implementation 'androidx.room:room-runtime:2.8.4'
implementation 'androidx.core:core-splashscreen:1.0.1' implementation 'androidx.core:core-splashscreen:1.2.0'
implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'androidx.appcompat:appcompat:1.7.1'
// Android Material // Android Material
implementation 'com.google.android.material:material:1.10.0' implementation 'com.google.android.material:material:1.13.0'
// Glide // Glide
implementation 'com.github.bumptech.glide:glide:4.16.0' implementation 'com.github.bumptech.glide:glide:5.0.5'
implementation 'com.github.bumptech.glide:annotations:4.16.0' implementation 'com.github.bumptech.glide:annotations:5.0.5'
// Media3 // Media3
implementation 'androidx.media3:media3-session:1.5.1' implementation 'androidx.media3:media3-session:1.8.0'
implementation 'androidx.media3:media3-common:1.5.1' implementation 'androidx.media3:media3-common:1.8.0'
implementation 'androidx.media3:media3-exoplayer:1.5.1' implementation 'androidx.media3:media3-exoplayer:1.8.0'
implementation 'androidx.media3:media3-ui:1.5.1' implementation 'androidx.media3:media3-ui:1.8.0'
implementation 'androidx.media3:media3-exoplayer-hls:1.5.1' implementation 'androidx.media3:media3-exoplayer-hls:1.8.0'
tempoImplementation 'androidx.media3:media3-cast:1.5.1' tempoImplementation 'androidx.media3:media3-cast:1.8.0'
playImplementation 'androidx.media3:media3-cast:1.5.1' playImplementation 'androidx.media3:media3-cast:1.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:5.0.5'
annotationProcessor 'androidx.room:room-compiler:2.6.1' annotationProcessor 'androidx.room:room-compiler:2.8.4'
// Retrofit // Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.11.0' implementation 'com.squareup.retrofit2:retrofit:3.0.0'
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.14' implementation 'com.squareup.okhttp3:logging-interceptor:5.3.2'
implementation 'com.squareup.retrofit2:converter-gson:2.11.0' implementation 'com.squareup.retrofit2:converter-gson:3.0.0'
} }

View File

@@ -1,7 +1,9 @@
package com.cappielloantonio.tempo.github.models package com.cappielloantonio.tempo.github.models
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class Assets( data class Assets(
@SerializedName("url") @SerializedName("url")
var url: String? = null, var url: String? = null,

View File

@@ -1,7 +1,9 @@
package com.cappielloantonio.tempo.github.models package com.cappielloantonio.tempo.github.models
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class Author( data class Author(
@SerializedName("login") @SerializedName("login")
var login: String? = null, var login: String? = null,

View File

@@ -1,7 +1,9 @@
package com.cappielloantonio.tempo.github.models package com.cappielloantonio.tempo.github.models
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class LatestRelease( data class LatestRelease(
@SerializedName("url") @SerializedName("url")
var url: String? = null, var url: String? = null,

View File

@@ -1,7 +1,9 @@
package com.cappielloantonio.tempo.github.models package com.cappielloantonio.tempo.github.models
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class Reactions( data class Reactions(
@SerializedName("url") @SerializedName("url")
var url: String? = null, var url: String? = null,

View File

@@ -1,7 +1,9 @@
package com.cappielloantonio.tempo.github.models package com.cappielloantonio.tempo.github.models
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class Uploader( data class Uploader(
@SerializedName("login") @SerializedName("login")
var login: String? = null, var login: String? = null,

View File

@@ -40,7 +40,7 @@ class RetrofitClient(subsonic: Subsonic) {
.connectTimeout(20, TimeUnit.SECONDS) .connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS)
.addInterceptor(getHttpLoggingInterceptor()) // .addInterceptor(getHttpLoggingInterceptor())
.addInterceptor(cacheUtil.offlineInterceptor) .addInterceptor(cacheUtil.offlineInterceptor)
// .addNetworkInterceptor(cacheUtil.onlineInterceptor) // .addNetworkInterceptor(cacheUtil.onlineInterceptor)
.cache(getCache()) .cache(getCache())

View File

@@ -50,7 +50,7 @@ public class ArtistCatalogueAdapter extends RecyclerView.Adapter<ArtistCatalogue
@Override @Override
protected void publishResults(CharSequence constraint, FilterResults results) { protected void publishResults(CharSequence constraint, FilterResults results) {
artists.clear(); artists.clear();
artists.addAll((List) results.values); if (results.count > 0) artists.addAll((List) results.values);
notifyDataSetChanged(); notifyDataSetChanged();
} }
}; };

View File

@@ -13,7 +13,6 @@ import com.cappielloantonio.tempo.databinding.ItemLibraryCatalogueGenreBinding;
import com.cappielloantonio.tempo.interfaces.ClickCallback; import com.cappielloantonio.tempo.interfaces.ClickCallback;
import com.cappielloantonio.tempo.subsonic.models.Genre; import com.cappielloantonio.tempo.subsonic.models.Genre;
import com.cappielloantonio.tempo.util.Constants; import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.util.MusicUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -49,7 +48,7 @@ public class GenreCatalogueAdapter extends RecyclerView.Adapter<GenreCatalogueAd
@Override @Override
protected void publishResults(CharSequence constraint, FilterResults results) { protected void publishResults(CharSequence constraint, FilterResults results) {
genres.clear(); genres.clear();
genres.addAll((List) results.values); if (results.count > 0) genres.addAll((List) results.values);
notifyDataSetChanged(); notifyDataSetChanged();
} }
}; };

View File

@@ -54,7 +54,7 @@ public class PlaylistHorizontalAdapter extends RecyclerView.Adapter<PlaylistHori
@Override @Override
protected void publishResults(CharSequence constraint, FilterResults results) { protected void publishResults(CharSequence constraint, FilterResults results) {
playlists.clear(); playlists.clear();
playlists.addAll((List) results.values); if (results.count > 0) playlists.addAll((List) results.values);
notifyDataSetChanged(); notifyDataSetChanged();
} }
}; };

View File

@@ -48,7 +48,7 @@ public class PodcastChannelCatalogueAdapter extends RecyclerView.Adapter<Podcast
@Override @Override
protected void publishResults(CharSequence constraint, FilterResults results) { protected void publishResults(CharSequence constraint, FilterResults results) {
podcastChannels.clear(); podcastChannels.clear();
podcastChannels.addAll((List) results.values); if (results.count > 0) podcastChannels.addAll((List) results.values);
notifyDataSetChanged(); notifyDataSetChanged();
} }
}; };

View File

@@ -105,7 +105,7 @@ public class GenreCatalogueFragment extends Fragment implements ClickCallback {
genreCatalogueAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY); genreCatalogueAdapter.setStateRestorationPolicy(RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY);
bind.genreCatalogueRecyclerView.setAdapter(genreCatalogueAdapter); bind.genreCatalogueRecyclerView.setAdapter(genreCatalogueAdapter);
genreCatalogueViewModel.getGenreList().observe(getViewLifecycleOwner(), genres -> genreCatalogueAdapter.setItems(genres)); genreCatalogueViewModel.getGenreList().observe(getViewLifecycleOwner(), genres -> genreCatalogueAdapter.setItems(genres) );
bind.genreCatalogueRecyclerView.setOnTouchListener((v, event) -> { bind.genreCatalogueRecyclerView.setOnTouchListener((v, event) -> {
hideKeyboard(v); hideKeyboard(v);

View File

@@ -4,8 +4,8 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.7.3' classpath 'com.android.tools.build:gradle:8.13.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0' classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.21'
} }
} }

View File

@@ -1,6 +1,6 @@
#Wed Nov 06 17:17:57 CET 2024 #Wed Nov 06 17:17:57 CET 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists