Compare commits
10 Commits
3783a2f790
...
d293e3bcfe
| Author | SHA1 | Date | |
|---|---|---|---|
| d293e3bcfe | |||
|
|
9cf62c8c0c | ||
|
|
330556ec33 | ||
|
|
4c8c5ce120 | ||
|
|
55ae9a8442 | ||
|
|
f8a53c7db2 | ||
|
|
b58cae1ecd | ||
|
|
e305f20811 | ||
|
|
c8c1bcfd3e | ||
|
|
e1c96d278f |
2
.github/workflows/github_release.yml
vendored
2
.github/workflows/github_release.yml
vendored
@@ -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
1
.idea/gradle.xml
generated
@@ -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
3
.idea/misc.xml
generated
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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'
|
||||||
}
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user