mirror of
https://github.com/CappielloAntonio/tempo.git
synced 2026-01-31 14:43:36 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cb371dc5a | ||
|
|
499001a269 | ||
|
|
4c9e47379d | ||
|
|
a0dbb5c81f | ||
|
|
dab53c6bbf | ||
|
|
c0a665c00a | ||
|
|
41b5c57240 | ||
|
|
1d65a79c20 | ||
|
|
efb6e72636 | ||
|
|
af83ffd608 | ||
|
|
0201077bc4 | ||
|
|
91d91d3024 | ||
|
|
9784a2b6c5 | ||
|
|
87a3301912 | ||
|
|
295795edc9 | ||
|
|
6120ab66ba | ||
|
|
7bea180c58 | ||
|
|
a29cee488e | ||
|
|
74b4b04693 | ||
|
|
b8b9c80bdc | ||
|
|
a50fc74117 | ||
|
|
c1af438a3a | ||
|
|
80b251cddc | ||
|
|
7d9a48818e | ||
|
|
ca3da0839b | ||
|
|
cf463d8fa1 | ||
|
|
635fdc4c5c | ||
|
|
3e913931c4 | ||
|
|
46420da038 | ||
|
|
d5b7619dd1 | ||
|
|
89b39123da | ||
|
|
5a43137984 | ||
|
|
761b07450f | ||
|
|
a0b67a06f4 | ||
|
|
59d7adb66d |
16
.github/workflows/github_release.yml
vendored
16
.github/workflows/github_release.yml
vendored
@@ -6,19 +6,15 @@ on:
|
|||||||
- '[0-9]+.[0-9]+.[0-9]+'
|
- '[0-9]+.[0-9]+.[0-9]+'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Setup JDK 8
|
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 8
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: setup
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Setup JDK 17
|
||||||
|
uses: actions/setup-java@v2
|
||||||
|
with:
|
||||||
|
distribution: 'zulu'
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Cache Gradle and wrapper
|
- name: Cache Gradle and wrapper
|
||||||
|
|||||||
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -7,7 +7,7 @@
|
|||||||
<option name="testRunner" value="GRADLE" />
|
<option name="testRunner" value="GRADLE" />
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleJvm" value="11" />
|
<option name="gradleJvm" value="17" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -191,7 +191,7 @@
|
|||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" 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">
|
||||||
|
|||||||
@@ -33,12 +33,8 @@ Tempo does not rely on magic algorithms to decide what you should listen to. Ins
|
|||||||
<img src="mockup/feat/6_screenshot.png" width=200>
|
<img src="mockup/feat/6_screenshot.png" width=200>
|
||||||
<img src="mockup/feat/7_screenshot.png" width=200>
|
<img src="mockup/feat/7_screenshot.png" width=200>
|
||||||
<img src="mockup/feat/8_screenshot.png" width=200>
|
<img src="mockup/feat/8_screenshot.png" width=200>
|
||||||
<img src="mockup/feat/9_screenshot.png" width=200>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Disclaimer
|
|
||||||
Tempo is currently under active development and is in alpha state. This means that the app may contain stability issues, bugs, or incomplete features. While we strive to provide a smooth and reliable experience, please be aware that using Tempo in its current state may not be as stable as a fully released version. I appreciate your understanding and patience as I work towards improving the app.
|
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
Tempo is an open-source project developed and maintained solely by me. I would like to express my heartfelt thanks to all the users who have shown their love and support for Tempo. Your contributions and encouragement mean a lot to me, and they help drive the development and improvement of the app.
|
Tempo is an open-source project developed and maintained solely by me. I would like to express my heartfelt thanks to all the users who have shown their love and support for Tempo. Your contributions and encouragement mean a lot to me, and they help drive the development and improvement of the app.
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ apply plugin: 'kotlin-android'
|
|||||||
apply plugin: 'kotlin-parcelize'
|
apply plugin: 'kotlin-parcelize'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 34
|
compileSdk 34
|
||||||
buildToolsVersion '33.0.0'
|
buildToolsVersion "34.0.0"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 24
|
minSdkVersion 24
|
||||||
@@ -28,8 +28,8 @@ android {
|
|||||||
tempo {
|
tempo {
|
||||||
dimension "default"
|
dimension "default"
|
||||||
applicationId 'com.cappielloantonio.tempo'
|
applicationId 'com.cappielloantonio.tempo'
|
||||||
versionCode 15
|
versionCode 17
|
||||||
versionName '3.4.9'
|
versionName '3.5.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
notquitemy {
|
notquitemy {
|
||||||
@@ -77,22 +77,23 @@ dependencies {
|
|||||||
implementation 'androidx.recyclerview:recyclerview:1.3.1'
|
implementation 'androidx.recyclerview:recyclerview:1.3.1'
|
||||||
implementation 'androidx.room:room-runtime:2.5.2'
|
implementation 'androidx.room:room-runtime:2.5.2'
|
||||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||||
|
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||||
|
|
||||||
// Android Material
|
// Android Material
|
||||||
implementation 'com.google.android.material:material:1.9.0'
|
implementation 'com.google.android.material:material:1.9.0'
|
||||||
|
|
||||||
// Glide
|
// Glide
|
||||||
implementation 'com.github.bumptech.glide:glide:4.15.1'
|
implementation 'com.github.bumptech.glide:glide:4.16.0'
|
||||||
implementation 'com.github.bumptech.glide:annotations:4.15.1'
|
implementation 'com.github.bumptech.glide:annotations:4.16.0'
|
||||||
|
|
||||||
// Media3
|
// Media3
|
||||||
implementation 'androidx.media3:media3-session:1.1.0'
|
implementation 'androidx.media3:media3-session:1.1.1'
|
||||||
implementation 'androidx.media3:media3-common:1.1.0'
|
implementation 'androidx.media3:media3-common:1.1.1'
|
||||||
implementation 'androidx.media3:media3-exoplayer:1.1.0'
|
implementation 'androidx.media3:media3-exoplayer:1.1.1'
|
||||||
implementation 'androidx.media3:media3-ui:1.1.0'
|
implementation 'androidx.media3:media3-ui:1.1.1'
|
||||||
tempoImplementation 'androidx.media3:media3-cast:1.1.0'
|
tempoImplementation 'androidx.media3:media3-cast:1.1.1'
|
||||||
|
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
|
||||||
annotationProcessor 'androidx.room:room-compiler:2.5.2'
|
annotationProcessor 'androidx.room:room-compiler:2.5.2'
|
||||||
|
|
||||||
// Retrofit
|
// Retrofit
|
||||||
|
|||||||
@@ -0,0 +1,797 @@
|
|||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 3,
|
||||||
|
"identityHash": "6ea111217793c58d54eabb1190dd92ec",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "queue",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `track_order` INTEGER NOT NULL, `last_play` INTEGER NOT NULL, `playing_changed` INTEGER NOT NULL, `stream_id` TEXT, `parent_id` TEXT, `is_dir` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `artist` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `cover_art_id` TEXT, `size` INTEGER, `content_type` TEXT, `suffix` TEXT, `transcoding_content_type` TEXT, `transcoded_suffix` TEXT, `duration` INTEGER, `bitrate` INTEGER, `path` TEXT, `is_video` INTEGER NOT NULL, `user_rating` INTEGER, `average_rating` REAL, `play_count` INTEGER, `disc_number` INTEGER, `created` INTEGER, `starred` INTEGER, `album_id` TEXT, `artist_id` TEXT, `type` TEXT, `bookmark_position` INTEGER, `original_width` INTEGER, `original_height` INTEGER, PRIMARY KEY(`track_order`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "trackOrder",
|
||||||
|
"columnName": "track_order",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastPlay",
|
||||||
|
"columnName": "last_play",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playingChanged",
|
||||||
|
"columnName": "playing_changed",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "streamId",
|
||||||
|
"columnName": "stream_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parentId",
|
||||||
|
"columnName": "parent_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isDir",
|
||||||
|
"columnName": "is_dir",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "album",
|
||||||
|
"columnName": "album",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "artist",
|
||||||
|
"columnName": "artist",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "track",
|
||||||
|
"columnName": "track",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "year",
|
||||||
|
"columnName": "year",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "genre",
|
||||||
|
"columnName": "genre",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "coverArtId",
|
||||||
|
"columnName": "cover_art_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "size",
|
||||||
|
"columnName": "size",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "contentType",
|
||||||
|
"columnName": "content_type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "suffix",
|
||||||
|
"columnName": "suffix",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "transcodedContentType",
|
||||||
|
"columnName": "transcoding_content_type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "transcodedSuffix",
|
||||||
|
"columnName": "transcoded_suffix",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bitrate",
|
||||||
|
"columnName": "bitrate",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isVideo",
|
||||||
|
"columnName": "is_video",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "userRating",
|
||||||
|
"columnName": "user_rating",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "averageRating",
|
||||||
|
"columnName": "average_rating",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playCount",
|
||||||
|
"columnName": "play_count",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "discNumber",
|
||||||
|
"columnName": "disc_number",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "created",
|
||||||
|
"columnName": "created",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "starred",
|
||||||
|
"columnName": "starred",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "albumId",
|
||||||
|
"columnName": "album_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "artistId",
|
||||||
|
"columnName": "artist_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bookmarkPosition",
|
||||||
|
"columnName": "bookmark_position",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "originalWidth",
|
||||||
|
"columnName": "original_width",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "originalHeight",
|
||||||
|
"columnName": "original_height",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"track_order"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "server",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `server_name` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, `address` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `low_security` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "serverId",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "serverName",
|
||||||
|
"columnName": "server_name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "username",
|
||||||
|
"columnName": "username",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "password",
|
||||||
|
"columnName": "password",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "address",
|
||||||
|
"columnName": "address",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timestamp",
|
||||||
|
"columnName": "timestamp",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isLowSecurity",
|
||||||
|
"columnName": "low_security",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "recent_search",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`search` TEXT NOT NULL, PRIMARY KEY(`search`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "search",
|
||||||
|
"columnName": "search",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"search"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "download",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `playlist_id` TEXT, `playlist_name` TEXT, `download_state` INTEGER NOT NULL DEFAULT 1, `download_uri` TEXT DEFAULT '', `parent_id` TEXT, `is_dir` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `artist` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `cover_art_id` TEXT, `size` INTEGER, `content_type` TEXT, `suffix` TEXT, `transcoding_content_type` TEXT, `transcoded_suffix` TEXT, `duration` INTEGER, `bitrate` INTEGER, `path` TEXT, `is_video` INTEGER NOT NULL, `user_rating` INTEGER, `average_rating` REAL, `play_count` INTEGER, `disc_number` INTEGER, `created` INTEGER, `starred` INTEGER, `album_id` TEXT, `artist_id` TEXT, `type` TEXT, `bookmark_position` INTEGER, `original_width` INTEGER, `original_height` INTEGER, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playlistId",
|
||||||
|
"columnName": "playlist_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playlistName",
|
||||||
|
"columnName": "playlist_name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadState",
|
||||||
|
"columnName": "download_state",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadUri",
|
||||||
|
"columnName": "download_uri",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false,
|
||||||
|
"defaultValue": "''"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parentId",
|
||||||
|
"columnName": "parent_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isDir",
|
||||||
|
"columnName": "is_dir",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "album",
|
||||||
|
"columnName": "album",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "artist",
|
||||||
|
"columnName": "artist",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "track",
|
||||||
|
"columnName": "track",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "year",
|
||||||
|
"columnName": "year",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "genre",
|
||||||
|
"columnName": "genre",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "coverArtId",
|
||||||
|
"columnName": "cover_art_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "size",
|
||||||
|
"columnName": "size",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "contentType",
|
||||||
|
"columnName": "content_type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "suffix",
|
||||||
|
"columnName": "suffix",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "transcodedContentType",
|
||||||
|
"columnName": "transcoding_content_type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "transcodedSuffix",
|
||||||
|
"columnName": "transcoded_suffix",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bitrate",
|
||||||
|
"columnName": "bitrate",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isVideo",
|
||||||
|
"columnName": "is_video",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "userRating",
|
||||||
|
"columnName": "user_rating",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "averageRating",
|
||||||
|
"columnName": "average_rating",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playCount",
|
||||||
|
"columnName": "play_count",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "discNumber",
|
||||||
|
"columnName": "disc_number",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "created",
|
||||||
|
"columnName": "created",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "starred",
|
||||||
|
"columnName": "starred",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "albumId",
|
||||||
|
"columnName": "album_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "artistId",
|
||||||
|
"columnName": "artist_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bookmarkPosition",
|
||||||
|
"columnName": "bookmark_position",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "originalWidth",
|
||||||
|
"columnName": "original_width",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "originalHeight",
|
||||||
|
"columnName": "original_height",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "chronology",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `server` TEXT, `parent_id` TEXT, `is_dir` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `artist` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `cover_art_id` TEXT, `size` INTEGER, `content_type` TEXT, `suffix` TEXT, `transcoding_content_type` TEXT, `transcoded_suffix` TEXT, `duration` INTEGER, `bitrate` INTEGER, `path` TEXT, `is_video` INTEGER NOT NULL, `user_rating` INTEGER, `average_rating` REAL, `play_count` INTEGER, `disc_number` INTEGER, `created` INTEGER, `starred` INTEGER, `album_id` TEXT, `artist_id` TEXT, `type` TEXT, `bookmark_position` INTEGER, `original_width` INTEGER, `original_height` INTEGER, PRIMARY KEY(`id`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "timestamp",
|
||||||
|
"columnName": "timestamp",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "server",
|
||||||
|
"columnName": "server",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "parentId",
|
||||||
|
"columnName": "parent_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isDir",
|
||||||
|
"columnName": "is_dir",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "album",
|
||||||
|
"columnName": "album",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "artist",
|
||||||
|
"columnName": "artist",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "track",
|
||||||
|
"columnName": "track",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "year",
|
||||||
|
"columnName": "year",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "genre",
|
||||||
|
"columnName": "genre",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "coverArtId",
|
||||||
|
"columnName": "cover_art_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "size",
|
||||||
|
"columnName": "size",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "contentType",
|
||||||
|
"columnName": "content_type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "suffix",
|
||||||
|
"columnName": "suffix",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "transcodedContentType",
|
||||||
|
"columnName": "transcoding_content_type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "transcodedSuffix",
|
||||||
|
"columnName": "transcoded_suffix",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bitrate",
|
||||||
|
"columnName": "bitrate",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "path",
|
||||||
|
"columnName": "path",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isVideo",
|
||||||
|
"columnName": "is_video",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "userRating",
|
||||||
|
"columnName": "user_rating",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "averageRating",
|
||||||
|
"columnName": "average_rating",
|
||||||
|
"affinity": "REAL",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "playCount",
|
||||||
|
"columnName": "play_count",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "discNumber",
|
||||||
|
"columnName": "disc_number",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "created",
|
||||||
|
"columnName": "created",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "starred",
|
||||||
|
"columnName": "starred",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "albumId",
|
||||||
|
"columnName": "album_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "artistId",
|
||||||
|
"columnName": "artist_id",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "bookmarkPosition",
|
||||||
|
"columnName": "bookmark_position",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "originalWidth",
|
||||||
|
"columnName": "original_width",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "originalHeight",
|
||||||
|
"columnName": "original_height",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "favorite",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`timestamp` INTEGER NOT NULL, `songId` TEXT, `albumId` TEXT, `artistId` TEXT, `toStar` INTEGER NOT NULL, PRIMARY KEY(`timestamp`))",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "timestamp",
|
||||||
|
"columnName": "timestamp",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "songId",
|
||||||
|
"columnName": "songId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "albumId",
|
||||||
|
"columnName": "albumId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "artistId",
|
||||||
|
"columnName": "artistId",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "toStar",
|
||||||
|
"columnName": "toStar",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": false,
|
||||||
|
"columnNames": [
|
||||||
|
"timestamp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6ea111217793c58d54eabb1190dd92ec')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,54 +1,71 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="App"
|
android:name="App"
|
||||||
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:localeConfig="@xml/locale_config"
|
||||||
android:roundIcon="@mipmap/ic_launcher"
|
android:roundIcon="@mipmap/ic_launcher"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme.SplashScreen"
|
android:theme="@style/AppTheme.SplashScreen"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true">
|
||||||
android:allowBackup="false">
|
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||||
android:value="androidx.media3.cast.DefaultCastOptionsProvider"/>
|
android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="androidx.car.app.TintableAttributionIcon"
|
||||||
|
android:resource="@drawable/ic_graphic_eq" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.activity.MainActivity"
|
android:name=".ui.activity.MainActivity"
|
||||||
android:windowSoftInputMode="adjustPan|adjustResize"
|
android:exported="true"
|
||||||
android:exported="true">
|
android:windowSoftInputMode="adjustPan|adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.MediaService"
|
android:name=".service.MediaService"
|
||||||
android:foregroundServiceType="mediaPlayback"
|
android:exported="true"
|
||||||
android:exported="true">
|
android:foregroundServiceType="mediaPlayback">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="androidx.media3.session.MediaLibraryService" />
|
<action android:name="androidx.media3.session.MediaLibraryService" />
|
||||||
<action android:name="androidx.media3.session.MediaBrowserService" />
|
<action android:name="androidx.media3.session.MediaBrowserService" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
<service android:name=".service.DownloaderService"
|
|
||||||
android:foregroundServiceType="dataSync"
|
<service
|
||||||
android:exported="true">
|
android:name=".service.DownloaderService"
|
||||||
|
android:exported="true"
|
||||||
|
android:foregroundServiceType="dataSync">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="androidx.media3.exoplayer.downloadService.action.RESTART"/>
|
<action android:name="androidx.media3.exoplayer.downloadService.action.RESTART" />
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
|
||||||
|
android:enabled="false"
|
||||||
|
android:exported="false">
|
||||||
|
<meta-data
|
||||||
|
android:name="autoStoreLocales"
|
||||||
|
android:value="true" />
|
||||||
|
</service>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -10,7 +10,6 @@ import com.cappielloantonio.tempo.helper.ThemeHelper;
|
|||||||
import com.cappielloantonio.tempo.subsonic.Subsonic;
|
import com.cappielloantonio.tempo.subsonic.Subsonic;
|
||||||
import com.cappielloantonio.tempo.subsonic.SubsonicPreferences;
|
import com.cappielloantonio.tempo.subsonic.SubsonicPreferences;
|
||||||
import com.cappielloantonio.tempo.util.Preferences;
|
import com.cappielloantonio.tempo.util.Preferences;
|
||||||
import com.google.android.material.color.DynamicColors;
|
|
||||||
|
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
private static App instance;
|
private static App instance;
|
||||||
@@ -22,7 +21,6 @@ public class App extends Application {
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
DynamicColors.applyToActivitiesIfAvailable(this);
|
|
||||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||||
String themePref = sharedPreferences.getString(Preferences.THEME, ThemeHelper.DEFAULT_MODE);
|
String themePref = sharedPreferences.getString(Preferences.THEME, ThemeHelper.DEFAULT_MODE);
|
||||||
ThemeHelper.applyTheme(themePref);
|
ThemeHelper.applyTheme(themePref);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import com.bumptech.glide.request.RequestOptions;
|
|||||||
import com.bumptech.glide.signature.ObjectKey;
|
import com.bumptech.glide.signature.ObjectKey;
|
||||||
import com.cappielloantonio.tempo.App;
|
import com.cappielloantonio.tempo.App;
|
||||||
import com.cappielloantonio.tempo.util.Preferences;
|
import com.cappielloantonio.tempo.util.Preferences;
|
||||||
|
import com.cappielloantonio.tempo.util.Util;
|
||||||
import com.google.android.material.elevation.SurfaceColors;
|
import com.google.android.material.elevation.SurfaceColors;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -46,7 +47,7 @@ public class CustomGlideRequest {
|
|||||||
uri.append("getCoverArt");
|
uri.append("getCoverArt");
|
||||||
|
|
||||||
if (params.containsKey("u") && params.get("u") != null)
|
if (params.containsKey("u") && params.get("u") != null)
|
||||||
uri.append("?u=").append(params.get("u"));
|
uri.append("?u=").append(Util.encode(params.get("u")));
|
||||||
if (params.containsKey("p") && params.get("p") != null)
|
if (params.containsKey("p") && params.get("p") != null)
|
||||||
uri.append("&p=").append(params.get("p"));
|
uri.append("&p=").append(params.get("p"));
|
||||||
if (params.containsKey("s") && params.get("s") != null)
|
if (params.containsKey("s") && params.get("s") != null)
|
||||||
|
|||||||
@@ -63,8 +63,10 @@ public class ArtistRepository {
|
|||||||
if (response.isSuccessful() && response.body() != null) {
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
List<ArtistID3> artists = new ArrayList<>();
|
List<ArtistID3> artists = new ArrayList<>();
|
||||||
|
|
||||||
for (IndexID3 index : response.body().getSubsonicResponse().getArtists().getIndices()) {
|
if(response.body().getSubsonicResponse().getArtists() != null) {
|
||||||
artists.addAll(index.getArtists());
|
for (IndexID3 index : response.body().getSubsonicResponse().getArtists().getIndices()) {
|
||||||
|
artists.addAll(index.getArtists());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (random) {
|
if (random) {
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ public class DownloaderManager {
|
|||||||
public void removeAll() {
|
public void removeAll() {
|
||||||
DownloadService.sendRemoveAllDownloads(context, DownloaderService.class, false);
|
DownloadService.sendRemoveAllDownloads(context, DownloaderService.class, false);
|
||||||
deleteAllDatabase();
|
deleteAllDatabase();
|
||||||
|
DownloadUtil.eraseDownloadFolder(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadDownloads() {
|
private void loadDownloads() {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import com.cappielloantonio.tempo.util.Preferences;
|
|||||||
import com.cappielloantonio.tempo.viewmodel.MainViewModel;
|
import com.cappielloantonio.tempo.viewmodel.MainViewModel;
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
|
import com.google.android.material.color.DynamicColors;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -51,10 +52,10 @@ public class MainActivity extends BaseActivity {
|
|||||||
|
|
||||||
ConnectivityStatusBroadcastReceiver connectivityStatusBroadcastReceiver;
|
ConnectivityStatusBroadcastReceiver connectivityStatusBroadcastReceiver;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
SplashScreen.installSplashScreen(this);
|
SplashScreen.installSplashScreen(this);
|
||||||
|
DynamicColors.applyToActivityIfAvailable(this);
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
@@ -118,6 +119,8 @@ public class MainActivity extends BaseActivity {
|
|||||||
fragmentManager.beginTransaction().replace(R.id.player_bottom_sheet, new PlayerBottomSheetFragment(), "PlayerBottomSheet").commit();
|
fragmentManager.beginTransaction().replace(R.id.player_bottom_sheet, new PlayerBottomSheetFragment(), "PlayerBottomSheet").commit();
|
||||||
|
|
||||||
setBottomSheetInPeek(mainViewModel.isQueueLoaded());
|
setBottomSheetInPeek(mainViewModel.isQueueLoaded());
|
||||||
|
|
||||||
|
collapseBottomSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBottomSheetInPeek(Boolean isVisible) {
|
public void setBottomSheetInPeek(Boolean isVisible) {
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public class BaseActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setNavigationBarColor() {
|
private void setNavigationBarColor() {
|
||||||
getWindow().setNavigationBarColor(SurfaceColors.getColorForElevation(this, 10));
|
getWindow().setNavigationBarColor(SurfaceColors.getColorForElevation(this, 8));
|
||||||
|
getWindow().setStatusBarColor(SurfaceColors.getColorForElevation(this, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
|
|||||||
|
|
||||||
switch (view) {
|
switch (view) {
|
||||||
case Constants.DOWNLOAD_TYPE_TRACK:
|
case Constants.DOWNLOAD_TYPE_TRACK:
|
||||||
bundle.putParcelableArrayList(Constants.TRACKS_OBJECT, new ArrayList<>(songs));
|
bundle.putParcelableArrayList(Constants.TRACKS_OBJECT, new ArrayList<>(grouped));
|
||||||
bundle.putInt(Constants.ITEM_POSITION, getBindingAdapterPosition());
|
bundle.putInt(Constants.ITEM_POSITION, getBindingAdapterPosition());
|
||||||
click.onMediaClick(bundle);
|
click.onMediaClick(bundle);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter<SongHorizontalAd
|
|||||||
public void onClick() {
|
public void onClick() {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putParcelableArrayList(Constants.TRACKS_OBJECT, new ArrayList<>(MusicUtil.limitPlayableMedia(songs, getBindingAdapterPosition())));
|
bundle.putParcelableArrayList(Constants.TRACKS_OBJECT, new ArrayList<>(MusicUtil.limitPlayableMedia(songs, getBindingAdapterPosition())));
|
||||||
bundle.putInt(Constants.ITEM_POSITION, MusicUtil.getPlayableMediaPosition(getBindingAdapterPosition()));
|
bundle.putInt(Constants.ITEM_POSITION, MusicUtil.getPlayableMediaPosition(songs, getBindingAdapterPosition()));
|
||||||
|
|
||||||
click.onMediaClick(bundle);
|
click.onMediaClick(bundle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class PlayerBottomSheetFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void customizeBottomSheetBackground() {
|
private void customizeBottomSheetBackground() {
|
||||||
bind.playerHeaderLayout.getRoot().setBackgroundColor(SurfaceColors.getColorForElevation(requireContext(), 2));
|
bind.playerHeaderLayout.getRoot().setBackgroundColor(SurfaceColors.getColorForElevation(requireContext(), 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void customizeBottomSheetAction() {
|
private void customizeBottomSheetAction() {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import androidx.activity.result.contract.ActivityResultContracts;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.OptIn;
|
import androidx.annotation.OptIn;
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate;
|
||||||
|
import androidx.core.os.LocaleListCompat;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.preference.ListPreference;
|
import androidx.preference.ListPreference;
|
||||||
@@ -28,8 +30,12 @@ import com.cappielloantonio.tempo.ui.dialog.DeleteDownloadStorageDialog;
|
|||||||
import com.cappielloantonio.tempo.ui.dialog.DownloadStorageDialog;
|
import com.cappielloantonio.tempo.ui.dialog.DownloadStorageDialog;
|
||||||
import com.cappielloantonio.tempo.ui.dialog.StarredSyncDialog;
|
import com.cappielloantonio.tempo.ui.dialog.StarredSyncDialog;
|
||||||
import com.cappielloantonio.tempo.util.Preferences;
|
import com.cappielloantonio.tempo.util.Preferences;
|
||||||
|
import com.cappielloantonio.tempo.util.UIUtil;
|
||||||
import com.cappielloantonio.tempo.viewmodel.SettingViewModel;
|
import com.cappielloantonio.tempo.viewmodel.SettingViewModel;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@OptIn(markerClass = UnstableApi.class)
|
@OptIn(markerClass = UnstableApi.class)
|
||||||
public class SettingsFragment extends PreferenceFragmentCompat {
|
public class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
private static final String TAG = "SettingsFragment";
|
private static final String TAG = "SettingsFragment";
|
||||||
@@ -75,63 +81,16 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
checkEqualizer();
|
checkEqualizer();
|
||||||
|
|
||||||
checkStorage();
|
checkStorage();
|
||||||
|
|
||||||
findPreference("version").setSummary(BuildConfig.VERSION_NAME);
|
setAppLanguage();
|
||||||
|
setVersion();
|
||||||
|
|
||||||
findPreference("logout").setOnPreferenceClickListener(preference -> {
|
actionLogout();
|
||||||
activity.quit();
|
actionScan();
|
||||||
return true;
|
actionSyncStarredTracks();
|
||||||
});
|
actionChangeDownloadStorage();
|
||||||
|
actionDeleteDownloadStorage();
|
||||||
findPreference("scan_library").setOnPreferenceClickListener(preference -> {
|
|
||||||
settingViewModel.launchScan(new ScanCallback() {
|
|
||||||
@Override
|
|
||||||
public void onError(Exception exception) {
|
|
||||||
findPreference("scan_library").setSummary(exception.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSuccess(boolean isScanning, long count) {
|
|
||||||
getScanStatus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference("sync_starred_tracks_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
|
||||||
if (newValue instanceof Boolean) {
|
|
||||||
if ((Boolean) newValue) {
|
|
||||||
StarredSyncDialog dialog = new StarredSyncDialog();
|
|
||||||
dialog.show(activity.getSupportFragmentManager(), null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference("download_storage").setOnPreferenceClickListener(preference -> {
|
|
||||||
DownloadStorageDialog dialog = new DownloadStorageDialog(new DialogClickCallback() {
|
|
||||||
@Override
|
|
||||||
public void onPositiveClick() {
|
|
||||||
findPreference("download_storage").setSummary(R.string.download_storage_external_dialog_positive_button);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNegativeClick() {
|
|
||||||
findPreference("download_storage").setSummary(R.string.download_storage_internal_dialog_negative_button);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialog.show(activity.getSupportFragmentManager(), null);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
findPreference("delete_download_storage").setOnPreferenceClickListener(preference -> {
|
|
||||||
DeleteDownloadStorageDialog dialog = new DeleteDownloadStorageDialog();
|
|
||||||
dialog.show(activity.getSupportFragmentManager(), null);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -187,6 +146,94 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setAppLanguage() {
|
||||||
|
ListPreference localePref = (ListPreference) findPreference("language");
|
||||||
|
|
||||||
|
Map<String, String> locales = UIUtil.getLangPreferenceDropdownEntries(requireContext());
|
||||||
|
|
||||||
|
CharSequence[] entries = locales.keySet().toArray(new CharSequence[locales.size()]);
|
||||||
|
CharSequence[] entryValues = locales.values().toArray(new CharSequence[locales.size()]);
|
||||||
|
|
||||||
|
localePref.setEntries(entries);
|
||||||
|
localePref.setEntryValues(entryValues);
|
||||||
|
|
||||||
|
localePref.setDefaultValue(entryValues[0]);
|
||||||
|
localePref.setSummary(Locale.forLanguageTag(localePref.getValue()).getDisplayLanguage());
|
||||||
|
|
||||||
|
localePref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
LocaleListCompat appLocale = LocaleListCompat.forLanguageTags((String) newValue);
|
||||||
|
AppCompatDelegate.setApplicationLocales(appLocale);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setVersion() {
|
||||||
|
findPreference("version").setSummary(BuildConfig.VERSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionLogout() {
|
||||||
|
findPreference("logout").setOnPreferenceClickListener(preference -> {
|
||||||
|
activity.quit();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionScan() {
|
||||||
|
findPreference("scan_library").setOnPreferenceClickListener(preference -> {
|
||||||
|
settingViewModel.launchScan(new ScanCallback() {
|
||||||
|
@Override
|
||||||
|
public void onError(Exception exception) {
|
||||||
|
findPreference("scan_library").setSummary(exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(boolean isScanning, long count) {
|
||||||
|
getScanStatus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionSyncStarredTracks() {
|
||||||
|
findPreference("sync_starred_tracks_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
if (newValue instanceof Boolean) {
|
||||||
|
if ((Boolean) newValue) {
|
||||||
|
StarredSyncDialog dialog = new StarredSyncDialog();
|
||||||
|
dialog.show(activity.getSupportFragmentManager(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionChangeDownloadStorage() {
|
||||||
|
findPreference("download_storage").setOnPreferenceClickListener(preference -> {
|
||||||
|
DownloadStorageDialog dialog = new DownloadStorageDialog(new DialogClickCallback() {
|
||||||
|
@Override
|
||||||
|
public void onPositiveClick() {
|
||||||
|
findPreference("download_storage").setSummary(R.string.download_storage_external_dialog_positive_button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNegativeClick() {
|
||||||
|
findPreference("download_storage").setSummary(R.string.download_storage_internal_dialog_negative_button);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialog.show(activity.getSupportFragmentManager(), null);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionDeleteDownloadStorage() {
|
||||||
|
findPreference("delete_download_storage").setOnPreferenceClickListener(preference -> {
|
||||||
|
DeleteDownloadStorageDialog dialog = new DeleteDownloadStorageDialog();
|
||||||
|
dialog.show(activity.getSupportFragmentManager(), null);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void getScanStatus() {
|
private void getScanStatus() {
|
||||||
settingViewModel.getScanStatus(new ScanCallback() {
|
settingViewModel.getScanStatus(new ScanCallback() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.cappielloantonio.tempo.util;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.database.DatabaseProvider;
|
import androidx.media3.database.DatabaseProvider;
|
||||||
import androidx.media3.database.StandaloneDatabaseProvider;
|
import androidx.media3.database.StandaloneDatabaseProvider;
|
||||||
@@ -23,6 +24,8 @@ import java.io.File;
|
|||||||
import java.net.CookieHandler;
|
import java.net.CookieHandler;
|
||||||
import java.net.CookieManager;
|
import java.net.CookieManager;
|
||||||
import java.net.CookiePolicy;
|
import java.net.CookiePolicy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
@@ -153,4 +156,32 @@ public final class DownloadUtil {
|
|||||||
.setCacheWriteDataSinkFactory(null)
|
.setCacheWriteDataSinkFactory(null)
|
||||||
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
|
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static synchronized void eraseDownloadFolder(Context context) {
|
||||||
|
File directory = getDownloadDirectory(context);
|
||||||
|
|
||||||
|
ArrayList<File> files = listFiles(directory, new ArrayList<>());
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static synchronized ArrayList<File> listFiles(File directory, ArrayList<File> files) {
|
||||||
|
if (directory.isDirectory()) {
|
||||||
|
File[] list = directory.listFiles();
|
||||||
|
|
||||||
|
if (list != null) {
|
||||||
|
for (File file : list) {
|
||||||
|
if (file.isFile() && file.getName().toLowerCase().endsWith(".exo")) {
|
||||||
|
files.add(file);
|
||||||
|
} else if (file.isDirectory()) {
|
||||||
|
listFiles(file, files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,9 +223,9 @@ public class MappingUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Uri getUri(PodcastEpisode podcastEpisode) {
|
private static Uri getUri(PodcastEpisode podcastEpisode) {
|
||||||
return DownloadUtil.getDownloadTracker(App.getContext()).isDownloaded(podcastEpisode.getId())
|
return DownloadUtil.getDownloadTracker(App.getContext()).isDownloaded(podcastEpisode.getStreamId())
|
||||||
? getDownloadUri(podcastEpisode.getId())
|
? getDownloadUri(podcastEpisode.getStreamId())
|
||||||
: MusicUtil.getStreamUri(podcastEpisode.getId());
|
: MusicUtil.getStreamUri(podcastEpisode.getStreamId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Uri getDownloadUri(String id) {
|
private static Uri getDownloadUri(String id) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class MusicUtil {
|
|||||||
uri.append("stream");
|
uri.append("stream");
|
||||||
|
|
||||||
if (params.containsKey("u") && params.get("u") != null)
|
if (params.containsKey("u") && params.get("u") != null)
|
||||||
uri.append("?u=").append(params.get("u"));
|
uri.append("?u=").append(Util.encode(params.get("u")));
|
||||||
if (params.containsKey("p") && params.get("p") != null)
|
if (params.containsKey("p") && params.get("p") != null)
|
||||||
uri.append("&p=").append(params.get("p"));
|
uri.append("&p=").append(params.get("p"));
|
||||||
if (params.containsKey("s") && params.get("s") != null)
|
if (params.containsKey("s") && params.get("s") != null)
|
||||||
@@ -68,7 +68,7 @@ public class MusicUtil {
|
|||||||
uri.append("download");
|
uri.append("download");
|
||||||
|
|
||||||
if (params.containsKey("u") && params.get("u") != null)
|
if (params.containsKey("u") && params.get("u") != null)
|
||||||
uri.append("?u=").append(params.get("u"));
|
uri.append("?u=").append(Util.encode(params.get("u")));
|
||||||
if (params.containsKey("p") && params.get("p") != null)
|
if (params.containsKey("p") && params.get("p") != null)
|
||||||
uri.append("&p=").append(params.get("p"));
|
uri.append("&p=").append(params.get("p"));
|
||||||
if (params.containsKey("s") && params.get("s") != null)
|
if (params.containsKey("s") && params.get("s") != null)
|
||||||
@@ -99,7 +99,7 @@ public class MusicUtil {
|
|||||||
uri.append("stream");
|
uri.append("stream");
|
||||||
|
|
||||||
if (params.containsKey("u") && params.get("u") != null)
|
if (params.containsKey("u") && params.get("u") != null)
|
||||||
uri.append("?u=").append(params.get("u"));
|
uri.append("?u=").append(Util.encode(params.get("u")));
|
||||||
if (params.containsKey("p") && params.get("p") != null)
|
if (params.containsKey("p") && params.get("p") != null)
|
||||||
uri.append("&p=").append(params.get("p"));
|
uri.append("&p=").append(params.get("p"));
|
||||||
if (params.containsKey("s") && params.get("s") != null)
|
if (params.containsKey("s") && params.get("s") != null)
|
||||||
@@ -271,8 +271,12 @@ public class MusicUtil {
|
|||||||
return toLimit;
|
return toLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getPlayableMediaPosition(int initialPosition) {
|
public static int getPlayableMediaPosition(List<Child> toLimit, int position) {
|
||||||
return Math.min(initialPosition, Constants.PRE_PLAYABLE_MEDIA);
|
if (!toLimit.isEmpty() && toLimit.size() > Constants.PLAYABLE_MEDIA_LIMIT) {
|
||||||
|
return Math.min(position, Constants.PRE_PLAYABLE_MEDIA);
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ConnectivityManager getConnectivityManager() {
|
private static ConnectivityManager getConnectivityManager() {
|
||||||
|
|||||||
@@ -5,8 +5,21 @@ import android.content.res.TypedArray;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.InsetDrawable;
|
import android.graphics.drawable.InsetDrawable;
|
||||||
|
|
||||||
|
import androidx.core.os.LocaleListCompat;
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
|
|
||||||
|
import com.cappielloantonio.tempo.R;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class UIUtil {
|
public class UIUtil {
|
||||||
public static int getSpanCount(int itemCount, int maxSpan) {
|
public static int getSpanCount(int itemCount, int maxSpan) {
|
||||||
int itemSize = itemCount == 0 ? 1 : itemCount;
|
int itemSize = itemCount == 0 ? 1 : itemCount;
|
||||||
@@ -31,4 +44,44 @@ public class UIUtil {
|
|||||||
|
|
||||||
return itemDecoration;
|
return itemDecoration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static LocaleListCompat getLocalesFromResources(Context context) {
|
||||||
|
final List<String> tagsList = new ArrayList<>();
|
||||||
|
|
||||||
|
XmlPullParser xpp = context.getResources().getXml(R.xml.locale_config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (xpp.getEventType() != XmlPullParser.END_DOCUMENT) {
|
||||||
|
String tagName = xpp.getName();
|
||||||
|
|
||||||
|
if (xpp.getEventType() == XmlPullParser.START_TAG) {
|
||||||
|
if ("locale".equals(tagName) && xpp.getAttributeCount() > 0 && xpp.getAttributeName(0).equals("name")) {
|
||||||
|
tagsList.add(xpp.getAttributeValue(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xpp.next();
|
||||||
|
}
|
||||||
|
} catch (XmlPullParserException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return LocaleListCompat.forLanguageTags(String.join(",", tagsList));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> getLangPreferenceDropdownEntries(Context context) {
|
||||||
|
LocaleListCompat localeList = getLocalesFromResources(context);
|
||||||
|
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < localeList.size(); i++) {
|
||||||
|
Locale locale = localeList.get(i);
|
||||||
|
|
||||||
|
if (locale != null) {
|
||||||
|
map.put(Util.toPascalCase(locale.getDisplayName()), locale.toLanguageTag());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.cappielloantonio.tempo.util;
|
package com.cappielloantonio.tempo.util;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -14,4 +17,48 @@ public class Util {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toPascalCase(String name) {
|
||||||
|
if (name == null || name.isEmpty()) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder pascalCase = new StringBuilder();
|
||||||
|
|
||||||
|
char newChar;
|
||||||
|
boolean toUpper = false;
|
||||||
|
char[] charArray = name.toCharArray();
|
||||||
|
|
||||||
|
for (int ctr = 0; ctr <= charArray.length - 1; ctr++) {
|
||||||
|
if (ctr == 0) {
|
||||||
|
newChar = Character.toUpperCase(charArray[ctr]);
|
||||||
|
pascalCase = new StringBuilder(Character.toString(newChar));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charArray[ctr] == '_') {
|
||||||
|
toUpper = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toUpper) {
|
||||||
|
newChar = Character.toUpperCase(charArray[ctr]);
|
||||||
|
pascalCase.append(newChar);
|
||||||
|
toUpper = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pascalCase.append(charArray[ctr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pascalCase.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encode(String value) {
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,9 +73,11 @@ public class SongListPageViewModel extends AndroidViewModel {
|
|||||||
case Constants.MEDIA_BY_GENRE:
|
case Constants.MEDIA_BY_GENRE:
|
||||||
int page = (songList.getValue() != null ? songList.getValue().size() : 0) / 100;
|
int page = (songList.getValue() != null ? songList.getValue().size() : 0) / 100;
|
||||||
songRepository.getSongsByGenre(genre.getGenre(), page).observe(owner, children -> {
|
songRepository.getSongsByGenre(genre.getGenre(), page).observe(owner, children -> {
|
||||||
List<Child> currentMedia = songList.getValue();
|
if (children != null && !children.isEmpty()) {
|
||||||
currentMedia.addAll(children);
|
List<Child> currentMedia = songList.getValue();
|
||||||
songList.setValue(currentMedia);
|
currentMedia.addAll(children);
|
||||||
|
songList.setValue(currentMedia);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case Constants.MEDIA_BY_ARTIST:
|
case Constants.MEDIA_BY_ARTIST:
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="16dp"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -67,6 +67,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="16dp"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -69,6 +69,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="12dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -85,6 +85,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="16dp"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -57,6 +57,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="12dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin" />
|
app:layout_collapseMode="pin" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -67,6 +67,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="12dp"
|
||||||
android:paddingStart="2dp"
|
android:paddingStart="2dp"
|
||||||
android:paddingEnd="2dp"
|
android:paddingEnd="2dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
android:id="@+id/anim_toolbar"
|
android:id="@+id/anim_toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -50,6 +50,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="16dp"
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp"
|
android:paddingEnd="16dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
@@ -101,6 +102,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="16dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,13 @@
|
|||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
app:layout_collapseMode="pin"
|
app:layout_collapseMode="pin"
|
||||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar_layout"
|
android:id="@+id/app_bar_layout"
|
||||||
@@ -69,6 +69,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
android:paddingTop="12dp"
|
||||||
android:paddingBottom="@dimen/global_padding_bottom"
|
android:paddingBottom="@dimen/global_padding_bottom"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|||||||
@@ -181,9 +181,15 @@
|
|||||||
<string name="server_unreachable_dialog_summary">Der angefragte Server ist nicht erreichbar. Wenn Du trotzdem weitermachst, wird dieser Dialog für eine Stunden nicht wieder erscheinen.</string>
|
<string name="server_unreachable_dialog_summary">Der angefragte Server ist nicht erreichbar. Wenn Du trotzdem weitermachst, wird dieser Dialog für eine Stunden nicht wieder erscheinen.</string>
|
||||||
<string name="settings_about_summary">Tempo ist ein nativ für Android entwickelter, leichtgewichtiger Open-Source Client für Subsonic.</string>
|
<string name="settings_about_summary">Tempo ist ein nativ für Android entwickelter, leichtgewichtiger Open-Source Client für Subsonic.</string>
|
||||||
<string name="settings_about_title">Über</string>
|
<string name="settings_about_title">Über</string>
|
||||||
|
<string name="settings_audio_transcode_download_priority_summary">Diese Option deaktiviert die Transkodierungssettings für Downloads.</string>
|
||||||
|
<string name="settings_audio_transcode_download_priority_title">Transkodierungseinstellungen des Servers für Downloads bevorzugen.</string>
|
||||||
|
<string name="settings_audio_transcode_download_summary">Diese Option aktiviert das Transkodieren für heruntergeladene Tracks.</string>
|
||||||
|
<string name="settings_audio_transcode_download_title">Transkodierte Tracks herunterladen</string>
|
||||||
|
<string name="settings_audio_transcode_download_format">Transkodierungs-Format</string>
|
||||||
<string name="settings_audio_transcode_priority_summary">Diese Option deaktiviert die weiter unten folgenden Transkodierungseinstellungen.</string>
|
<string name="settings_audio_transcode_priority_summary">Diese Option deaktiviert die weiter unten folgenden Transkodierungseinstellungen.</string>
|
||||||
<string name="settings_audio_transcode_priority_title">Transkodierungseinstellungen des Servers bevorzugen</string>
|
<string name="settings_audio_transcode_priority_title">Transkodierungseinstellungen des Servers bevorzugen</string>
|
||||||
<string name="settings_audio_transcode_priority_toast">Servereinstellungen zur Transkodierung des Tracks werden bevorzugt</string>
|
<string name="settings_audio_transcode_priority_toast">Servereinstellungen zur Transkodierung des Tracks werden bevorzugt</string>
|
||||||
|
<string name="settings_audio_transcode_format_download">Transkodierungs-Format für Downloads</string>
|
||||||
<string name="settings_audio_transcode_format_mobile">Transkodierungsformat im mobilen Netz</string>
|
<string name="settings_audio_transcode_format_mobile">Transkodierungsformat im mobilen Netz</string>
|
||||||
<string name="settings_audio_transcode_format_wifi">Transkodierungsformat im Wi-Fi</string>
|
<string name="settings_audio_transcode_format_wifi">Transkodierungsformat im Wi-Fi</string>
|
||||||
<string name="settings_covers_cache">Größe des Artwork Caches</string>
|
<string name="settings_covers_cache">Größe des Artwork Caches</string>
|
||||||
@@ -198,7 +204,9 @@
|
|||||||
<string name="settings_github_summary">Verfolge die Entwicklung</string>
|
<string name="settings_github_summary">Verfolge die Entwicklung</string>
|
||||||
<string name="settings_github_title">Github</string>
|
<string name="settings_github_title">Github</string>
|
||||||
<string name="settings_image_size">Bilder Auflösung anpassen</string>
|
<string name="settings_image_size">Bilder Auflösung anpassen</string>
|
||||||
|
<string name="settings_language">Sprache</string>
|
||||||
<string name="settings_logout_title">Abmelden</string>
|
<string name="settings_logout_title">Abmelden</string>
|
||||||
|
<string name="settings_max_bitrate_download">Bitrate für Downloads</string>
|
||||||
<string name="settings_max_bitrate_wifi">Bitrate bei Wi-Fi Nutzung</string>
|
<string name="settings_max_bitrate_wifi">Bitrate bei Wi-Fi Nutzung</string>
|
||||||
<string name="settings_max_bitrate_mobile">Bitrate bei mobiler Nutzung</string>
|
<string name="settings_max_bitrate_mobile">Bitrate bei mobiler Nutzung</string>
|
||||||
<string name="settings_media_cache">Größe des Medienfile Caches</string>
|
<string name="settings_media_cache">Größe des Medienfile Caches</string>
|
||||||
@@ -220,6 +228,7 @@
|
|||||||
<string name="settings_summary_replay_gain">Replay-Gain ist ein Feature, das die Lautstärke von Tracks für ein konsistentes Hörerlebnis anpasst. Diese Einstellung funktioniert nur, wenn Tracks die entsprechenden Metadaten haben.</string>
|
<string name="settings_summary_replay_gain">Replay-Gain ist ein Feature, das die Lautstärke von Tracks für ein konsistentes Hörerlebnis anpasst. Diese Einstellung funktioniert nur, wenn Tracks die entsprechenden Metadaten haben.</string>
|
||||||
<string name="settings_summary_syncing">Den Zustand der Warteschlange synchronisieren. Das beinhaltet die Tracks in der Warteschlange, den aktuell gespielten Track und die Position innerhalb dieses Tracks. Der Server muss dieses Feature unterstützen.</string>
|
<string name="settings_summary_syncing">Den Zustand der Warteschlange synchronisieren. Das beinhaltet die Tracks in der Warteschlange, den aktuell gespielten Track und die Position innerhalb dieses Tracks. Der Server muss dieses Feature unterstützen.</string>
|
||||||
<string name="settings_summary_transcoding">Priorität des Transkodierungsmodus. \"Direktes Abspielen\" ändert die Bitrate der Dateien nicht.</string>
|
<string name="settings_summary_transcoding">Priorität des Transkodierungsmodus. \"Direktes Abspielen\" ändert die Bitrate der Dateien nicht.</string>
|
||||||
|
<string name="settings_summary_transcoding_download">Transkodierte Medien herunterladen. Diese Option deaktiviert den Download-Endpoint und benutzt stattdessen die folgenden Einstellungen. \n\n If \"Transkodierungs-Format\" ist auf \"Direktes Abspielen\" gesetzt, Die Bitrate des Tracks wird nicht geändert.</string>
|
||||||
<string name="settings_sync_starred_tracks_for_offline_use_summary">Lieblingslieder werden automatisch heruntergeladen.</string>
|
<string name="settings_sync_starred_tracks_for_offline_use_summary">Lieblingslieder werden automatisch heruntergeladen.</string>
|
||||||
<string name="settings_sync_starred_tracks_for_offline_use_title">Lieblingslieder für Offline-Modus sychronisieren</string>
|
<string name="settings_sync_starred_tracks_for_offline_use_title">Lieblingslieder für Offline-Modus sychronisieren</string>
|
||||||
<string name="settings_theme">Design</string>
|
<string name="settings_theme">Design</string>
|
||||||
@@ -228,6 +237,7 @@
|
|||||||
<string name="settings_title_replay_gain">Replay Gain</string>
|
<string name="settings_title_replay_gain">Replay Gain</string>
|
||||||
<string name="settings_title_syncing">Sychronisierung</string>
|
<string name="settings_title_syncing">Sychronisierung</string>
|
||||||
<string name="settings_title_transcoding">Transkodierung</string>
|
<string name="settings_title_transcoding">Transkodierung</string>
|
||||||
|
<string name="settings_title_transcoding_download">Transkodierung Download</string>
|
||||||
<string name="settings_title_ui">Benutzeroberfläche</string>
|
<string name="settings_title_ui">Benutzeroberfläche</string>
|
||||||
<string name="settings_transcoded_download">Transcoded download</string>
|
<string name="settings_transcoded_download">Transcoded download</string>
|
||||||
<string name="settings_version_title">Version</string>
|
<string name="settings_version_title">Version</string>
|
||||||
|
|||||||
@@ -206,6 +206,7 @@
|
|||||||
<string name="settings_github_summary">Follow the development</string>
|
<string name="settings_github_summary">Follow the development</string>
|
||||||
<string name="settings_github_title">Github</string>
|
<string name="settings_github_title">Github</string>
|
||||||
<string name="settings_image_size">Set image resolution</string>
|
<string name="settings_image_size">Set image resolution</string>
|
||||||
|
<string name="settings_language">Language</string>
|
||||||
<string name="settings_logout_title">Log out</string>
|
<string name="settings_logout_title">Log out</string>
|
||||||
<string name="settings_max_bitrate_download">Bitrate for downloads</string>
|
<string name="settings_max_bitrate_download">Bitrate for downloads</string>
|
||||||
<string name="settings_max_bitrate_wifi">Bitrate in Wi-Fi</string>
|
<string name="settings_max_bitrate_wifi">Bitrate in Wi-Fi</string>
|
||||||
|
|||||||
@@ -16,6 +16,12 @@
|
|||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory app:title="@string/settings_title_ui">
|
<PreferenceCategory app:title="@string/settings_title_ui">
|
||||||
|
<ListPreference
|
||||||
|
app:defaultValue="default"
|
||||||
|
app:dialogTitle="@string/settings_language"
|
||||||
|
app:key="language"
|
||||||
|
app:title="@string/settings_language"/>
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
app:defaultValue="default"
|
app:defaultValue="default"
|
||||||
app:dialogTitle="@string/settings_theme"
|
app:dialogTitle="@string/settings_theme"
|
||||||
|
|||||||
5
app/src/main/res/xml/locale_config.xml
Normal file
5
app/src/main/res/xml/locale_config.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<locale android:name="en"/> <!-- English -->
|
||||||
|
<locale android:name="de-DE"/> <!-- German -->
|
||||||
|
</locale-config>
|
||||||
@@ -4,7 +4,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
classpath 'com.android.tools.build:gradle:8.1.0'
|
||||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0'
|
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
#Mon Jun 19 19:28:49 CEST 2023
|
#Wed Aug 16 22:52:26 CEST 2023
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
Reference in New Issue
Block a user