Compare commits
7 Commits
bleeding-e
...
v4.13.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1beeab28a6 | ||
|
|
ad6a569961 | ||
|
|
0f5a8f6b97 | ||
|
|
3cd1bdf229 | ||
|
|
d7389db265 | ||
|
|
b3c93b3885 | ||
|
|
25864accc9 |
22
CHANGELOG.md
@@ -1,5 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
## What's Changed
|
||||
## [4.13.0](https://github.com/eddyizm/tempo/releases/tag/v4.13.0) (2026-03-25)
|
||||
* chore(i18n): Improve Russian translation by @NikkoFox in https://github.com/eddyizm/tempus/pull/503
|
||||
* feat: tile size manager by @MaFo-28 in https://github.com/eddyizm/tempus/pull/440
|
||||
* chore(i18n): Translated to zh_TW by @olivertzeng in https://github.com/eddyizm/tempus/pull/494
|
||||
* fix: Show full album name when displaying details by @jaime-grj in https://github.com/eddyizm/tempus/pull/508
|
||||
* chore(i18n): Update Spanish translation by @jaime-grj in https://github.com/eddyizm/tempus/pull/509
|
||||
* fix: Relocate "Offline mode" text by @jaime-grj in https://github.com/eddyizm/tempus/pull/510
|
||||
* chore(i18n): Update Polish translation by @skajmer in https://github.com/eddyizm/tempus/pull/516
|
||||
* refactor: navigation and bottom sheet by @tvillega in https://github.com/eddyizm/tempus/pull/491
|
||||
* feat: Logo refresh by @eddyizm in https://github.com/eddyizm/tempus/pull/498
|
||||
* feat: Add 'genres' page/function to Android Auto by @Jorilx in https://github.com/eddyizm/tempus/pull/505
|
||||
* feat: Added all-songs feature by @unknown0816 in https://github.com/eddyizm/tempus/pull/517
|
||||
|
||||
## New Contributors
|
||||
* @NikkoFox made their first contribution in https://github.com/eddyizm/tempus/pull/503
|
||||
* @olivertzeng made their first contribution in https://github.com/eddyizm/tempus/pull/494
|
||||
* @Jorilx made their first contribution in https://github.com/eddyizm/tempus/pull/505
|
||||
* @unknown0816 made their first contribution in https://github.com/eddyizm/tempus/pull/517
|
||||
|
||||
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.12.6...v4.13.0
|
||||
|
||||
## What's Changed
|
||||
## [4.12.6](https://github.com/eddyizm/tempo/releases/tag/v4.12.6) (2026-03-06)
|
||||
* doc: update USAGE with android auto configuration by @MaFo-28 in https://github.com/eddyizm/tempus/pull/481
|
||||
|
||||
20
README.md
@@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<img alt="Tempus" title="Tempus" src="mockup/svg/tempus_horizontal_logo.png" width="250">
|
||||
<img alt="Tempus" title="Tempus" src="mockup/svg/tempus-horizontal-banner.png" width="250">
|
||||
</p>
|
||||
|
||||
---
|
||||
@@ -84,13 +84,13 @@ Please note the two variants in the release assets include release/debug and 32/
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/1_light.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2_light.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/3_light.png" width=200>
|
||||
<img src="mockup/1_light_tempus.png" width=200>
|
||||
<img src="mockup/2_light_tempus.png" width=200>
|
||||
<img src="mockup/3_light_tempus.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/4_light.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/5_light.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/6_light.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/8_light.png" width=200>
|
||||
<!-- <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/8_light.png" width=200> -->
|
||||
</p>
|
||||
|
||||
<br>
|
||||
@@ -100,13 +100,13 @@ Please note the two variants in the release assets include release/debug and 32/
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/1_dark.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2_dark.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/3_dark.png" width=200>
|
||||
<img src="mockup/1_dark_tempus.png" width=200>
|
||||
<img src="mockup/2_dark_tempus.png" width=200>
|
||||
<img src="mockup/3_dark_tempus.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/4_dark.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/5_dark.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/6_dark.png" width=200>
|
||||
<img src="fastlane/metadata/android/en-US/images/phoneScreenshots/8_dark.png" width=200>
|
||||
<!-- <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/8_dark.png" width=200> -->
|
||||
|
||||
</p>
|
||||
|
||||
@@ -136,4 +136,4 @@ Tempus is released under the [GNU General Public License v3.0](LICENSE). Feel fr
|
||||
## Credits
|
||||
Thanks to the original repo/creator [CappielloAntonio](https://github.com/CappielloAntonio) (forked from v3.9.0)
|
||||
|
||||
[Opensvg.org](https://opensvg.org) for the new turntable logo.
|
||||
[SeattleGuy](https://github.com/SeattleGuy) for the new logo design.
|
||||
|
||||
1
USAGE.md
@@ -203,6 +203,7 @@ The Android Auto interface can be configured by user to best suit their preferen
|
||||
- Star albums
|
||||
- Star artists
|
||||
- Random : 100 random songs
|
||||
- Genres : 500 songs of the chosen genre OR 100 random songs if "shuffle genre songs" is selected
|
||||
|
||||
If all tabs are set to "Do not display", then "Home" tab will be created with all functions inside.
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ android {
|
||||
minSdkVersion 24
|
||||
targetSdk 35
|
||||
|
||||
versionCode 23
|
||||
versionName '4.12.6'
|
||||
versionCode 24
|
||||
versionName '4.13.0'
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
javaCompileOptions {
|
||||
|
||||
|
Before Width: | Height: | Size: 20 KiB |
10
app/src/degoogled/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#FF36C12C"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
</vector>
|
||||
@@ -1,54 +1,78 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<group android:scaleX="0.49"
|
||||
android:scaleY="0.49"
|
||||
android:translateX="130.56"
|
||||
android:translateY="130.56">
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<path
|
||||
android:pathData="M512,437.33c0,11.78 -9.56,21.34 -21.34,21.34H21.33C9.55,458.67 0,449.11 0,437.33V96c0,-11.78 9.55,-21.33 21.33,-21.33h469.33c11.78,0 21.34,9.55 21.34,21.33L512,437.33L512,437.33z"
|
||||
android:fillColor="#8CC152"/> <path
|
||||
android:pathData="M512,416.01c0,11.78 -9.56,21.31 -21.34,21.31H21.33C9.55,437.33 0,427.8 0,416.01V74.67c0,-11.78 9.55,-21.34 21.33,-21.34h469.33c11.78,0 21.34,9.56 21.34,21.34L512,416.01L512,416.01z"
|
||||
android:fillColor="#62A43B"/> <path
|
||||
android:pathData="M63.99,160c-5.89,0 -10.66,4.78 -10.66,10.67v149.34c0,5.88 4.77,10.66 10.66,10.66c5.89,0 10.67,-4.78 10.67,-10.66V170.67C74.66,164.78 69.88,160 63.99,160z"
|
||||
android:fillColor="#8CC152"/> <path
|
||||
android:pathData="M74.66,106.67c0,5.89 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.77 -10.66,-10.66S58.1,96 63.99,96C69.88,96 74.66,100.78 74.66,106.67z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M74.66,384.01c0,5.88 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.78 -10.66,-10.66c0,-5.91 4.77,-10.69 10.66,-10.69C69.88,373.33 74.66,378.11 74.66,384.01z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M448,123.73h-21.34v203.19l-40.31,50.41v0.02c-1.47,1.83 -2.34,4.14 -2.34,6.67c0,5.88 4.78,10.66 10.66,10.66c3.38,0 6.38,-1.56 8.33,-4h0.02l42.66,-53.34l0,0c1.47,-1.81 2.34,-4.13 2.34,-6.66V123.73z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,149.33c-11.77,0 -21.33,-9.56 -21.33,-21.33s9.56,-21.33 21.33,-21.33s21.33,9.56 21.33,21.33S449.09,149.33 437.33,149.33z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,96c-17.67,0 -32,14.33 -32,32s14.33,32 32,32s32,-14.33 32,-32S455,96 437.33,96zM437.33,138.67c-5.89,0 -10.67,-4.8 -10.67,-10.67c0,-5.88 4.78,-10.67 10.67,-10.67s10.67,4.8 10.67,10.67C448,133.88 443.22,138.67 437.33,138.67z"
|
||||
android:fillColor="#CCD1D9"/>
|
||||
<path
|
||||
android:pathData="M405.33,245.33c0,82.48 -66.86,149.34 -149.33,149.34c-82.47,0 -149.33,-66.86 -149.33,-149.34C106.66,162.86 173.52,96 255.99,96C338.47,96 405.33,162.86 405.33,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M266.66,149.33c0,-5.89 -4.77,-10.66 -10.67,-10.66c-58.91,0 -106.66,47.75 -106.66,106.65l0,0c0,5.89 4.77,10.67 10.67,10.67s10.67,-4.78 10.67,-10.67l0,0c0,-22.78 8.88,-44.22 24.99,-60.33c16.12,-16.13 37.55,-25 60.34,-25C261.89,160 266.66,155.22 266.66,149.33z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M352,234.67c-5.9,0 -10.67,4.77 -10.67,10.66l0,0c0,22.8 -8.88,44.23 -24.98,60.34c-16.13,16.13 -37.56,25 -60.35,25c-5.89,0 -10.66,4.78 -10.66,10.66c0,5.91 4.77,10.69 10.66,10.69c58.91,0 106.66,-47.77 106.66,-106.69C362.65,239.44 357.89,234.67 352,234.67z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M255.99,288.01c-23.52,0 -42.66,-19.16 -42.66,-42.69c0,-23.52 19.14,-42.66 42.66,-42.66c23.54,0 42.66,19.14 42.66,42.66C298.65,268.86 279.53,288.01 255.99,288.01z"
|
||||
android:fillColor="#FFCE54"/>
|
||||
<path
|
||||
android:pathData="M255.99,192c-29.45,0 -53.33,23.88 -53.33,53.33s23.88,53.34 53.33,53.34c29.46,0 53.34,-23.89 53.34,-53.34S285.45,192 255.99,192zM255.99,277.34c-17.64,0 -32,-14.36 -32,-32.02c0,-17.64 14.36,-32 32,-32c17.65,0 32.01,14.36 32.01,32C288,262.98 273.64,277.34 255.99,277.34z"
|
||||
android:fillColor="#F6BB42"/>
|
||||
<path
|
||||
android:pathData="M266.66,245.33c0,5.89 -4.77,10.67 -10.67,10.67c-5.89,0 -10.66,-4.78 -10.66,-10.67s4.77,-10.66 10.66,-10.66C261.89,234.67 266.66,239.44 266.66,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M74.66,234.67H53.33c-5.89,0 -10.66,4.77 -10.66,10.66s4.77,10.67 10.66,10.67h21.34c5.89,0 10.66,-4.78 10.66,-10.67S80.56,234.67 74.66,234.67z"
|
||||
android:fillColor="#434A54"/>
|
||||
</group>
|
||||
<group
|
||||
android:scaleX="0.13"
|
||||
android:scaleY="0.13"
|
||||
android:translateX="21.5"
|
||||
android:translateY="21.5">
|
||||
|
||||
<path
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FF36C12C" />
|
||||
<item android:offset="1.0" android:color="#FF36C12C" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,53 +1,77 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<group android:scaleX="0.55"
|
||||
android:scaleY="0.55"
|
||||
android:translateX="150.56"
|
||||
android:translateY="150.56">
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<group
|
||||
android:scaleX="0.13"
|
||||
android:scaleY="0.13"
|
||||
android:translateX="21.5"
|
||||
android:translateY="21.5">
|
||||
<path
|
||||
android:pathData="M512,437.33c0,11.78 -9.56,21.34 -21.34,21.34H21.33C9.55,458.67 0,449.11 0,437.33V96c0,-11.78 9.55,-21.33 21.33,-21.33h469.33c11.78,0 21.34,9.55 21.34,21.33L512,437.33L512,437.33z"
|
||||
android:fillColor="#8CC152"/> <path
|
||||
android:pathData="M512,416.01c0,11.78 -9.56,21.31 -21.34,21.31H21.33C9.55,437.33 0,427.8 0,416.01V74.67c0,-11.78 9.55,-21.34 21.33,-21.34h469.33c11.78,0 21.34,9.56 21.34,21.34L512,416.01L512,416.01z"
|
||||
android:fillColor="#62A43B"/> <path
|
||||
android:pathData="M63.99,160c-5.89,0 -10.66,4.78 -10.66,10.67v149.34c0,5.88 4.77,10.66 10.66,10.66c5.89,0 10.67,-4.78 10.67,-10.66V170.67C74.66,164.78 69.88,160 63.99,160z"
|
||||
android:fillColor="#8CC152"/> <path
|
||||
android:pathData="M74.66,106.67c0,5.89 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.77 -10.66,-10.66S58.1,96 63.99,96C69.88,96 74.66,100.78 74.66,106.67z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FF36C12C" />
|
||||
<item android:offset="1.0" android:color="#FF36C12C" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M74.66,384.01c0,5.88 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.78 -10.66,-10.66c0,-5.91 4.77,-10.69 10.66,-10.69C69.88,373.33 74.66,378.11 74.66,384.01z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M448,123.73h-21.34v203.19l-40.31,50.41v0.02c-1.47,1.83 -2.34,4.14 -2.34,6.67c0,5.88 4.78,10.66 10.66,10.66c3.38,0 6.38,-1.56 8.33,-4h0.02l42.66,-53.34l0,0c1.47,-1.81 2.34,-4.13 2.34,-6.66V123.73z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M437.33,149.33c-11.77,0 -21.33,-9.56 -21.33,-21.33s9.56,-21.33 21.33,-21.33s21.33,9.56 21.33,21.33S449.09,149.33 437.33,149.33z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M437.33,96c-17.67,0 -32,14.33 -32,32s14.33,32 32,32s32,-14.33 32,-32S455,96 437.33,96zM437.33,138.67c-5.89,0 -10.67,-4.8 -10.67,-10.67c0,-5.88 4.78,-10.67 10.67,-10.67s10.67,4.8 10.67,10.67C448,133.88 443.22,138.67 437.33,138.67z"
|
||||
android:fillColor="#CCD1D9"/>
|
||||
<path
|
||||
android:pathData="M405.33,245.33c0,82.48 -66.86,149.34 -149.33,149.34c-82.47,0 -149.33,-66.86 -149.33,-149.34C106.66,162.86 173.52,96 255.99,96C338.47,96 405.33,162.86 405.33,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M266.66,149.33c0,-5.89 -4.77,-10.66 -10.67,-10.66c-58.91,0 -106.66,47.75 -106.66,106.65l0,0c0,5.89 4.77,10.67 10.67,10.67s10.67,-4.78 10.67,-10.67l0,0c0,-22.78 8.88,-44.22 24.99,-60.33c16.12,-16.13 37.55,-25 60.34,-25C261.89,160 266.66,155.22 266.66,149.33z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M352,234.67c-5.9,0 -10.67,4.77 -10.67,10.66l0,0c0,22.8 -8.88,44.23 -24.98,60.34c-16.13,16.13 -37.56,25 -60.35,25c-5.89,0 -10.66,4.78 -10.66,10.66c0,5.91 4.77,10.69 10.66,10.69c58.91,0 106.66,-47.77 106.66,-106.69C362.65,239.44 357.89,234.67 352,234.67z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M255.99,288.01c-23.52,0 -42.66,-19.16 -42.66,-42.69c0,-23.52 19.14,-42.66 42.66,-42.66c23.54,0 42.66,19.14 42.66,42.66C298.65,268.86 279.53,288.01 255.99,288.01z"
|
||||
android:fillColor="#FFCE54"/>
|
||||
<path
|
||||
android:pathData="M255.99,192c-29.45,0 -53.33,23.88 -53.33,53.33s23.88,53.34 53.33,53.34c29.46,0 53.34,-23.89 53.34,-53.34S285.45,192 255.99,192zM255.99,277.34c-17.64,0 -32,-14.36 -32,-32.02c0,-17.64 14.36,-32 32,-32c17.65,0 32.01,14.36 32.01,32C288,262.98 273.64,277.34 255.99,277.34z"
|
||||
android:fillColor="#F6BB42"/>
|
||||
<path
|
||||
android:pathData="M266.66,245.33c0,5.89 -4.77,10.67 -10.67,10.67c-5.89,0 -10.66,-4.78 -10.66,-10.67s4.77,-10.66 10.66,-10.66C261.89,234.67 266.66,239.44 266.66,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M74.66,234.67H53.33c-5.89,0 -10.66,4.77 -10.66,10.66s4.77,10.67 10.66,10.67h21.34c5.89,0 10.66,-4.78 10.66,-10.67S80.56,234.67 74.66,234.67z"
|
||||
android:fillColor="#434A54"/>
|
||||
</group>
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
77
app/src/degoogled/res/drawable/ic_toolbar_tempo.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="522">
|
||||
<group
|
||||
android:scaleX="1.0"
|
||||
android:scaleY="1.0"
|
||||
android:translateX="14.0"
|
||||
android:translateY="14.0">
|
||||
|
||||
<path
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FF36C12C" />
|
||||
<item android:offset="1.0" android:color="#FF36C12C" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
78
app/src/degoogled/res/drawable/logo.xml
Normal file
@@ -0,0 +1,78 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<group
|
||||
android:scaleX="0.16"
|
||||
android:scaleY="0.16"
|
||||
android:translateX="14.0"
|
||||
android:translateY="14.0">
|
||||
|
||||
<path
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FF36C12C" />
|
||||
<item android:offset="1.0" android:color="#FF36C12C" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#626A75</color>
|
||||
</resources>
|
||||
|
Before Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,44 @@
|
||||
package com.cappielloantonio.tempo.navigation;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.navigation.NavController;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
|
||||
public class NavigationController {
|
||||
|
||||
NavigationHelper helper;
|
||||
|
||||
public NavigationController(@NonNull NavigationHelper helper) {
|
||||
this.helper = helper;
|
||||
}
|
||||
|
||||
public void syncWithBottomSheetBehavior(BottomSheetBehavior<View> bottomSheetBehavior,
|
||||
NavController navController) {
|
||||
helper.syncWithBottomSheetBehavior(bottomSheetBehavior, navController);
|
||||
|
||||
}
|
||||
|
||||
public void setNavbarVisibility(boolean visibility) {
|
||||
helper.setBottomNavigationBarVisibility(visibility);
|
||||
}
|
||||
|
||||
public void setDrawerLock(boolean visibility) {
|
||||
helper.setNavigationDrawerLock(visibility);
|
||||
}
|
||||
|
||||
public boolean isNavigationDrawerLocked() {
|
||||
return helper.isNavigationDrawerLocked();
|
||||
}
|
||||
|
||||
public void toggleDrawerLockOnOrientation(AppCompatActivity activity) {
|
||||
helper.toggleNavigationDrawerLockOnOrientationChange(activity);
|
||||
}
|
||||
|
||||
public void setSystemBarsVisibility(AppCompatActivity activity, boolean visibility) {
|
||||
helper.setSystemBarsVisibility(activity, visibility);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.cappielloantonio.tempo.navigation;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDestination;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
public class NavigationHelper {
|
||||
/* UI components */
|
||||
private BottomNavigationView bottomNavigationView;
|
||||
private FrameLayout bottomNavigationViewFrame;
|
||||
private DrawerLayout drawerLayout;
|
||||
|
||||
/* Navigation components */
|
||||
private NavigationView navigationView;
|
||||
private NavHostFragment navHostFragment;
|
||||
|
||||
/* States that need to be remembered */
|
||||
// -- //
|
||||
|
||||
/* Private constructor */
|
||||
public NavigationHelper(@NonNull BottomNavigationView bottomNavigationView,
|
||||
@NonNull FrameLayout bottomNavigationViewFrame,
|
||||
@NonNull DrawerLayout drawerLayout,
|
||||
@NonNull NavigationView navigationView,
|
||||
@NonNull NavHostFragment navHostFragment) {
|
||||
this.bottomNavigationView = bottomNavigationView;
|
||||
this.bottomNavigationViewFrame = bottomNavigationViewFrame;
|
||||
this.drawerLayout = drawerLayout;
|
||||
this.navigationView = navigationView;
|
||||
this.navHostFragment = navHostFragment;
|
||||
}
|
||||
|
||||
public void syncWithBottomSheetBehavior(@NonNull BottomSheetBehavior<View> bottomSheetBehavior,
|
||||
@NonNull NavController navController) {
|
||||
navController.addOnDestinationChangedListener(
|
||||
(controller, destination, arguments) -> {
|
||||
// React to the user clicking one of these on bottom-navbar/drawer
|
||||
boolean isTarget = isTargetDestination(destination);
|
||||
int currentState = bottomSheetBehavior.getState();
|
||||
|
||||
if (isTarget && currentState == BottomSheetBehavior.STATE_EXPANDED) {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
}
|
||||
});
|
||||
|
||||
NavigationUI.setupWithNavController(bottomNavigationView, navController);
|
||||
NavigationUI.setupWithNavController(navigationView, navController);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
private static boolean isTargetDestination(NavDestination destination) {
|
||||
int destId = destination.getId();
|
||||
return destId == R.id.homeFragment ||
|
||||
destId == R.id.libraryFragment ||
|
||||
destId == R.id.downloadFragment ||
|
||||
destId == R.id.albumCatalogueFragment ||
|
||||
destId == R.id.artistCatalogueFragment ||
|
||||
destId == R.id.genreCatalogueFragment ||
|
||||
destId == R.id.playlistCatalogueFragment;
|
||||
}
|
||||
|
||||
/*
|
||||
Clean public methods
|
||||
Removes the need to invoke the activity on the fragment
|
||||
*/
|
||||
|
||||
public void setBottomNavigationBarVisibility(boolean visible) {
|
||||
int visibility = visible
|
||||
? View.VISIBLE
|
||||
: View.GONE;
|
||||
bottomNavigationView.setVisibility(visibility);
|
||||
bottomNavigationViewFrame.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public void setNavigationDrawerLock(boolean locked) {
|
||||
int mode = locked
|
||||
? DrawerLayout.LOCK_MODE_LOCKED_CLOSED
|
||||
: DrawerLayout.LOCK_MODE_UNLOCKED;
|
||||
drawerLayout.setDrawerLockMode(mode);
|
||||
}
|
||||
|
||||
public boolean isNavigationDrawerLocked() {
|
||||
return drawerLayout.getDrawerLockMode(navigationView) != DrawerLayout.LOCK_MODE_UNLOCKED;
|
||||
}
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public void toggleNavigationDrawerLockOnOrientationChange(
|
||||
AppCompatActivity activity) {
|
||||
|
||||
int orientation = activity.getResources().getConfiguration().orientation;
|
||||
boolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||
|
||||
if (Preferences.getEnableDrawerOnPortrait()) {
|
||||
setNavigationDrawerLock(false);
|
||||
return;
|
||||
}
|
||||
setNavigationDrawerLock(!isLandscape);
|
||||
}
|
||||
|
||||
/*
|
||||
All of these are the "backward compatible" changes that don't break the assumption
|
||||
that everything was defined on the activity and is gobally available
|
||||
*/
|
||||
|
||||
@NonNull
|
||||
public BottomNavigationView getBottomNavigationView() {
|
||||
return bottomNavigationView;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public FrameLayout getBottomNavigationViewFrame() {
|
||||
return bottomNavigationViewFrame;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public DrawerLayout getDrawerLayout() {
|
||||
return drawerLayout;
|
||||
}
|
||||
|
||||
/*
|
||||
Auxiliar functions, could be moved somewhere else
|
||||
*/
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public void setSystemBarsVisibility(AppCompatActivity activity, boolean visibility) {
|
||||
WindowInsetsControllerCompat insetsController;
|
||||
Window window = activity.getWindow();
|
||||
View decorView = window.getDecorView();
|
||||
insetsController = new WindowInsetsControllerCompat(window, decorView);
|
||||
|
||||
if (visibility) {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, true);
|
||||
insetsController.show(WindowInsetsCompat.Type.navigationBars());
|
||||
insetsController.show(WindowInsetsCompat.Type.statusBars());
|
||||
insetsController.setSystemBarsBehavior(
|
||||
WindowInsetsControllerCompat.BEHAVIOR_DEFAULT);
|
||||
} else {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false);
|
||||
insetsController.hide(WindowInsetsCompat.Type.navigationBars());
|
||||
insetsController.hide(WindowInsetsCompat.Type.statusBars());
|
||||
insetsController.setSystemBarsBehavior(
|
||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation;
|
||||
import com.cappielloantonio.tempo.subsonic.models.MusicFolder;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Genre;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
@@ -789,7 +790,7 @@ public class AutomotiveRepository {
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getSearchingClient()
|
||||
.search3(query, 20, 20, 20)
|
||||
.search3(query, 20, 0, 20, 0, 20, 0)
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
@@ -952,6 +953,116 @@ public class AutomotiveRepository {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getGenres(String prefix) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getBrowsingClient()
|
||||
.getGenres()
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getGenres() != null && response.body().getSubsonicResponse().getGenres().getGenres() != null) {
|
||||
List<Genre> genres = response.body().getSubsonicResponse().getGenres().getGenres();
|
||||
|
||||
// Sort genres alphabetically by name
|
||||
genres.sort((g1, g2) -> {
|
||||
String name1 = g1.getGenre() != null ? g1.getGenre() : "";
|
||||
String name2 = g2.getGenre() != null ? g2.getGenre() : "";
|
||||
return name1.compareToIgnoreCase(name2);
|
||||
});
|
||||
|
||||
List<MediaItem> mediaItems = new ArrayList<>();
|
||||
|
||||
for (Genre genre : genres) {
|
||||
MediaMetadata mediaMetadata = new MediaMetadata.Builder()
|
||||
.setTitle(genre.getGenre())
|
||||
.setIsBrowsable(true)
|
||||
.setIsPlayable(false)
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_PLAYLIST)
|
||||
.build();
|
||||
|
||||
MediaItem mediaItem = new MediaItem.Builder()
|
||||
.setMediaId(prefix + genre.getGenre())
|
||||
.setMediaMetadata(mediaMetadata)
|
||||
.setUri("")
|
||||
.build();
|
||||
|
||||
mediaItems.add(mediaItem);
|
||||
}
|
||||
|
||||
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
|
||||
|
||||
listenableFuture.set(libraryResult);
|
||||
} else {
|
||||
listenableFuture.set(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
listenableFuture.setException(t);
|
||||
}
|
||||
});
|
||||
|
||||
return listenableFuture;
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getSongsByGenre(String genre, int count, boolean shuffle) {
|
||||
final SettableFuture<LibraryResult<ImmutableList<MediaItem>>> listenableFuture = SettableFuture.create();
|
||||
|
||||
Call<ApiResponse> call;
|
||||
if (shuffle) {
|
||||
call = App.getSubsonicClientInstance(false)
|
||||
.getAlbumSongListClient()
|
||||
.getRandomSongs(count, null, null, genre);
|
||||
} else {
|
||||
call = App.getSubsonicClientInstance(false)
|
||||
.getAlbumSongListClient()
|
||||
.getSongsByGenre(genre, count, 0);
|
||||
}
|
||||
|
||||
call.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
List<com.cappielloantonio.tempo.subsonic.models.Child> songs;
|
||||
if (shuffle) {
|
||||
songs = response.body().getSubsonicResponse().getRandomSongs() != null
|
||||
? response.body().getSubsonicResponse().getRandomSongs().getSongs()
|
||||
: null;
|
||||
} else {
|
||||
songs = response.body().getSubsonicResponse().getSongsByGenre() != null
|
||||
? response.body().getSubsonicResponse().getSongsByGenre().getSongs()
|
||||
: null;
|
||||
}
|
||||
|
||||
if (songs != null) {
|
||||
setChildrenMetadata(songs);
|
||||
List<MediaItem> mediaItems = MappingUtil.mapMediaItems(songs);
|
||||
LibraryResult<ImmutableList<MediaItem>> libraryResult = LibraryResult.ofItemList(ImmutableList.copyOf(mediaItems), null);
|
||||
listenableFuture.set(libraryResult);
|
||||
} else {
|
||||
listenableFuture.set(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE));
|
||||
}
|
||||
} else {
|
||||
listenableFuture.set(LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
|
||||
listenableFuture.setException(t);
|
||||
}
|
||||
});
|
||||
|
||||
return listenableFuture;
|
||||
}
|
||||
|
||||
public ListenableFuture<LibraryResult<ImmutableList<MediaItem>>> getSongsByGenre(String genre, int count) {
|
||||
return getSongsByGenre(genre, count, false);
|
||||
}
|
||||
|
||||
private static class GetMediaItemThreadSafe implements Runnable {
|
||||
private final SessionMediaItemDao sessionMediaItemDao;
|
||||
private final String id;
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
package com.cappielloantonio.tempo.repository;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.database.AppDatabase;
|
||||
import com.cappielloantonio.tempo.database.dao.RecentSearchDao;
|
||||
import com.cappielloantonio.tempo.model.RecentSearch;
|
||||
@@ -11,13 +16,18 @@ import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
|
||||
import com.cappielloantonio.tempo.subsonic.models.AlbumID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PlaylistWithSongs;
|
||||
import com.cappielloantonio.tempo.subsonic.models.SearchResult2;
|
||||
import com.cappielloantonio.tempo.subsonic.models.SearchResult3;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.ui.fragment.SearchFragment;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
@@ -31,7 +41,7 @@ public class SearchingRepository {
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getSearchingClient()
|
||||
.search3(query, 20, 20, 20)
|
||||
.search3(query, 20, 0, 20, 0, 20, 0)
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
@@ -49,12 +59,63 @@ public class SearchingRepository {
|
||||
return result;
|
||||
}
|
||||
|
||||
public MutableLiveData<SearchResult3> search3(String query) {
|
||||
@UnstableApi
|
||||
public MutableLiveData<SearchResult3> search3(SearchFragment sf, String query) {
|
||||
MutableLiveData<SearchResult3> result = new MutableLiveData<>();
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
List<Child> allSongs = new ArrayList<>();
|
||||
int offset = 0;
|
||||
int limit = 1000;
|
||||
boolean hasMore = true;
|
||||
|
||||
while (hasMore) {
|
||||
try {
|
||||
Response<ApiResponse> response = App.getSubsonicClientInstance(false)
|
||||
.getSearchingClient()
|
||||
.search3(query, limit, offset, 0, 0, 0, 0)
|
||||
.execute();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
SearchResult3 tmp = response.body().getSubsonicResponse().getSearchResult3();
|
||||
if (tmp != null && tmp.getSongs() != null && !tmp.getSongs().isEmpty()) {
|
||||
List<Child> fetchedSongs = tmp.getSongs();
|
||||
allSongs.addAll(fetchedSongs);
|
||||
|
||||
offset += fetchedSongs.size();
|
||||
hasMore = fetchedSongs.size() == limit;
|
||||
} else {
|
||||
hasMore = false;
|
||||
}
|
||||
} else {
|
||||
hasMore = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
PlaylistWithSongs pws = new PlaylistWithSongs("allsongs", allSongs);
|
||||
pws.setName(sf.getView().getContext().getString(R.string.search_all_songs, String.valueOf(allSongs.size())));
|
||||
pws.setSongCount(allSongs.size());
|
||||
List<Playlist> lpws = new ArrayList<>();
|
||||
lpws.add(pws);
|
||||
long duration = 0;
|
||||
for (Child song: allSongs) {
|
||||
if (song != null && song.getDuration() != null) {
|
||||
duration += song.getDuration();
|
||||
}
|
||||
}
|
||||
pws.setDuration(duration);
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
sf.updateUI(lpws);
|
||||
});
|
||||
});
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getSearchingClient()
|
||||
.search3(query, 20, 20, 20)
|
||||
.search3(query, 20, 0, 20, 0, 20, 0)
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
@@ -77,7 +138,7 @@ public class SearchingRepository {
|
||||
|
||||
App.getSubsonicClientInstance(false)
|
||||
.getSearchingClient()
|
||||
.search3(query, 5, 5, 5)
|
||||
.search3(query, 5, 0, 5, 0, 5, 0)
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
|
||||
@@ -24,8 +24,8 @@ public class SearchingClient {
|
||||
return searchingService.search2(subsonic.getParams(), query, songCount, albumCount, artistCount);
|
||||
}
|
||||
|
||||
public Call<ApiResponse> search3(String query, int songCount, int albumCount, int artistCount) {
|
||||
public Call<ApiResponse> search3(String query, int songCount, int songOffset, int albumCount, int albumOffset, int artistCount, int artistOffset) {
|
||||
Log.d(TAG, "search3()");
|
||||
return searchingService.search3(subsonic.getParams(), query, songCount, albumCount, artistCount);
|
||||
return searchingService.search3(subsonic.getParams(), query, songCount, songOffset, albumCount, albumOffset, artistCount, artistOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,5 +14,5 @@ public interface SearchingService {
|
||||
Call<ApiResponse> search2(@QueryMap Map<String, String> params, @Query("query") String query, @Query("songCount") int songCount, @Query("albumCount") int albumCount, @Query("artistCount") int artistCount);
|
||||
|
||||
@GET("search3")
|
||||
Call<ApiResponse> search3(@QueryMap Map<String, String> params, @Query("query") String query, @Query("songCount") int songCount, @Query("albumCount") int albumCount, @Query("artistCount") int artistCount);
|
||||
Call<ApiResponse> search3(@QueryMap Map<String, String> params, @Query("query") String query, @Query("songCount") int songCount, @Query("songOffset") int songOffset, @Query("albumCount") int albumCount, @Query("albumOffset") int albumOffset, @Query("artistCount") int artistCount, @Query("artistOffset") int artistOffset);
|
||||
}
|
||||
|
||||
@@ -4,23 +4,16 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.splashscreen.SplashScreen;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
@@ -31,7 +24,6 @@ import androidx.media3.common.Player;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import com.cappielloantonio.tempo.App;
|
||||
import com.cappielloantonio.tempo.BuildConfig;
|
||||
@@ -39,8 +31,12 @@ import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.broadcast.receiver.ConnectivityStatusBroadcastReceiver;
|
||||
import com.cappielloantonio.tempo.databinding.ActivityMainBinding;
|
||||
import com.cappielloantonio.tempo.github.utils.UpdateUtil;
|
||||
import com.cappielloantonio.tempo.navigation.NavigationController;
|
||||
import com.cappielloantonio.tempo.navigation.NavigationHelper;
|
||||
import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.ui.activity.base.BaseActivity;
|
||||
import com.cappielloantonio.tempo.ui.controller.BottomSheetController;
|
||||
import com.cappielloantonio.tempo.ui.controller.BottomSheetHelper;
|
||||
import com.cappielloantonio.tempo.ui.dialog.ConnectionAlertDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.GithubTempoUpdateDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.ServerUnreachableDialog;
|
||||
@@ -70,10 +66,12 @@ public class MainActivity extends BaseActivity {
|
||||
private NavHostFragment navHostFragment;
|
||||
private BottomNavigationView bottomNavigationView;
|
||||
private FrameLayout bottomNavigationViewFrame;
|
||||
public NavController navController;
|
||||
private DrawerLayout drawerLayout;
|
||||
private NavigationView navigationView;
|
||||
private BottomSheetBehavior bottomSheetBehavior;
|
||||
public NavController navController;
|
||||
private NavigationController navigationController;
|
||||
private BottomSheetController bottomSheetController;
|
||||
public BottomSheetBehavior bottomSheetBehavior;
|
||||
public boolean isLandscape = false;
|
||||
private AssetLinkNavigator assetLinkNavigator;
|
||||
private AssetLinkUtil.AssetLink pendingAssetLink;
|
||||
@@ -81,6 +79,10 @@ public class MainActivity extends BaseActivity {
|
||||
ConnectivityStatusBroadcastReceiver connectivityStatusBroadcastReceiver;
|
||||
private Intent pendingDownloadPlaybackIntent;
|
||||
|
||||
public ActivityMainBinding getBinding() {
|
||||
return bind;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
SplashScreen.installSplashScreen(this);
|
||||
@@ -147,7 +149,6 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
fragmentManager = getSupportFragmentManager();
|
||||
|
||||
initBottomSheet();
|
||||
initNavigation();
|
||||
@@ -162,49 +163,74 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
}
|
||||
|
||||
// BOTTOM SHEET/NAVIGATION
|
||||
private void initBottomSheet() {
|
||||
bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.player_bottom_sheet));
|
||||
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallback);
|
||||
fragmentManager.beginTransaction().replace(R.id.player_bottom_sheet, new PlayerBottomSheetFragment(), "PlayerBottomSheet").commit();
|
||||
private void initNavigation() {
|
||||
// We link the nav_graph.xml with our navigationController
|
||||
NavHostFragment navHostFragment = (NavHostFragment) this
|
||||
.getSupportFragmentManager()
|
||||
.findFragmentById(R.id.nav_host_fragment);
|
||||
navController = Objects.requireNonNull(navHostFragment).getNavController();
|
||||
/*
|
||||
navController is currently global since some legacy code still invokes it directly
|
||||
the MainActivity methods that use it must be converted to NavigationHelper methods
|
||||
*/
|
||||
|
||||
checkBottomSheetAfterStateChanged();
|
||||
// Helper
|
||||
NavigationHelper navigationHelper =
|
||||
new NavigationHelper(
|
||||
findViewById(R.id.bottom_navigation),
|
||||
findViewById(R.id.bottom_navigation_frame),
|
||||
findViewById(R.id.drawer_layout),
|
||||
findViewById(R.id.nav_view),
|
||||
navHostFragment
|
||||
);
|
||||
|
||||
// Controller
|
||||
navigationController = new NavigationController(navigationHelper);
|
||||
navigationController.syncWithBottomSheetBehavior(bottomSheetBehavior, navController);
|
||||
}
|
||||
|
||||
private void initBottomSheet() {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
View bottomSheetView = findViewById(R.id.player_bottom_sheet);
|
||||
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetView);
|
||||
/*
|
||||
bottomSheetBehavior is currently global since some legacy code still invokes it directly
|
||||
the MainActivity methods that use it must be converted to BottomSheetHelper methods
|
||||
*/
|
||||
|
||||
// Helper
|
||||
BottomSheetHelper bottomSheetHelper =
|
||||
new BottomSheetHelper(
|
||||
bottomSheetBehavior,
|
||||
bottomSheetView,
|
||||
fragmentManager
|
||||
);
|
||||
|
||||
// Controller
|
||||
bottomSheetController = new BottomSheetController(bottomSheetHelper);
|
||||
bottomSheetController.addCallback(bottomSheetCallback);
|
||||
bottomSheetController.replaceFragment(R.id.player_bottom_sheet);
|
||||
bottomSheetController.checkAfterStateChanged(mainViewModel);
|
||||
}
|
||||
|
||||
public void setBottomSheetInPeek(Boolean isVisible) {
|
||||
if (isVisible) {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
} else {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
}
|
||||
bottomSheetController.setStateInPeek(isVisible);
|
||||
}
|
||||
|
||||
public void setBottomSheetVisibility(boolean visibility) {
|
||||
if (visibility) {
|
||||
findViewById(R.id.player_bottom_sheet).setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
findViewById(R.id.player_bottom_sheet).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkBottomSheetAfterStateChanged() {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> setBottomSheetInPeek(mainViewModel.isQueueLoaded());
|
||||
handler.postDelayed(runnable, 100);
|
||||
bottomSheetController.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public void collapseBottomSheetDelayed() {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
handler.postDelayed(runnable, 100);
|
||||
bottomSheetController.collapseDelayed();
|
||||
}
|
||||
|
||||
public void expandBottomSheet() {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
bottomSheetController.expand();
|
||||
}
|
||||
|
||||
public void setBottomSheetDraggableState(Boolean isDraggable) {
|
||||
bottomSheetBehavior.setDraggable(isDraggable);
|
||||
bottomSheetController.setDraggable(isDraggable);
|
||||
}
|
||||
|
||||
private final BottomSheetBehavior.BottomSheetCallback bottomSheetCallback =
|
||||
@@ -217,7 +243,7 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
switch (state) {
|
||||
case BottomSheetBehavior.STATE_HIDDEN:
|
||||
resetMusicSession();
|
||||
resetMusicSession(); // I can't put the callback inside BottomSheetHelper because of this line
|
||||
break;
|
||||
case BottomSheetBehavior.STATE_COLLAPSED:
|
||||
if (playerBottomSheetFragment != null)
|
||||
@@ -241,12 +267,7 @@ public class MainActivity extends BaseActivity {
|
||||
};
|
||||
|
||||
private void animateBottomSheet(float slideOffset) {
|
||||
PlayerBottomSheetFragment playerBottomSheetFragment = (PlayerBottomSheetFragment) getSupportFragmentManager().findFragmentByTag("PlayerBottomSheet");
|
||||
if (playerBottomSheetFragment != null) {
|
||||
float condensedSlideOffset = Math.max(0.0f, Math.min(0.2f, slideOffset - 0.2f)) / 0.2f;
|
||||
playerBottomSheetFragment.getPlayerHeader().setAlpha(1 - condensedSlideOffset);
|
||||
playerBottomSheetFragment.getPlayerHeader().setVisibility(condensedSlideOffset > 0.99 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
bottomSheetController.animate(slideOffset);
|
||||
}
|
||||
|
||||
private void animateBottomNavigation(float slideOffset, int navigationHeight) {
|
||||
@@ -261,117 +282,56 @@ public class MainActivity extends BaseActivity {
|
||||
bind.bottomNavigation.setTranslationY(slideY);
|
||||
}
|
||||
|
||||
private void initNavigation() {
|
||||
bottomNavigationView = findViewById(R.id.bottom_navigation);
|
||||
bottomNavigationViewFrame = findViewById(R.id.bottom_navigation_frame);
|
||||
navHostFragment = (NavHostFragment) fragmentManager.findFragmentById(R.id.nav_host_fragment);
|
||||
navController = Objects.requireNonNull(navHostFragment).getNavController();
|
||||
// This is the lateral slide-in drawer
|
||||
drawerLayout = findViewById(R.id.drawer_layout);
|
||||
navigationView = findViewById(R.id.nav_view);
|
||||
|
||||
/*
|
||||
* In questo modo intercetto il cambio schermata tramite navbar e se il bottom sheet è aperto,
|
||||
* lo chiudo
|
||||
*/
|
||||
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
|
||||
if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED && (
|
||||
destination.getId() == R.id.homeFragment ||
|
||||
destination.getId() == R.id.libraryFragment ||
|
||||
destination.getId() == R.id.downloadFragment ||
|
||||
destination.getId() == R.id.albumCatalogueFragment ||
|
||||
destination.getId() == R.id.artistCatalogueFragment ||
|
||||
destination.getId() == R.id.genreCatalogueFragment ||
|
||||
destination.getId() == R.id.playlistCatalogueFragment)
|
||||
) {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
}
|
||||
});
|
||||
|
||||
NavigationUI.setupWithNavController(bottomNavigationView, navController);
|
||||
NavigationUI.setupWithNavController(navigationView, navController);
|
||||
}
|
||||
|
||||
public void setBottomNavigationBarVisibility(boolean visibility) {
|
||||
if (visibility) {
|
||||
bottomNavigationView.setVisibility(View.VISIBLE);
|
||||
bottomNavigationViewFrame.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
bottomNavigationView.setVisibility(View.GONE);
|
||||
bottomNavigationViewFrame.setVisibility(View.GONE);
|
||||
}
|
||||
navigationController.setNavbarVisibility(visibility);
|
||||
}
|
||||
|
||||
public void toggleBottomNavigationBarVisibilityOnOrientationChange() {
|
||||
float displayDensity = getResources().getDisplayMetrics().density;
|
||||
// Ignore orientation change, bottom navbar always hidden
|
||||
if (Preferences.getHideBottomNavbarOnPortrait()) {
|
||||
setBottomNavigationBarVisibility(false);
|
||||
setPortraitPlayerBottomSheetPeekHeight(56);
|
||||
setSystemBarsVisibility(!isLandscape);
|
||||
navigationController.setNavbarVisibility(false);
|
||||
bottomSheetController.setPeekHeight(56, displayDensity);
|
||||
navigationController.setSystemBarsVisibility(this, !isLandscape);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLandscape) {
|
||||
// Show app navbar + show system bars
|
||||
setPortraitPlayerBottomSheetPeekHeight(136);
|
||||
setBottomNavigationBarVisibility(true);
|
||||
setSystemBarsVisibility(true);
|
||||
bottomSheetController.setPeekHeight(136, displayDensity);
|
||||
navigationController.setNavbarVisibility(true);
|
||||
navigationController.setSystemBarsVisibility(this, true);
|
||||
} else {
|
||||
// Hide app navbar + hide system bars
|
||||
setPortraitPlayerBottomSheetPeekHeight(56);
|
||||
setBottomNavigationBarVisibility(false);
|
||||
setSystemBarsVisibility(false);
|
||||
bottomSheetController.setPeekHeight(56, displayDensity);
|
||||
navigationController.setNavbarVisibility(false);
|
||||
navigationController.setSystemBarsVisibility(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void setNavigationDrawerLock(boolean locked) {
|
||||
int mode = locked
|
||||
? DrawerLayout.LOCK_MODE_LOCKED_CLOSED
|
||||
: DrawerLayout.LOCK_MODE_UNLOCKED;
|
||||
drawerLayout.setDrawerLockMode(mode);
|
||||
navigationController.setDrawerLock(locked);
|
||||
}
|
||||
|
||||
public boolean isNavigationDrawerLocked() {
|
||||
return navigationController.isNavigationDrawerLocked();
|
||||
}
|
||||
|
||||
public void toggleNavigationDrawerLockOnOrientationChange() {
|
||||
// Ignore orientation check, drawer always unlocked
|
||||
if (Preferences.getEnableDrawerOnPortrait()) {
|
||||
setNavigationDrawerLock(false);
|
||||
return;
|
||||
}
|
||||
if (!isLandscape) {
|
||||
setNavigationDrawerLock(true);
|
||||
} else {
|
||||
setNavigationDrawerLock(false);
|
||||
}
|
||||
navigationController.toggleDrawerLockOnOrientation(this);
|
||||
}
|
||||
|
||||
public void setSystemBarsVisibility(boolean visibility) {
|
||||
WindowInsetsControllerCompat insetsController;
|
||||
View decorView = getWindow().getDecorView();
|
||||
insetsController = new WindowInsetsControllerCompat(getWindow(), decorView);
|
||||
|
||||
if (visibility) {
|
||||
WindowCompat.setDecorFitsSystemWindows(getWindow(), true);
|
||||
insetsController.show(WindowInsetsCompat.Type.navigationBars());
|
||||
insetsController.show(WindowInsetsCompat.Type.statusBars());
|
||||
insetsController.setSystemBarsBehavior(
|
||||
WindowInsetsControllerCompat.BEHAVIOR_DEFAULT);
|
||||
} else {
|
||||
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
|
||||
insetsController.hide(WindowInsetsCompat.Type.navigationBars());
|
||||
insetsController.hide(WindowInsetsCompat.Type.statusBars());
|
||||
insetsController.setSystemBarsBehavior(
|
||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||
}
|
||||
navigationController.setSystemBarsVisibility(this, visibility);
|
||||
}
|
||||
|
||||
private void setPortraitPlayerBottomSheetPeekHeight(int peekHeight) {
|
||||
FrameLayout bottomSheet = findViewById(R.id.player_bottom_sheet);
|
||||
BottomSheetBehavior<FrameLayout> behavior =
|
||||
BottomSheetBehavior.from(bottomSheet);
|
||||
|
||||
int newPeekPx = (int) (peekHeight * getResources().getDisplayMetrics().density);
|
||||
behavior.setPeekHeight(newPeekPx);
|
||||
}
|
||||
/*
|
||||
There are only 4 init functions that must exist up to here
|
||||
1. init()
|
||||
2. initNavigation()
|
||||
3. initBottomSheet()
|
||||
4. bottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() { ... }
|
||||
*/
|
||||
|
||||
private void initService() {
|
||||
MediaManager.check(getMediaBrowserListenableFuture());
|
||||
@@ -407,7 +367,7 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
private void goToHome() {
|
||||
bottomNavigationView.setVisibility(View.VISIBLE);
|
||||
setBottomNavigationBarVisibility(true);
|
||||
|
||||
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
|
||||
navController.navigate(R.id.action_landingFragment_to_homeFragment);
|
||||
@@ -657,4 +617,4 @@ public class MainActivity extends BaseActivity {
|
||||
|
||||
MediaManager.playDownloadedMediaItem(getMediaBrowserListenableFuture(), mediaItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.cappielloantonio.tempo.ui.controller;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.cappielloantonio.tempo.viewmodel.MainViewModel;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
|
||||
public class BottomSheetController {
|
||||
|
||||
BottomSheetHelper helper;
|
||||
|
||||
public BottomSheetController(@NonNull BottomSheetHelper bottomSheetPlayerHelper) {
|
||||
this.helper = bottomSheetPlayerHelper;
|
||||
}
|
||||
|
||||
public void expand() {
|
||||
helper.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
helper.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
}
|
||||
|
||||
public void setStateInPeek(boolean isVisible) {
|
||||
helper.setStateInPeek(isVisible);
|
||||
}
|
||||
|
||||
public void setVisibility(boolean visibility) {
|
||||
helper.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public void addCallback(BottomSheetBehavior.BottomSheetCallback callback) {
|
||||
helper.addCallback(callback);
|
||||
}
|
||||
|
||||
public void replaceFragment(int playerBottomSheet) {
|
||||
helper.replaceFragment(playerBottomSheet);
|
||||
}
|
||||
|
||||
public void checkAfterStateChanged(MainViewModel mainViewModel) {
|
||||
helper.checkAfterStateChanged(mainViewModel);
|
||||
}
|
||||
|
||||
public void collapseDelayed() {
|
||||
helper.collapseDelayed();
|
||||
}
|
||||
|
||||
public void setDraggable(Boolean isDraggable) {
|
||||
helper.setDraggable(isDraggable);
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return helper.getState();
|
||||
}
|
||||
|
||||
public void animate(float slideOffset) {
|
||||
helper.animate(slideOffset);
|
||||
}
|
||||
|
||||
public void setPeekHeight(int peekHeight, float displayDensity) {
|
||||
helper.setPeekHeight(peekHeight, displayDensity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.cappielloantonio.tempo.ui.controller;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.ui.fragment.PlayerBottomSheetFragment;
|
||||
import com.cappielloantonio.tempo.viewmodel.MainViewModel;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
|
||||
public class BottomSheetHelper {
|
||||
|
||||
BottomSheetBehavior<View> bottomSheetBehavior;
|
||||
View bottomSheetView;
|
||||
FragmentManager fragmentManager; // Of the entire activity
|
||||
PlayerBottomSheetFragment playerBottomSheetFragment;
|
||||
|
||||
public void setState(int state) {
|
||||
bottomSheetBehavior.setState(state);
|
||||
}
|
||||
|
||||
public BottomSheetHelper(@NonNull BottomSheetBehavior<View> bottomSheetBehavior,
|
||||
@NonNull View bottomSheetView,
|
||||
@NonNull FragmentManager fragmentManager) {
|
||||
this.bottomSheetBehavior = bottomSheetBehavior;
|
||||
this.bottomSheetView = bottomSheetView;
|
||||
this.fragmentManager = fragmentManager;
|
||||
this.playerBottomSheetFragment = new PlayerBottomSheetFragment();
|
||||
}
|
||||
|
||||
public void addCallback(BottomSheetBehavior.BottomSheetCallback callback) {
|
||||
bottomSheetBehavior.addBottomSheetCallback(callback);
|
||||
}
|
||||
|
||||
public void setStateInPeek(boolean isVisible) {
|
||||
if (isVisible) {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
} else {
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisibility(boolean visibility) {
|
||||
if (visibility) {
|
||||
bottomSheetView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
bottomSheetView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceFragment(int playerBottomSheet) {
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
playerBottomSheet,
|
||||
playerBottomSheetFragment,
|
||||
"PlayerBottomSheet")
|
||||
.commit();
|
||||
}
|
||||
|
||||
public void checkAfterStateChanged(MainViewModel mainViewModel) {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> setStateInPeek(mainViewModel.isQueueLoaded());
|
||||
handler.postDelayed(runnable, 100);
|
||||
}
|
||||
|
||||
public void collapseDelayed() {
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = () -> bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
handler.postDelayed(runnable, 100);
|
||||
}
|
||||
|
||||
public void setDraggable(Boolean isDraggable) {
|
||||
bottomSheetBehavior.setDraggable((isDraggable));
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return bottomSheetBehavior.getState();
|
||||
}
|
||||
|
||||
public void animate(float slideOffset) {
|
||||
if (playerBottomSheetFragment != null) {
|
||||
float condensedSlideOffset = Math.max(0.0f, Math.min(0.2f, slideOffset - 0.2f)) / 0.2f;
|
||||
playerBottomSheetFragment.getPlayerHeader().setAlpha(1 - condensedSlideOffset);
|
||||
playerBottomSheetFragment.getPlayerHeader().setVisibility(condensedSlideOffset > 0.99 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPeekHeight(int peekHeight, float displayDensity) {
|
||||
int newPeekPx = (int) (peekHeight * displayDensity);
|
||||
bottomSheetBehavior.setPeekHeight(newPeekPx);
|
||||
}
|
||||
}
|
||||
@@ -26,16 +26,20 @@ import com.cappielloantonio.tempo.helper.recyclerview.CustomLinearSnapHelper;
|
||||
import com.cappielloantonio.tempo.interfaces.ClickCallback;
|
||||
import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.tempo.ui.adapter.AlbumAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.ArtistAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.ui.adapter.PlaylistHorizontalAdapter;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.viewmodel.PlaybackViewModel;
|
||||
import com.cappielloantonio.tempo.viewmodel.SearchViewModel;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PlaylistWithSongs;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@UnstableApi
|
||||
public class SearchFragment extends Fragment implements ClickCallback {
|
||||
@@ -49,6 +53,7 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
||||
private ArtistAdapter artistAdapter;
|
||||
private AlbumAdapter albumAdapter;
|
||||
private SongHorizontalAdapter songHorizontalAdapter;
|
||||
private PlaylistHorizontalAdapter playlistHorizontalAdapter;
|
||||
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
|
||||
@@ -126,6 +131,12 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
||||
reapplyPlayback();
|
||||
|
||||
bind.searchResultTracksRecyclerView.setAdapter(songHorizontalAdapter);
|
||||
|
||||
bind.allsongsview.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||
bind.allsongsview.setHasFixedSize(true);
|
||||
|
||||
playlistHorizontalAdapter = new PlaylistHorizontalAdapter(this);
|
||||
bind.allsongsview.setAdapter(playlistHorizontalAdapter);
|
||||
}
|
||||
|
||||
private void initSearchView() {
|
||||
@@ -216,13 +227,23 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
||||
|
||||
public void search(String query) {
|
||||
searchViewModel.setQuery(query);
|
||||
bind.allSongs.setText(this.getView().getContext().getString(R.string.search_all_songs_loading));
|
||||
playlistHorizontalAdapter.setItems(Collections.emptyList());
|
||||
bind.searchBar.setText(query);
|
||||
bind.searchView.hide();
|
||||
performSearch(query);
|
||||
}
|
||||
|
||||
public void updateUI(List<Playlist> allSongs) {
|
||||
if (!allSongs.isEmpty()) {
|
||||
playlistHorizontalAdapter.setItems(allSongs);
|
||||
} else {
|
||||
playlistHorizontalAdapter.setItems(Collections.emptyList());
|
||||
}
|
||||
bind.allSongs.setText(this.getView().getContext().getString(R.string.search_all_songs_play,String.valueOf(allSongs.getFirst().getName())));
|
||||
}
|
||||
private void performSearch(String query) {
|
||||
searchViewModel.search3(query).observe(getViewLifecycleOwner(), result -> {
|
||||
searchViewModel.search3(this, query).observe(getViewLifecycleOwner(), result -> {
|
||||
if (bind != null) {
|
||||
if (result.getArtists() != null) {
|
||||
bind.searchArtistSector.setVisibility(!result.getArtists().isEmpty() ? View.VISIBLE : View.GONE);
|
||||
@@ -281,6 +302,19 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.songBottomSheetDialog, bundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaylistClick(Bundle bundle) {
|
||||
PlaylistWithSongs playlistWithSongs = bundle.getParcelable(Constants.PLAYLIST_OBJECT);
|
||||
if (playlistWithSongs != null) {
|
||||
MediaManager.startQueue(mediaBrowserListenableFuture, playlistWithSongs.getEntries(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaylistLongClick(Bundle bundle) {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.playlistBottomSheetDialog, bundle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAlbumClick(Bundle bundle) {
|
||||
Navigation.findNavController(requireView()).navigate(R.id.albumPageFragment, bundle);
|
||||
|
||||
@@ -0,0 +1,603 @@
|
||||
package com.cappielloantonio.tempo.ui.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.os.LocaleListCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavOptions;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.cappielloantonio.tempo.BuildConfig;
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.helper.ThemeHelper;
|
||||
import com.cappielloantonio.tempo.interfaces.DialogClickCallback;
|
||||
import com.cappielloantonio.tempo.interfaces.ScanCallback;
|
||||
import com.cappielloantonio.tempo.service.EqualizerManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.tempo.ui.dialog.DeleteDownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.DownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredAlbumSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredArtistSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StreamingCacheStorageDialog;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.ExternalAudioReader;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.util.UIUtil;
|
||||
import com.cappielloantonio.tempo.viewmodel.SettingViewModel;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class SettingsContainerFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private static final String TAG = "SettingsFragment";
|
||||
private MainActivity activity;
|
||||
|
||||
private SettingViewModel settingViewModel;
|
||||
|
||||
private ActivityResultLauncher<Intent> directoryPickerLauncher;
|
||||
|
||||
private MediaService.LocalBinder mediaServiceBinder;
|
||||
private boolean isServiceBound = false;
|
||||
private ActivityResultLauncher<Intent> equalizerResultLauncher;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
equalizerResultLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {}
|
||||
);
|
||||
|
||||
if (!BuildConfig.FLAVOR.equals("tempus")) {
|
||||
PreferenceCategory githubUpdateCategory = findPreference("settings_github_update_category_key");
|
||||
if (githubUpdateCategory != null) {
|
||||
getPreferenceScreen().removePreference(githubUpdateCategory);
|
||||
}
|
||||
}
|
||||
|
||||
directoryPickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == Activity.RESULT_OK) {
|
||||
Intent data = result.getData();
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
requireContext().getContentResolver().takePersistableUriPermission(
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
);
|
||||
|
||||
Preferences.setDownloadDirectoryUri(uri.toString());
|
||||
ExternalAudioReader.refreshCache();
|
||||
Toast.makeText(requireContext(), R.string.settings_download_folder_set, Toast.LENGTH_SHORT).show();
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
settingViewModel = new ViewModelProvider(requireActivity()).get(SettingViewModel.class);
|
||||
|
||||
if (view != null) {
|
||||
getListView().setPadding(0, 0, 0, (int) getResources().getDimension(R.dimen.global_padding_bottom));
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
activity.setBottomNavigationBarVisibility(false);
|
||||
activity.setBottomSheetVisibility(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
checkSystemEqualizer();
|
||||
checkCacheStorage();
|
||||
checkStorage();
|
||||
checkDownloadDirectory();
|
||||
|
||||
setStreamingCacheSize();
|
||||
setAppLanguage();
|
||||
setVersion();
|
||||
setNetorkPingTimeoutBase();
|
||||
|
||||
actionLogout();
|
||||
actionScan();
|
||||
actionSyncStarredAlbums();
|
||||
actionSyncStarredTracks();
|
||||
actionSyncStarredArtists();
|
||||
actionChangeStreamingCacheStorage();
|
||||
actionChangeDownloadStorage();
|
||||
actionSetDownloadDirectory();
|
||||
actionDeleteDownloadStorage();
|
||||
actionKeepScreenOn();
|
||||
actionAutoDownloadLyrics();
|
||||
actionMiniPlayerHeart();
|
||||
|
||||
bindMediaService();
|
||||
actionAppEqualizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.global_preferences, rootKey);
|
||||
ListPreference themePreference = findPreference(Preferences.THEME);
|
||||
if (themePreference != null) {
|
||||
themePreference.setOnPreferenceChangeListener(
|
||||
(preference, newValue) -> {
|
||||
String themeOption = (String) newValue;
|
||||
ThemeHelper.applyTheme(themeOption);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSystemEqualizer() {
|
||||
Preference equalizer = findPreference("system_equalizer");
|
||||
|
||||
if (equalizer == null) return;
|
||||
|
||||
Intent intent = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
|
||||
|
||||
if ((intent.resolveActivity(requireActivity().getPackageManager()) != null)) {
|
||||
equalizer.setOnPreferenceClickListener(preference -> {
|
||||
equalizerResultLauncher.launch(intent);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
equalizer.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCacheStorage() {
|
||||
Preference storage = findPreference("streaming_cache_storage");
|
||||
|
||||
if (storage == null) return;
|
||||
|
||||
try {
|
||||
if (requireContext().getExternalFilesDirs(null)[1] == null) {
|
||||
storage.setVisible(false);
|
||||
} else {
|
||||
storage.setSummary(Preferences.getStreamingCacheStoragePreference() == 0 ? R.string.download_storage_internal_dialog_negative_button : R.string.download_storage_external_dialog_positive_button);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
storage.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkStorage() {
|
||||
Preference storage = findPreference("download_storage");
|
||||
|
||||
if (storage == null) return;
|
||||
|
||||
try {
|
||||
if (requireContext().getExternalFilesDirs(null)[1] == null) {
|
||||
storage.setVisible(false);
|
||||
} else {
|
||||
int pref = Preferences.getDownloadStoragePreference();
|
||||
if (pref == 0) {
|
||||
storage.setSummary(R.string.download_storage_internal_dialog_negative_button);
|
||||
} else if (pref == 1) {
|
||||
storage.setSummary(R.string.download_storage_external_dialog_positive_button);
|
||||
} else {
|
||||
storage.setSummary(R.string.download_storage_directory_dialog_neutral_button);
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
storage.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDownloadDirectory() {
|
||||
Preference storage = findPreference("download_storage");
|
||||
Preference directory = findPreference("set_download_directory");
|
||||
|
||||
if (directory == null) return;
|
||||
|
||||
String current = Preferences.getDownloadDirectoryUri();
|
||||
if (current != null) {
|
||||
if (storage != null) storage.setVisible(false);
|
||||
directory.setVisible(true);
|
||||
directory.setIcon(R.drawable.ic_close);
|
||||
directory.setTitle(R.string.settings_clear_download_folder);
|
||||
directory.setSummary(current);
|
||||
} else {
|
||||
if (storage != null) storage.setVisible(true);
|
||||
if (Preferences.getDownloadStoragePreference() == 2) {
|
||||
directory.setVisible(true);
|
||||
directory.setIcon(R.drawable.ic_folder);
|
||||
directory.setTitle(R.string.settings_set_download_folder);
|
||||
directory.setSummary(R.string.settings_choose_download_folder);
|
||||
} else {
|
||||
directory.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setNetorkPingTimeoutBase() {
|
||||
EditTextPreference networkPingTimeoutBase = findPreference("network_ping_timeout_base");
|
||||
|
||||
if (networkPingTimeoutBase != null) {
|
||||
networkPingTimeoutBase.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
|
||||
networkPingTimeoutBase.setOnBindEditTextListener(editText -> {
|
||||
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
editText.setFilters(new InputFilter[]{ (source, start, end, dest, dstart, dend) -> {
|
||||
for (int i = start; i < end; i++) {
|
||||
if (!Character.isDigit(source.charAt(i))) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}});
|
||||
});
|
||||
|
||||
networkPingTimeoutBase.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
String input = (String) newValue;
|
||||
return input != null && !input.isEmpty();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setStreamingCacheSize() {
|
||||
ListPreference streamingCachePreference = findPreference("streaming_cache_size");
|
||||
|
||||
if (streamingCachePreference != null) {
|
||||
streamingCachePreference.setSummaryProvider(new Preference.SummaryProvider<ListPreference>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence provideSummary(@NonNull ListPreference preference) {
|
||||
CharSequence entry = preference.getEntry();
|
||||
|
||||
if (entry == null) return null;
|
||||
|
||||
long currentSizeMb = DownloadUtil.getStreamingCacheSize(requireActivity()) / (1024 * 1024);
|
||||
|
||||
return getString(R.string.settings_summary_streaming_cache_size, entry, String.valueOf(currentSizeMb));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
String value = localePref.getValue();
|
||||
if ("default".equals(value)) {
|
||||
localePref.setSummary(requireContext().getString(R.string.settings_system_language));
|
||||
} else {
|
||||
localePref.setSummary(Locale.forLanguageTag(value).getDisplayName());
|
||||
}
|
||||
|
||||
localePref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if ("default".equals(newValue)) {
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList());
|
||||
preference.setSummary(requireContext().getString(R.string.settings_system_language));
|
||||
} else {
|
||||
LocaleListCompat appLocale = LocaleListCompat.forLanguageTags((String) newValue);
|
||||
AppCompatDelegate.setApplicationLocales(appLocale);
|
||||
preference.setSummary(Locale.forLanguageTag((String) newValue).getDisplayName());
|
||||
}
|
||||
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) {
|
||||
findPreference("scan_library").setSummary(getString(R.string.settings_scan_result, count));
|
||||
if (isScanning) 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(() -> {
|
||||
((SwitchPreference)preference).setChecked(false);
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionSyncStarredAlbums() {
|
||||
findPreference("sync_starred_albums_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
StarredAlbumSyncDialog dialog = new StarredAlbumSyncDialog(() -> {
|
||||
((SwitchPreference)preference).setChecked(false);
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionSyncStarredArtists() {
|
||||
findPreference("sync_starred_artists_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
StarredArtistSyncDialog dialog = new StarredArtistSyncDialog(() -> {
|
||||
((SwitchPreference)preference).setChecked(false);
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionChangeStreamingCacheStorage() {
|
||||
findPreference("streaming_cache_storage").setOnPreferenceClickListener(preference -> {
|
||||
StreamingCacheStorageDialog dialog = new StreamingCacheStorageDialog(new DialogClickCallback() {
|
||||
@Override
|
||||
public void onPositiveClick() {
|
||||
findPreference("streaming_cache_storage").setSummary(R.string.streaming_cache_storage_external_dialog_positive_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegativeClick() {
|
||||
findPreference("streaming_cache_storage").setSummary(R.string.streaming_cache_storage_internal_dialog_negative_button);
|
||||
}
|
||||
});
|
||||
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);
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegativeClick() {
|
||||
findPreference("download_storage").setSummary(R.string.download_storage_internal_dialog_negative_button);
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeutralClick() {
|
||||
findPreference("download_storage").setSummary(R.string.download_storage_directory_dialog_neutral_button);
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionSetDownloadDirectory() {
|
||||
Preference pref = findPreference("set_download_directory");
|
||||
if (pref != null) {
|
||||
pref.setOnPreferenceClickListener(preference -> {
|
||||
String current = Preferences.getDownloadDirectoryUri();
|
||||
|
||||
if (current != null) {
|
||||
Preferences.setDownloadDirectoryUri(null);
|
||||
Preferences.setDownloadStoragePreference(0);
|
||||
ExternalAudioReader.refreshCache();
|
||||
Toast.makeText(requireContext(), R.string.settings_download_folder_cleared, Toast.LENGTH_SHORT).show();
|
||||
checkStorage();
|
||||
checkDownloadDirectory();
|
||||
} else {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
|
||||
| Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
directoryPickerLauncher.launch(intent);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void actionDeleteDownloadStorage() {
|
||||
findPreference("delete_download_storage").setOnPreferenceClickListener(preference -> {
|
||||
DeleteDownloadStorageDialog dialog = new DeleteDownloadStorageDialog();
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionMiniPlayerHeart() {
|
||||
SwitchPreference preference = findPreference("mini_shuffle_button_visibility");
|
||||
if (preference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
preference.setChecked(Preferences.showShuffleInsteadOfHeart());
|
||||
preference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
Preferences.setShuffleInsteadOfHeart((Boolean) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionAutoDownloadLyrics() {
|
||||
SwitchPreference preference = findPreference("auto_download_lyrics");
|
||||
if (preference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
preference.setChecked(Preferences.isAutoDownloadLyricsEnabled());
|
||||
preference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
Preferences.setAutoDownloadLyricsEnabled((Boolean) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void getScanStatus() {
|
||||
settingViewModel.getScanStatus(new ScanCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
findPreference("scan_library").setSummary(exception.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(boolean isScanning, long count) {
|
||||
findPreference("scan_library").setSummary(getString(R.string.settings_scan_result, count));
|
||||
if (isScanning) getScanStatus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void actionKeepScreenOn() {
|
||||
findPreference("always_on_display").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
mediaServiceBinder = (MediaService.LocalBinder) service;
|
||||
isServiceBound = true;
|
||||
checkEqualizerBands();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
mediaServiceBinder = null;
|
||||
isServiceBound = false;
|
||||
}
|
||||
};
|
||||
|
||||
private void bindMediaService() {
|
||||
Intent intent = new Intent(requireActivity(), MediaService.class);
|
||||
intent.setAction(MediaService.ACTION_BIND_EQUALIZER);
|
||||
requireActivity().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
isServiceBound = true;
|
||||
}
|
||||
|
||||
private void checkEqualizerBands() {
|
||||
if (mediaServiceBinder != null) {
|
||||
EqualizerManager eqManager = mediaServiceBinder.getEqualizerManager();
|
||||
short numBands = eqManager.getNumberOfBands();
|
||||
Preference appEqualizer = findPreference("app_equalizer");
|
||||
if (appEqualizer != null) {
|
||||
appEqualizer.setVisible(numBands > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void actionAppEqualizer() {
|
||||
Preference appEqualizer = findPreference("app_equalizer");
|
||||
if (appEqualizer != null) {
|
||||
appEqualizer.setOnPreferenceClickListener(preference -> {
|
||||
NavController navController = NavHostFragment.findNavController(this);
|
||||
NavOptions navOptions = new NavOptions.Builder()
|
||||
.setLaunchSingleTop(true)
|
||||
.setPopUpTo(R.id.equalizerFragment, true)
|
||||
.build();
|
||||
activity.setBottomNavigationBarVisibility(true);
|
||||
activity.setBottomSheetVisibility(true);
|
||||
navController.navigate(R.id.equalizerFragment, null, navOptions);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (isServiceBound) {
|
||||
requireActivity().unbindService(serviceConnection);
|
||||
isServiceBound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +1,61 @@
|
||||
package com.cappielloantonio.tempo.ui.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.net.Uri;
|
||||
import static com.google.android.material.internal.ViewUtils.hideKeyboard;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.os.LocaleListCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavOptions;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.cappielloantonio.tempo.BuildConfig;
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.helper.ThemeHelper;
|
||||
import com.cappielloantonio.tempo.interfaces.DialogClickCallback;
|
||||
import com.cappielloantonio.tempo.interfaces.ScanCallback;
|
||||
import com.cappielloantonio.tempo.service.EqualizerManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.databinding.FragmentSettingsBinding;
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.tempo.ui.dialog.DeleteDownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.DownloadStorageDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredAlbumSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StarredArtistSyncDialog;
|
||||
import com.cappielloantonio.tempo.ui.dialog.StreamingCacheStorageDialog;
|
||||
import com.cappielloantonio.tempo.util.DownloadUtil;
|
||||
import com.cappielloantonio.tempo.util.Preferences;
|
||||
import com.cappielloantonio.tempo.util.UIUtil;
|
||||
import com.cappielloantonio.tempo.util.ExternalAudioReader;
|
||||
import com.cappielloantonio.tempo.viewmodel.SettingViewModel;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
private static final String TAG = "SettingsFragment";
|
||||
public class SettingsFragment extends Fragment {
|
||||
|
||||
private MainActivity activity;
|
||||
private SettingViewModel settingViewModel;
|
||||
|
||||
private ActivityResultLauncher<Intent> equalizerResultLauncher;
|
||||
private ActivityResultLauncher<Intent> directoryPickerLauncher;
|
||||
|
||||
private MediaService.LocalBinder mediaServiceBinder;
|
||||
private boolean isServiceBound = false;
|
||||
private FragmentSettingsBinding bind;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
equalizerResultLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {}
|
||||
);
|
||||
activity = (MainActivity) getActivity();
|
||||
|
||||
if (!BuildConfig.FLAVOR.equals("tempus")) {
|
||||
PreferenceCategory githubUpdateCategory = findPreference("settings_github_update_category_key");
|
||||
if (githubUpdateCategory != null) {
|
||||
getPreferenceScreen().removePreference(githubUpdateCategory);
|
||||
}
|
||||
}
|
||||
|
||||
directoryPickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
if (result.getResultCode() == Activity.RESULT_OK) {
|
||||
Intent data = result.getData();
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
if (uri != null) {
|
||||
requireContext().getContentResolver().takePersistableUriPermission(
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
);
|
||||
|
||||
Preferences.setDownloadDirectoryUri(uri.toString());
|
||||
ExternalAudioReader.refreshCache();
|
||||
Toast.makeText(requireContext(), R.string.settings_download_folder_set, Toast.LENGTH_SHORT).show();
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = (MainActivity) getActivity();
|
||||
bind = FragmentSettingsBinding.inflate(inflater,container,false);
|
||||
View view = bind.getRoot();
|
||||
|
||||
View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
settingViewModel = new ViewModelProvider(requireActivity()).get(SettingViewModel.class);
|
||||
|
||||
if (view != null) {
|
||||
getListView().setPadding(0, 0, 0, (int) getResources().getDimension(R.dimen.global_padding_bottom));
|
||||
}
|
||||
initAppBar();
|
||||
|
||||
return view;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// Add the PreferenceFragment only the first time
|
||||
if (savedInstanceState == null) {
|
||||
SettingsContainerFragment prefFragment = new SettingsContainerFragment();
|
||||
|
||||
// Use the child fragment manager so the PreferenceFragment is scoped to this fragment
|
||||
getChildFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings_container, prefFragment)
|
||||
.setReorderingAllowed(true) // optional but recommended
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,479 +67,21 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
activity.setSystemBarsVisibility(!activity.isLandscape);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
checkSystemEqualizer();
|
||||
checkCacheStorage();
|
||||
checkStorage();
|
||||
checkDownloadDirectory();
|
||||
|
||||
setStreamingCacheSize();
|
||||
setAppLanguage();
|
||||
setVersion();
|
||||
setNetorkPingTimeoutBase();
|
||||
|
||||
actionLogout();
|
||||
actionScan();
|
||||
actionSyncStarredAlbums();
|
||||
actionSyncStarredTracks();
|
||||
actionSyncStarredArtists();
|
||||
actionChangeStreamingCacheStorage();
|
||||
actionChangeDownloadStorage();
|
||||
actionSetDownloadDirectory();
|
||||
actionDeleteDownloadStorage();
|
||||
actionKeepScreenOn();
|
||||
actionAutoDownloadLyrics();
|
||||
actionMiniPlayerHeart();
|
||||
|
||||
bindMediaService();
|
||||
actionAppEqualizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
activity.setBottomSheetVisibility(true);
|
||||
activity.toggleNavigationDrawerLockOnOrientationChange();
|
||||
activity.setSystemBarsVisibility(!activity.isLandscape);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.global_preferences, rootKey);
|
||||
ListPreference themePreference = findPreference(Preferences.THEME);
|
||||
if (themePreference != null) {
|
||||
themePreference.setOnPreferenceChangeListener(
|
||||
(preference, newValue) -> {
|
||||
String themeOption = (String) newValue;
|
||||
ThemeHelper.applyTheme(themeOption);
|
||||
return true;
|
||||
});
|
||||
if (activity.isLandscape) {
|
||||
activity.setNavigationDrawerLock(false);
|
||||
} else if (Preferences.getEnableDrawerOnPortrait()) {
|
||||
activity.setNavigationDrawerLock(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSystemEqualizer() {
|
||||
Preference equalizer = findPreference("system_equalizer");
|
||||
|
||||
if (equalizer == null) return;
|
||||
|
||||
Intent intent = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
|
||||
|
||||
if ((intent.resolveActivity(requireActivity().getPackageManager()) != null)) {
|
||||
equalizer.setOnPreferenceClickListener(preference -> {
|
||||
equalizerResultLauncher.launch(intent);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
equalizer.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCacheStorage() {
|
||||
Preference storage = findPreference("streaming_cache_storage");
|
||||
|
||||
if (storage == null) return;
|
||||
|
||||
try {
|
||||
if (requireContext().getExternalFilesDirs(null)[1] == null) {
|
||||
storage.setVisible(false);
|
||||
} else {
|
||||
storage.setSummary(Preferences.getStreamingCacheStoragePreference() == 0 ? R.string.download_storage_internal_dialog_negative_button : R.string.download_storage_external_dialog_positive_button);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
storage.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkStorage() {
|
||||
Preference storage = findPreference("download_storage");
|
||||
|
||||
if (storage == null) return;
|
||||
|
||||
try {
|
||||
if (requireContext().getExternalFilesDirs(null)[1] == null) {
|
||||
storage.setVisible(false);
|
||||
} else {
|
||||
int pref = Preferences.getDownloadStoragePreference();
|
||||
if (pref == 0) {
|
||||
storage.setSummary(R.string.download_storage_internal_dialog_negative_button);
|
||||
} else if (pref == 1) {
|
||||
storage.setSummary(R.string.download_storage_external_dialog_positive_button);
|
||||
} else {
|
||||
storage.setSummary(R.string.download_storage_directory_dialog_neutral_button);
|
||||
}
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
storage.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDownloadDirectory() {
|
||||
Preference storage = findPreference("download_storage");
|
||||
Preference directory = findPreference("set_download_directory");
|
||||
|
||||
if (directory == null) return;
|
||||
|
||||
String current = Preferences.getDownloadDirectoryUri();
|
||||
if (current != null) {
|
||||
if (storage != null) storage.setVisible(false);
|
||||
directory.setVisible(true);
|
||||
directory.setIcon(R.drawable.ic_close);
|
||||
directory.setTitle(R.string.settings_clear_download_folder);
|
||||
directory.setSummary(current);
|
||||
} else {
|
||||
if (storage != null) storage.setVisible(true);
|
||||
if (Preferences.getDownloadStoragePreference() == 2) {
|
||||
directory.setVisible(true);
|
||||
directory.setIcon(R.drawable.ic_folder);
|
||||
directory.setTitle(R.string.settings_set_download_folder);
|
||||
directory.setSummary(R.string.settings_choose_download_folder);
|
||||
} else {
|
||||
directory.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setNetorkPingTimeoutBase() {
|
||||
EditTextPreference networkPingTimeoutBase = findPreference("network_ping_timeout_base");
|
||||
|
||||
if (networkPingTimeoutBase != null) {
|
||||
networkPingTimeoutBase.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
|
||||
networkPingTimeoutBase.setOnBindEditTextListener(editText -> {
|
||||
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
editText.setFilters(new InputFilter[]{ (source, start, end, dest, dstart, dend) -> {
|
||||
for (int i = start; i < end; i++) {
|
||||
if (!Character.isDigit(source.charAt(i))) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}});
|
||||
private void initAppBar() {
|
||||
bind.settingsToolbar.setNavigationOnClickListener(v -> {
|
||||
activity.navController.navigateUp();
|
||||
});
|
||||
|
||||
networkPingTimeoutBase.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
String input = (String) newValue;
|
||||
return input != null && !input.isEmpty();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setStreamingCacheSize() {
|
||||
ListPreference streamingCachePreference = findPreference("streaming_cache_size");
|
||||
|
||||
if (streamingCachePreference != null) {
|
||||
streamingCachePreference.setSummaryProvider(new Preference.SummaryProvider<ListPreference>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence provideSummary(@NonNull ListPreference preference) {
|
||||
CharSequence entry = preference.getEntry();
|
||||
|
||||
if (entry == null) return null;
|
||||
|
||||
long currentSizeMb = DownloadUtil.getStreamingCacheSize(requireActivity()) / (1024 * 1024);
|
||||
|
||||
return getString(R.string.settings_summary_streaming_cache_size, entry, String.valueOf(currentSizeMb));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
String value = localePref.getValue();
|
||||
if ("default".equals(value)) {
|
||||
localePref.setSummary(requireContext().getString(R.string.settings_system_language));
|
||||
} else {
|
||||
localePref.setSummary(Locale.forLanguageTag(value).getDisplayName());
|
||||
}
|
||||
|
||||
localePref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if ("default".equals(newValue)) {
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList());
|
||||
preference.setSummary(requireContext().getString(R.string.settings_system_language));
|
||||
} else {
|
||||
LocaleListCompat appLocale = LocaleListCompat.forLanguageTags((String) newValue);
|
||||
AppCompatDelegate.setApplicationLocales(appLocale);
|
||||
preference.setSummary(Locale.forLanguageTag((String) newValue).getDisplayName());
|
||||
}
|
||||
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) {
|
||||
findPreference("scan_library").setSummary(getString(R.string.settings_scan_result, count));
|
||||
if (isScanning) 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(() -> {
|
||||
((SwitchPreference)preference).setChecked(false);
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionSyncStarredAlbums() {
|
||||
findPreference("sync_starred_albums_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
StarredAlbumSyncDialog dialog = new StarredAlbumSyncDialog(() -> {
|
||||
((SwitchPreference)preference).setChecked(false);
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionSyncStarredArtists() {
|
||||
findPreference("sync_starred_artists_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
StarredArtistSyncDialog dialog = new StarredArtistSyncDialog(() -> {
|
||||
((SwitchPreference)preference).setChecked(false);
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionChangeStreamingCacheStorage() {
|
||||
findPreference("streaming_cache_storage").setOnPreferenceClickListener(preference -> {
|
||||
StreamingCacheStorageDialog dialog = new StreamingCacheStorageDialog(new DialogClickCallback() {
|
||||
@Override
|
||||
public void onPositiveClick() {
|
||||
findPreference("streaming_cache_storage").setSummary(R.string.streaming_cache_storage_external_dialog_positive_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegativeClick() {
|
||||
findPreference("streaming_cache_storage").setSummary(R.string.streaming_cache_storage_internal_dialog_negative_button);
|
||||
}
|
||||
});
|
||||
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);
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNegativeClick() {
|
||||
findPreference("download_storage").setSummary(R.string.download_storage_internal_dialog_negative_button);
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeutralClick() {
|
||||
findPreference("download_storage").setSummary(R.string.download_storage_directory_dialog_neutral_button);
|
||||
checkDownloadDirectory();
|
||||
}
|
||||
});
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionSetDownloadDirectory() {
|
||||
Preference pref = findPreference("set_download_directory");
|
||||
if (pref != null) {
|
||||
pref.setOnPreferenceClickListener(preference -> {
|
||||
String current = Preferences.getDownloadDirectoryUri();
|
||||
|
||||
if (current != null) {
|
||||
Preferences.setDownloadDirectoryUri(null);
|
||||
Preferences.setDownloadStoragePreference(0);
|
||||
ExternalAudioReader.refreshCache();
|
||||
Toast.makeText(requireContext(), R.string.settings_download_folder_cleared, Toast.LENGTH_SHORT).show();
|
||||
checkStorage();
|
||||
checkDownloadDirectory();
|
||||
} else {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
|
||||
| Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
directoryPickerLauncher.launch(intent);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void actionDeleteDownloadStorage() {
|
||||
findPreference("delete_download_storage").setOnPreferenceClickListener(preference -> {
|
||||
DeleteDownloadStorageDialog dialog = new DeleteDownloadStorageDialog();
|
||||
dialog.show(activity.getSupportFragmentManager(), null);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionMiniPlayerHeart() {
|
||||
SwitchPreference preference = findPreference("mini_shuffle_button_visibility");
|
||||
if (preference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
preference.setChecked(Preferences.showShuffleInsteadOfHeart());
|
||||
preference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
Preferences.setShuffleInsteadOfHeart((Boolean) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void actionAutoDownloadLyrics() {
|
||||
SwitchPreference preference = findPreference("auto_download_lyrics");
|
||||
if (preference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
preference.setChecked(Preferences.isAutoDownloadLyricsEnabled());
|
||||
preference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
Preferences.setAutoDownloadLyricsEnabled((Boolean) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void getScanStatus() {
|
||||
settingViewModel.getScanStatus(new ScanCallback() {
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
findPreference("scan_library").setSummary(exception.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(boolean isScanning, long count) {
|
||||
findPreference("scan_library").setSummary(getString(R.string.settings_scan_result, count));
|
||||
if (isScanning) getScanStatus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void actionKeepScreenOn() {
|
||||
findPreference("always_on_display").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
mediaServiceBinder = (MediaService.LocalBinder) service;
|
||||
isServiceBound = true;
|
||||
checkEqualizerBands();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
mediaServiceBinder = null;
|
||||
isServiceBound = false;
|
||||
}
|
||||
};
|
||||
|
||||
private void bindMediaService() {
|
||||
Intent intent = new Intent(requireActivity(), MediaService.class);
|
||||
intent.setAction(MediaService.ACTION_BIND_EQUALIZER);
|
||||
requireActivity().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
isServiceBound = true;
|
||||
}
|
||||
|
||||
private void checkEqualizerBands() {
|
||||
if (mediaServiceBinder != null) {
|
||||
EqualizerManager eqManager = mediaServiceBinder.getEqualizerManager();
|
||||
short numBands = eqManager.getNumberOfBands();
|
||||
Preference appEqualizer = findPreference("app_equalizer");
|
||||
if (appEqualizer != null) {
|
||||
appEqualizer.setVisible(numBands > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void actionAppEqualizer() {
|
||||
Preference appEqualizer = findPreference("app_equalizer");
|
||||
if (appEqualizer != null) {
|
||||
appEqualizer.setOnPreferenceClickListener(preference -> {
|
||||
NavController navController = NavHostFragment.findNavController(this);
|
||||
NavOptions navOptions = new NavOptions.Builder()
|
||||
.setLaunchSingleTop(true)
|
||||
.setPopUpTo(R.id.equalizerFragment, true)
|
||||
.build();
|
||||
activity.setBottomNavigationBarVisibility(true);
|
||||
activity.setBottomSheetVisibility(true);
|
||||
navController.navigate(R.id.equalizerFragment, null, navOptions);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (isServiceBound) {
|
||||
requireActivity().unbindService(serviceConnection);
|
||||
isServiceBound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,4 +299,4 @@ public class AlbumBottomSheetDialog extends BottomSheetDialogFragment implements
|
||||
homeViewModel.refreshShares(requireActivity());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.session.MediaBrowser;
|
||||
import androidx.media3.session.SessionToken;
|
||||
|
||||
import com.cappielloantonio.tempo.R;
|
||||
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
|
||||
import com.cappielloantonio.tempo.service.MediaManager;
|
||||
import com.cappielloantonio.tempo.service.MediaService;
|
||||
import com.cappielloantonio.tempo.subsonic.models.PlaylistWithSongs;
|
||||
import com.cappielloantonio.tempo.ui.activity.MainActivity;
|
||||
import com.cappielloantonio.tempo.util.Constants;
|
||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
@UnstableApi
|
||||
public class PlaylistBottomSheetDialog extends BottomSheetDialogFragment implements View.OnClickListener {
|
||||
private PlaylistWithSongs playlist;
|
||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||
private static final String TAG = "PlaylistBottomSheetDialog";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.bottom_sheet_playlist_dialog, container, false);
|
||||
|
||||
playlist = requireArguments().getParcelable(Constants.PLAYLIST_OBJECT);
|
||||
|
||||
init(view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
initializeMediaBrowser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
releaseMediaBrowser();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private void init(View view) {
|
||||
ImageView coverPlaylist = view.findViewById(R.id.playlist_cover_image_view);
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(view.getContext(), playlist.getCoverArtId(), CustomGlideRequest.ResourceType.Playlist)
|
||||
.build()
|
||||
.into(coverPlaylist);
|
||||
|
||||
TextView titlePlaylist = view.findViewById(R.id.playlist_title_text_view);
|
||||
titlePlaylist.setText(playlist.getName());
|
||||
|
||||
titlePlaylist.setSelected(true);
|
||||
|
||||
TextView countPlaylist = view.findViewById(R.id.playlist_count_text_view);
|
||||
countPlaylist.setText(view.getContext().getString(R.string.playlist_counted_tracks, playlist.getSongCount(), MusicUtil.getReadableDurationString(playlist.getDuration(), false)));
|
||||
|
||||
TextView playNext = view.findViewById(R.id.play_next_text_view);
|
||||
playNext.setOnClickListener(v -> {
|
||||
MediaManager.enqueue(mediaBrowserListenableFuture, playlist.getEntries(), true);
|
||||
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
|
||||
dismissBottomSheet();
|
||||
});
|
||||
|
||||
TextView addToQueue = view.findViewById(R.id.add_to_queue_text_view);
|
||||
addToQueue.setOnClickListener(v -> {
|
||||
MediaManager.enqueue(mediaBrowserListenableFuture, playlist.getEntries(), false);
|
||||
((MainActivity) requireActivity()).setBottomSheetInPeek(true);
|
||||
dismissBottomSheet();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dismissBottomSheet();
|
||||
}
|
||||
|
||||
private void dismissBottomSheet() {
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private void initializeMediaBrowser() {
|
||||
mediaBrowserListenableFuture = new MediaBrowser.Builder(requireContext(), new SessionToken(requireContext(), new ComponentName(requireContext(), MediaService.class))).buildAsync();
|
||||
}
|
||||
|
||||
private void releaseMediaBrowser() {
|
||||
MediaBrowser.releaseFuture(mediaBrowserListenableFuture);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -102,6 +102,7 @@ object Preferences {
|
||||
private const val AA_SECOND_TAB = "androidauto_second_tab"
|
||||
private const val AA_THIRD_TAB = "androidauto_third_tab"
|
||||
private const val AA_FOURTH_TAB = "androidauto_fourth_tab"
|
||||
private const val AA_SHUFFLE_GENRE_SONGS = "androidauto_shuffle_genre_songs"
|
||||
|
||||
@JvmStatic
|
||||
fun getServer(): String? {
|
||||
@@ -818,4 +819,14 @@ object Preferences {
|
||||
return App.getInstance().preferences.getString(AA_FOURTH_TAB, "3")!!.toInt()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isAndroidAutoShuffleGenreSongsEnabled(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(AA_SHUFFLE_GENRE_SONGS, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setAndroidAutoShuffleGenreSongsEnabled(enabled: Boolean) {
|
||||
App.getInstance().preferences.edit().putBoolean(AA_SHUFFLE_GENRE_SONGS, enabled).apply()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,11 +5,13 @@ import android.app.Application;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
|
||||
import com.cappielloantonio.tempo.model.RecentSearch;
|
||||
import com.cappielloantonio.tempo.repository.SearchingRepository;
|
||||
import com.cappielloantonio.tempo.subsonic.models.SearchResult2;
|
||||
import com.cappielloantonio.tempo.subsonic.models.SearchResult3;
|
||||
import com.cappielloantonio.tempo.ui.fragment.SearchFragment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -43,8 +45,9 @@ public class SearchViewModel extends AndroidViewModel {
|
||||
return searchingRepository.search2(title);
|
||||
}
|
||||
|
||||
public LiveData<SearchResult3> search3(String title) {
|
||||
return searchingRepository.search3(title);
|
||||
@UnstableApi
|
||||
public LiveData<SearchResult3> search3(SearchFragment sf, String title) {
|
||||
return searchingRepository.search3(sf, title);
|
||||
}
|
||||
|
||||
public void insertNewSearch(String search) {
|
||||
|
||||
11
app/src/main/res/drawable/ic_aa_genres.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="960"
|
||||
android:viewportWidth="960"
|
||||
android:width="24dp">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,660Q555,660 607.5,607.5Q660,555 660,480Q660,405 607.5,352.5Q555,300 480,300Q405,300 352.5,352.5Q300,405 300,480Q300,555 352.5,607.5Q405,660 480,660ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
|
||||
|
||||
</vector>
|
||||
10
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#FFEC4A4A"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
</vector>
|
||||
@@ -1,56 +1,77 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<group android:scaleX="0.49"
|
||||
android:scaleY="0.49"
|
||||
android:translateX="130.56"
|
||||
android:translateY="130.56">
|
||||
<path
|
||||
android:pathData="M512,437.33c0,11.78 -9.56,21.34 -21.34,21.34H21.33C9.55,458.67 0,449.11 0,437.33V96c0,-11.78 9.55,-21.33 21.33,-21.33h469.33c11.78,0 21.34,9.55 21.34,21.33L512,437.33L512,437.33z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M512,416.01c0,11.78 -9.56,21.31 -21.34,21.31H21.33C9.55,437.33 0,427.8 0,416.01V74.67c0,-11.78 9.55,-21.34 21.33,-21.34h469.33c11.78,0 21.34,9.56 21.34,21.34L512,416.01L512,416.01z"
|
||||
android:fillColor="#ED5564"/>
|
||||
<path
|
||||
android:pathData="M63.99,160c-5.89,0 -10.66,4.78 -10.66,10.67v149.34c0,5.88 4.77,10.66 10.66,10.66c5.89,0 10.67,-4.78 10.67,-10.66V170.67C74.66,164.78 69.88,160 63.99,160z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M74.66,106.67c0,5.89 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.77 -10.66,-10.66S58.1,96 63.99,96C69.88,96 74.66,100.78 74.66,106.67z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M74.66,384.01c0,5.88 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.78 -10.66,-10.66c0,-5.91 4.77,-10.69 10.66,-10.69C69.88,373.33 74.66,378.11 74.66,384.01z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M448,123.73h-21.34v203.19l-40.31,50.41v0.02c-1.47,1.83 -2.34,4.14 -2.34,6.67c0,5.88 4.78,10.66 10.66,10.66c3.38,0 6.38,-1.56 8.33,-4h0.02l42.66,-53.34l0,0c1.47,-1.81 2.34,-4.13 2.34,-6.66V123.73z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,149.33c-11.77,0 -21.33,-9.56 -21.33,-21.33s9.56,-21.33 21.33,-21.33s21.33,9.56 21.33,21.33S449.09,149.33 437.33,149.33z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,96c-17.67,0 -32,14.33 -32,32s14.33,32 32,32s32,-14.33 32,-32S455,96 437.33,96zM437.33,138.67c-5.89,0 -10.67,-4.8 -10.67,-10.67c0,-5.88 4.78,-10.67 10.67,-10.67s10.67,4.8 10.67,10.67C448,133.88 443.22,138.67 437.33,138.67z"
|
||||
android:fillColor="#CCD1D9"/>
|
||||
<path
|
||||
android:pathData="M405.33,245.33c0,82.48 -66.86,149.34 -149.33,149.34c-82.47,0 -149.33,-66.86 -149.33,-149.34C106.66,162.86 173.52,96 255.99,96C338.47,96 405.33,162.86 405.33,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M266.66,149.33c0,-5.89 -4.77,-10.66 -10.67,-10.66c-58.91,0 -106.66,47.75 -106.66,106.65l0,0c0,5.89 4.77,10.67 10.66,10.67s10.67,-4.78 10.67,-10.67l0,0c0,-22.78 8.88,-44.22 24.99,-60.33c16.12,-16.13 37.55,-25 60.34,-25C261.89,160 266.66,155.22 266.66,149.33z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M352,234.67c-5.9,0 -10.67,4.77 -10.67,10.66l0,0c0,22.8 -8.88,44.23 -24.98,60.34c-16.13,16.13 -37.56,25 -60.35,25c-5.89,0 -10.66,4.78 -10.66,10.66c0,5.91 4.77,10.69 10.66,10.69c58.91,0 106.66,-47.77 106.66,-106.69C362.65,239.44 357.89,234.67 352,234.67z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M255.99,288.01c-23.52,0 -42.66,-19.16 -42.66,-42.69c0,-23.52 19.14,-42.66 42.66,-42.66c23.54,0 42.66,19.14 42.66,42.66C298.65,268.86 279.53,288.01 255.99,288.01z"
|
||||
android:fillColor="#FFCE54"/>
|
||||
<path
|
||||
android:pathData="M255.99,192c-29.45,0 -53.33,23.88 -53.33,53.33s23.88,53.34 53.33,53.34c29.46,0 53.34,-23.89 53.34,-53.34S285.45,192 255.99,192zM255.99,277.34c-17.64,0 -32,-14.36 -32,-32.02c0,-17.64 14.36,-32 32,-32c17.65,0 32.01,14.36 32.01,32C288,262.98 273.64,277.34 255.99,277.34z"
|
||||
android:fillColor="#F6BB42"/>
|
||||
<path
|
||||
android:pathData="M266.66,245.33c0,5.89 -4.77,10.67 -10.67,10.67c-5.89,0 -10.66,-4.78 -10.66,-10.67s4.77,-10.66 10.66,-10.66C261.89,234.67 266.66,239.44 266.66,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M74.66,234.67H53.33c-5.89,0 -10.66,4.77 -10.66,10.66s4.77,10.67 10.66,10.67h21.34c5.89,0 10.66,-4.78 10.66,-10.67S80.56,234.67 74.66,234.67z"
|
||||
android:fillColor="#434A54"/>
|
||||
</group>
|
||||
</vector>
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<group
|
||||
android:scaleX="0.13"
|
||||
android:scaleY="0.13"
|
||||
android:translateX="21.5"
|
||||
android:translateY="21.5">
|
||||
<path
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FFEC4A4A" />
|
||||
<item android:offset="1.0" android:color="#FFEC4A4A" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
27
app/src/main/res/drawable/ic_launcher_monochrome.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<path
|
||||
android:fillColor="#424940"
|
||||
android:pathData="M54,50.6018C55.8768,50.6018 57.3982,52.1232 57.3982,54C57.3982,55.8768 55.8768,57.3982 54,57.3982C52.1232,57.3982 50.6018,55.8768 50.6018,54C50.6018,52.1232 52.1232,50.6018 54,50.6018Z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#424940"
|
||||
android:pathData="M54.1049,42.2712C60.6295,42.2712 65.9187,47.5605 65.9188,54.0851C65.9188,60.6097 60.6295,65.8989 54.1049,65.8989C47.5802,65.8989 42.2907,60.6097 42.2907,54.0851C42.2908,47.5604 47.5802,42.2712 54.1049,42.2712ZM54.0611,46.3408C49.7973,46.3408 46.3408,49.7973 46.3408,54.0611C46.3408,58.3249 49.7972,61.7815 54.0611,61.7816C58.3249,61.7816 61.7816,58.3249 61.7816,54.0611C61.7815,49.7972 58.3249,46.3408 54.0611,46.3408Z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#424940"
|
||||
android:pathData="M54,22.5C71.397,22.5 85.5,36.603 85.5,54C85.5,71.397 71.397,85.5 54,85.5C36.603,85.5 22.5,71.397 22.5,54C22.5,36.603 36.603,22.5 54,22.5ZM54.0506,26.9138C39.0743,26.9138 26.9334,39.0545 26.9334,54.0308C26.9334,69.007 39.0743,81.1477 54.0506,81.1477C69.0268,81.1476 81.1675,69.007 81.1675,54.0308C81.1675,39.0545 69.0268,26.9139 54.0506,26.9138Z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#424940"
|
||||
android:pathData="M43.4405,31.2951C43.9287,31.1317 44.4432,31.4282 44.5738,31.9262L46.9248,40.8911C47.055,41.3873 46.8662,41.9097 46.4665,42.2312C44.8479,43.5335 43.4426,45.0999 42.3131,46.8671C42.0058,47.3479 41.4269,47.5914 40.8765,47.4408L31.9176,44.9882C31.4322,44.8554 31.141,44.3566 31.2884,43.8754C33.1082,37.9357 37.6601,33.2302 43.4405,31.2951Z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#424940"
|
||||
android:pathData="M65.1611,75.9356C64.6879,76.0939 64.1895,75.8064 64.0629,75.3238L61.7908,66.6599C61.6607,66.1637 61.8495,65.6414 62.2488,65.3193C63.8012,64.0666 65.1506,62.5627 66.2378,60.8676C66.5459,60.3873 67.1247,60.1437 67.675,60.2943L76.3298,62.6636C76.8002,62.7924 77.0825,63.2759 76.9397,63.7422C75.1759,69.4992 70.7637,74.0601 65.1611,75.9356Z"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,56 +1,77 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<group android:scaleX="0.55"
|
||||
android:scaleY="0.55"
|
||||
android:translateX="150.56"
|
||||
android:translateY="150.56">
|
||||
<path
|
||||
android:pathData="M512,437.33c0,11.78 -9.56,21.34 -21.34,21.34H21.33C9.55,458.67 0,449.11 0,437.33V96c0,-11.78 9.55,-21.33 21.33,-21.33h469.33c11.78,0 21.34,9.55 21.34,21.33L512,437.33L512,437.33z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M512,416.01c0,11.78 -9.56,21.31 -21.34,21.31H21.33C9.55,437.33 0,427.8 0,416.01V74.67c0,-11.78 9.55,-21.34 21.33,-21.34h469.33c11.78,0 21.34,9.56 21.34,21.34L512,416.01L512,416.01z"
|
||||
android:fillColor="#ED5564"/>
|
||||
<path
|
||||
android:pathData="M63.99,160c-5.89,0 -10.66,4.78 -10.66,10.67v149.34c0,5.88 4.77,10.66 10.66,10.66c5.89,0 10.67,-4.78 10.67,-10.66V170.67C74.66,164.78 69.88,160 63.99,160z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M74.66,106.67c0,5.89 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.77 -10.66,-10.66S58.1,96 63.99,96C69.88,96 74.66,100.78 74.66,106.67z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M74.66,384.01c0,5.88 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.78 -10.66,-10.66c0,-5.91 4.77,-10.69 10.66,-10.69C69.88,373.33 74.66,378.11 74.66,384.01z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M448,123.73h-21.34v203.19l-40.31,50.41v0.02c-1.47,1.83 -2.34,4.14 -2.34,6.67c0,5.88 4.78,10.66 10.66,10.66c3.38,0 6.38,-1.56 8.33,-4h0.02l42.66,-53.34l0,0c1.47,-1.81 2.34,-4.13 2.34,-6.66V123.73z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,149.33c-11.77,0 -21.33,-9.56 -21.33,-21.33s9.56,-21.33 21.33,-21.33s21.33,9.56 21.33,21.33S449.09,149.33 437.33,149.33z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,96c-17.67,0 -32,14.33 -32,32s14.33,32 32,32s32,-14.33 32,-32S455,96 437.33,96zM437.33,138.67c-5.89,0 -10.67,-4.8 -10.67,-10.67c0,-5.88 4.78,-10.67 10.67,-10.67s10.67,4.8 10.67,10.67C448,133.88 443.22,138.67 437.33,138.67z"
|
||||
android:fillColor="#CCD1D9"/>
|
||||
<path
|
||||
android:pathData="M405.33,245.33c0,82.48 -66.86,149.34 -149.33,149.34c-82.47,0 -149.33,-66.86 -149.33,-149.34C106.66,162.86 173.52,96 255.99,96C338.47,96 405.33,162.86 405.33,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M266.66,149.33c0,-5.89 -4.77,-10.66 -10.67,-10.66c-58.91,0 -106.66,47.75 -106.66,106.65l0,0c0,5.89 4.77,10.67 10.66,10.67s10.67,-4.78 10.67,-10.67l0,0c0,-22.78 8.88,-44.22 24.99,-60.33c16.12,-16.13 37.55,-25 60.34,-25C261.89,160 266.66,155.22 266.66,149.33z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M352,234.67c-5.9,0 -10.67,4.77 -10.67,10.66l0,0c0,22.8 -8.88,44.23 -24.98,60.34c-16.13,16.13 -37.56,25 -60.35,25c-5.89,0 -10.66,4.78 -10.66,10.66c0,5.91 4.77,10.69 10.66,10.69c58.91,0 106.66,-47.77 106.66,-106.69C362.65,239.44 357.89,234.67 352,234.67z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M255.99,288.01c-23.52,0 -42.66,-19.16 -42.66,-42.69c0,-23.52 19.14,-42.66 42.66,-42.66c23.54,0 42.66,19.14 42.66,42.66C298.65,268.86 279.53,288.01 255.99,288.01z"
|
||||
android:fillColor="#FFCE54"/>
|
||||
<path
|
||||
android:pathData="M255.99,192c-29.45,0 -53.33,23.88 -53.33,53.33s23.88,53.34 53.33,53.34c29.46,0 53.34,-23.89 53.34,-53.34S285.45,192 255.99,192zM255.99,277.34c-17.64,0 -32,-14.36 -32,-32.02c0,-17.64 14.36,-32 32,-32c17.65,0 32.01,14.36 32.01,32C288,262.98 273.64,277.34 255.99,277.34z"
|
||||
android:fillColor="#F6BB42"/>
|
||||
<path
|
||||
android:pathData="M266.66,245.33c0,5.89 -4.77,10.67 -10.67,10.67c-5.89,0 -10.66,-4.78 -10.66,-10.67s4.77,-10.66 10.66,-10.66C261.89,234.67 266.66,239.44 266.66,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M74.66,234.67H53.33c-5.89,0 -10.66,4.77 -10.66,10.66s4.77,10.67 10.66,10.67h21.34c5.89,0 10.66,-4.78 10.66,-10.67S80.56,234.67 74.66,234.67z"
|
||||
android:fillColor="#434A54"/>
|
||||
</group>
|
||||
</vector>
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<group
|
||||
android:scaleX="0.13"
|
||||
android:scaleY="0.13"
|
||||
android:translateX="21.5"
|
||||
android:translateY="21.5">
|
||||
<path
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FFEC4A4A" />
|
||||
<item android:offset="1.0" android:color="#FFEC4A4A" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,52 +1,77 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
android:viewportHeight="522">
|
||||
<group
|
||||
android:scaleX="1.0"
|
||||
android:scaleY="1.0"
|
||||
android:translateX="14.0"
|
||||
android:translateY="14.0">
|
||||
|
||||
<path
|
||||
android:pathData="M512,437.33c0,11.78 -9.56,21.34 -21.34,21.34H21.33C9.55,458.67 0,449.11 0,437.33V96c0,-11.78 9.55,-21.33 21.33,-21.33h469.33c11.78,0 21.34,9.55 21.34,21.33L512,437.33L512,437.33z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M512,416.01c0,11.78 -9.56,21.31 -21.34,21.31H21.33C9.55,437.33 0,427.8 0,416.01V74.67c0,-11.78 9.55,-21.34 21.33,-21.34h469.33c11.78,0 21.34,9.56 21.34,21.34L512,416.01L512,416.01z"
|
||||
android:fillColor="#ED5564"/>
|
||||
<path
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FFEC4A4A" />
|
||||
<item android:offset="1.0" android:color="#FFEC4A4A" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path android:pathData="M63.99,160c-5.89,0 -10.66,4.78 -10.66,10.67v149.34c0,5.88 4.77,10.66 10.66,10.66c5.89,0 10.67,-4.78 10.67,-10.66V170.67C74.66,164.78 69.88,160 63.99,160z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M74.66,106.67c0,5.89 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.77 -10.66,-10.66S58.1,96 63.99,96C69.88,96 74.66,100.78 74.66,106.67z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M74.66,384.01c0,5.88 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.78 -10.66,-10.66c0,-5.91 4.77,-10.69 10.66,-10.69C69.88,373.33 74.66,378.11 74.66,384.01z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M448,123.73h-21.34v203.19l-40.31,50.41v0.02c-1.47,1.83 -2.34,4.14 -2.34,6.67c0,5.88 4.78,10.66 10.66,10.66c3.38,0 6.38,-1.56 8.33,-4h0.02l42.66,-53.34l0,0c1.47,-1.81 2.34,-4.13 2.34,-6.66V123.73z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,149.33c-11.77,0 -21.33,-9.56 -21.33,-21.33s9.56,-21.33 21.33,-21.33s21.33,9.56 21.33,21.33S449.09,149.33 437.33,149.33z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,96c-17.67,0 -32,14.33 -32,32s14.33,32 32,32s32,-14.33 32,-32S455,96 437.33,96zM437.33,138.67c-5.89,0 -10.67,-4.8 -10.67,-10.67c0,-5.88 4.78,-10.67 10.67,-10.67s10.67,4.8 10.67,10.67C448,133.88 443.22,138.67 437.33,138.67z"
|
||||
android:fillColor="#CCD1D9"/>
|
||||
<path
|
||||
android:pathData="M405.33,245.33c0,82.48 -66.86,149.34 -149.33,149.34c-82.47,0 -149.33,-66.86 -149.33,-149.34C106.66,162.86 173.52,96 255.99,96C338.47,96 405.33,162.86 405.33,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M266.66,149.33c0,-5.89 -4.77,-10.66 -10.67,-10.66c-58.91,0 -106.66,47.75 -106.66,106.65l0,0c0,5.89 4.77,10.67 10.67,10.67s10.67,-4.78 10.67,-10.67l0,0c0,-22.78 8.88,-44.22 24.99,-60.33c16.12,-16.13 37.55,-25 60.34,-25C261.89,160 266.66,155.22 266.66,149.33z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M352,234.67c-5.9,0 -10.67,4.77 -10.67,10.66l0,0c0,22.8 -8.88,44.23 -24.98,60.34c-16.13,16.13 -37.56,25 -60.35,25c-5.89,0 -10.66,4.78 -10.66,10.66c0,5.91 4.77,10.69 10.66,10.69c58.91,0 106.66,-47.77 106.66,-106.69C362.65,239.44 357.89,234.67 352,234.67z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M255.99,288.01c-23.52,0 -42.66,-19.16 -42.66,-42.69c0,-23.52 19.14,-42.66 42.66,-42.66c23.54,0 42.66,19.14 42.66,42.66C298.65,268.86 279.53,288.01 255.99,288.01z"
|
||||
android:fillColor="#FFCE54"/>
|
||||
<path
|
||||
android:pathData="M255.99,192c-29.45,0 -53.33,23.88 -53.33,53.33s23.88,53.34 53.33,53.34c29.46,0 53.34,-23.89 53.34,-53.34S285.45,192 255.99,192zM255.99,277.34c-17.64,0 -32,-14.36 -32,-32.02c0,-17.64 14.36,-32 32,-32c17.65,0 32.01,14.36 32.01,32C288,262.98 273.64,277.34 255.99,277.34z"
|
||||
android:fillColor="#F6BB42"/>
|
||||
<path
|
||||
android:pathData="M266.66,245.33c0,5.89 -4.77,10.67 -10.67,10.67c-5.89,0 -10.66,-4.78 -10.66,-10.67s4.77,-10.66 10.66,-10.66C261.89,234.67 266.66,239.44 266.66,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M74.66,234.67H53.33c-5.89,0 -10.66,4.77 -10.66,10.66s4.77,10.67 10.66,10.67h21.34c5.89,0 10.66,-4.78 10.66,-10.67S80.56,234.67 74.66,234.67z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,51 +1,78 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="800dp"
|
||||
android:height="800dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M512,437.33c0,11.78 -9.56,21.34 -21.34,21.34H21.33C9.55,458.67 0,449.11 0,437.33V96c0,-11.78 9.55,-21.33 21.33,-21.33h469.33c11.78,0 21.34,9.55 21.34,21.33L512,437.33L512,437.33z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M512,416.01c0,11.78 -9.56,21.31 -21.34,21.31H21.33C9.55,437.33 0,427.8 0,416.01V74.67c0,-11.78 9.55,-21.34 21.33,-21.34h469.33c11.78,0 21.34,9.56 21.34,21.34L512,416.01L512,416.01z"
|
||||
android:fillColor="#ED5564"/>
|
||||
<path
|
||||
android:pathData="M63.99,160c-5.89,0 -10.66,4.78 -10.66,10.67v149.34c0,5.88 4.77,10.66 10.66,10.66c5.89,0 10.67,-4.78 10.67,-10.66V170.67C74.66,164.78 69.88,160 63.99,160z"
|
||||
android:fillColor="#DA4453"/>
|
||||
<path
|
||||
android:pathData="M74.66,106.67c0,5.89 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.77 -10.66,-10.66S58.1,96 63.99,96C69.88,96 74.66,100.78 74.66,106.67z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M74.66,384.01c0,5.88 -4.78,10.66 -10.67,10.66c-5.89,0 -10.66,-4.78 -10.66,-10.66c0,-5.91 4.77,-10.69 10.66,-10.69C69.88,373.33 74.66,378.11 74.66,384.01z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M448,123.73h-21.34v203.19l-40.31,50.41v0.02c-1.47,1.83 -2.34,4.14 -2.34,6.67c0,5.88 4.78,10.66 10.66,10.66c3.38,0 6.38,-1.56 8.33,-4h0.02l42.66,-53.34l0,0c1.47,-1.81 2.34,-4.13 2.34,-6.66V123.73z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,149.33c-11.77,0 -21.33,-9.56 -21.33,-21.33s9.56,-21.33 21.33,-21.33s21.33,9.56 21.33,21.33S449.09,149.33 437.33,149.33z"
|
||||
android:fillColor="#E6E9ED"/>
|
||||
<path
|
||||
android:pathData="M437.33,96c-17.67,0 -32,14.33 -32,32s14.33,32 32,32s32,-14.33 32,-32S455,96 437.33,96zM437.33,138.67c-5.89,0 -10.67,-4.8 -10.67,-10.67c0,-5.88 4.78,-10.67 10.67,-10.67s10.67,4.8 10.67,10.67C448,133.88 443.22,138.67 437.33,138.67z"
|
||||
android:fillColor="#CCD1D9"/>
|
||||
<path
|
||||
android:pathData="M405.33,245.33c0,82.48 -66.86,149.34 -149.33,149.34c-82.47,0 -149.33,-66.86 -149.33,-149.34C106.66,162.86 173.52,96 255.99,96C338.47,96 405.33,162.86 405.33,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M266.66,149.33c0,-5.89 -4.77,-10.66 -10.67,-10.66c-58.91,0 -106.66,47.75 -106.66,106.65l0,0c0,5.89 4.77,10.67 10.66,10.67s10.67,-4.78 10.67,-10.67l0,0c0,-22.78 8.88,-44.22 24.99,-60.33c16.12,-16.13 37.55,-25 60.34,-25C261.89,160 266.66,155.22 266.66,149.33z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M352,234.67c-5.9,0 -10.67,4.77 -10.67,10.66l0,0c0,22.8 -8.88,44.23 -24.98,60.34c-16.13,16.13 -37.56,25 -60.35,25c-5.89,0 -10.66,4.78 -10.66,10.66c0,5.91 4.77,10.69 10.66,10.69c58.91,0 106.66,-47.77 106.66,-106.69C362.65,239.44 357.89,234.67 352,234.67z"
|
||||
android:fillColor="#656D78"/>
|
||||
<path
|
||||
android:pathData="M255.99,288.01c-23.52,0 -42.66,-19.16 -42.66,-42.69c0,-23.52 19.14,-42.66 42.66,-42.66c23.54,0 42.66,19.14 42.66,42.66C298.65,268.86 279.53,288.01 255.99,288.01z"
|
||||
android:fillColor="#FFCE54"/>
|
||||
<path
|
||||
android:pathData="M255.99,192c-29.45,0 -53.33,23.88 -53.33,53.33s23.88,53.34 53.33,53.34c29.46,0 53.34,-23.89 53.34,-53.34S285.45,192 255.99,192zM255.99,277.34c-17.64,0 -32,-14.36 -32,-32.02c0,-17.64 14.36,-32 32,-32c17.65,0 32.01,14.36 32.01,32C288,262.98 273.64,277.34 255.99,277.34z"
|
||||
android:fillColor="#F6BB42"/>
|
||||
<path
|
||||
android:pathData="M266.66,245.33c0,5.89 -4.77,10.67 -10.67,10.67c-5.89,0 -10.66,-4.78 -10.66,-10.67s4.77,-10.66 10.66,-10.66C261.89,234.67 266.66,239.44 266.66,245.33z"
|
||||
android:fillColor="#434A54"/>
|
||||
<path
|
||||
android:pathData="M74.66,234.67H53.33c-5.89,0 -10.66,4.77 -10.66,10.66s4.77,10.67 10.66,10.67h21.34c5.89,0 10.66,-4.78 10.66,-10.67S80.56,234.67 74.66,234.67z"
|
||||
android:fillColor="#434A54"/>
|
||||
</vector>
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<group
|
||||
android:scaleX="0.16"
|
||||
android:scaleY="0.16"
|
||||
android:translateX="14.0"
|
||||
android:translateY="14.0">
|
||||
|
||||
<path
|
||||
android:pathData="M250,0c138.07,0 250,111.93 250,250S388.07,500 250,500 0,388.07 0,250 111.93,0 250,0ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="122.34"
|
||||
android:startY="23.55"
|
||||
android:endX="377.69"
|
||||
android:endY="465.83"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#FFEC4A4A" />
|
||||
<item android:offset="1.0" android:color="#FFEC4A4A" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M250.41,20.5c126.89,0 229.75,102.86 229.75,229.75c0,126.89 -102.86,229.75 -229.75,229.75c-126.89,0 -229.75,-102.86 -229.75,-229.75C20.66,123.36 123.53,20.5 250.41,20.5ZM250.85,161.82c-49.09,0 -88.88,39.79 -88.88,88.88c0,49.09 39.79,88.88 88.88,88.88c49.09,0 88.88,-39.79 88.88,-88.88c0,-49.09 -39.79,-88.88 -88.88,-88.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="116.21"
|
||||
android:startY="67.61"
|
||||
android:endX="403.29"
|
||||
android:endY="429.34"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#66060606" />
|
||||
<item android:offset="1.0" android:color="#CC060606" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M453.23,307.8c-18.5,72.24 -73.8,129.26 -144.2,148.92l-36.39,-138.74c21.97,-7.21 39.22,-24.84 45.88,-47.06l134.71,36.88Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:pathData="M228.3,183.04c-21.73,7.15 -38.82,24.5 -45.62,46.39L47.5,192.42c18.5,-72.24 73.8,-129.26 144.2,-148.92l36.6,139.54Z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startX="420.63"
|
||||
android:startY="403.74"
|
||||
android:endX="78.4"
|
||||
android:endY="117.92"
|
||||
android:type="linear">
|
||||
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
||||
<path
|
||||
android:fillColor="#66FFFFFF"
|
||||
android:pathData="M250.5,179.5c39.21,0 71,31.79 71,71s-31.79,71 -71,71s-71,-31.79 -71,-71s31.79,-71 71,-71ZM250,235c-8.28,0 -15,6.72 -15,15c0,8.28 6.72,15 15,15c8.28,0 15,-6.72 15,-15c0,-8.28 -6.72,-15 -15,-15Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -47,6 +47,19 @@
|
||||
app:behavior_hideable="true"
|
||||
app:behavior_peekHeight="@dimen/bottom_sheet_peek_height"
|
||||
app:layout_behavior="@string/bottom_sheet_behavior" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/offline_mode_text_view"
|
||||
style="@style/NoConnectionTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="top"
|
||||
android:padding="2dp"
|
||||
android:text="@string/activity_info_offline_mode"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
@@ -57,13 +70,4 @@
|
||||
app:menu="@menu/nav_drawer"
|
||||
app:headerLayout="@layout/nav_drawer_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/offline_mode_text_view"
|
||||
style="@style/NoConnectionTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/activity_info_offline_mode"
|
||||
android:textSize="6sp"
|
||||
android:visibility="gone" />
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
@@ -37,6 +36,17 @@
|
||||
android:paddingEnd="24dp"
|
||||
app:menu="@menu/bottom_nav_menu" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/offline_mode_text_view"
|
||||
style="@style/NoConnectionTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="top"
|
||||
android:padding="2dp"
|
||||
android:text="@string/activity_info_offline_mode"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -60,13 +70,4 @@
|
||||
app:menu="@menu/nav_drawer"
|
||||
app:headerLayout="@layout/nav_drawer_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/offline_mode_text_view"
|
||||
style="@style/NoConnectionTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/activity_info_offline_mode"
|
||||
android:textSize="6sp"
|
||||
android:visibility="gone" />
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
@@ -200,4 +200,4 @@
|
||||
android:text="@string/album_bottom_sheet_share"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -92,4 +92,4 @@
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/artist_bottom_sheet_shuffle" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
130
app/src/main/res/layout/bottom_sheet_playlist_dialog.xml
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:clipChildren="false">
|
||||
|
||||
<!-- Header -->
|
||||
<ImageView
|
||||
android:id="@+id/playlist_cover_image_view"
|
||||
android:layout_width="54dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_margin="2dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ToggleButton
|
||||
android:id="@+id/button_favorite"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="@drawable/button_favorite_selector"
|
||||
android:checked="false"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:gravity="center_vertical"
|
||||
android:text=""
|
||||
android:textOff=""
|
||||
android:textOn=""
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playlist_title_text_view"
|
||||
style="@style/LabelMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ellipsize="marquee"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:singleLine="true"
|
||||
android:text="@string/label_placeholder"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_favorite"
|
||||
app:layout_constraintStart_toEndOf="@+id/playlist_cover_image_view"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playlist_count_text_view"
|
||||
style="@style/LabelSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:text="@string/label_placeholder"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_favorite"
|
||||
app:layout_constraintStart_toEndOf="@+id/playlist_cover_image_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/playlist_title_text_view" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/song_asset_link_row"
|
||||
layout="@layout/view_asset_link_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="12dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/option_linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/play_next_text_view"
|
||||
style="@style/LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/song_bottom_sheet_play_next" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_to_queue_text_view"
|
||||
style="@style/LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/song_bottom_sheet_add_to_queue" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/share_text_view"
|
||||
style="@style/LabelMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/song_bottom_sheet_share"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -108,6 +108,22 @@
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/allSongs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:text="@string/search_all_songs_loading"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/allsongsview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
@@ -146,4 +162,4 @@
|
||||
android:orientation="vertical"/>
|
||||
</ScrollView>
|
||||
</com.google.android.material.search.SearchView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingBottom="@dimen/global_padding_bottom" />
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/settings_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorSurface"
|
||||
app:layout_collapseMode="pin"
|
||||
app:navigationIcon="@drawable/ic_arrow_back" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/settings_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -225,4 +225,4 @@
|
||||
android:background="@drawable/ic_more_vert"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless" />
|
||||
</FrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
@@ -329,6 +329,11 @@
|
||||
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.SongBottomSheetDialog"
|
||||
android:label="SongBottomSheetDialog"
|
||||
tools:layout="@layout/bottom_sheet_song_dialog" />
|
||||
<dialog
|
||||
android:id="@+id/playlistBottomSheetDialog"
|
||||
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.PlaylistBottomSheetDialog"
|
||||
android:label="PlaylistBottomSheetDialog"
|
||||
tools:layout="@layout/bottom_sheet_playlist_dialog" />
|
||||
<dialog
|
||||
android:id="@+id/artistBottomSheetDialog"
|
||||
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.ArtistBottomSheetDialog"
|
||||
|
||||
@@ -288,6 +288,7 @@
|
||||
<item>Albums favoris</item>
|
||||
<item>Artistes favoris</item>
|
||||
<item>Aléatoire</item>
|
||||
<item>Genres</item>
|
||||
</string-array>
|
||||
<string-array name="aa_tab_values">
|
||||
<item>-1</item>
|
||||
@@ -307,6 +308,7 @@
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
</string-array>
|
||||
<!-- end Add by MFO -->
|
||||
|
||||
|
||||
@@ -338,6 +338,8 @@
|
||||
<string name="settings_androidauto_second_tab">Affichage du deuxième onglet</string>
|
||||
<string name="settings_androidauto_third_tab">Affichage du troisième onglet</string>
|
||||
<string name="settings_androidauto_fourth_tab">Affichage du quatrième onglet</string>
|
||||
<string name="settings_androidauto_shuffle_genre_songs">Mélanger les chansons par genre</string>
|
||||
<string name="settings_androidauto_shuffle_genre_songs_summary">Lire des chansons aléatoires lors de la sélection d\'un genre</string>
|
||||
<string name="settings_audio_transcode_download_format">Format de transcodage</string>
|
||||
<string name="settings_audio_transcode_download_priority_summary">Si activé, Tempus ne forcera pas le téléchargement de la piste avec les paramètres de transcodage ci-dessous.</string>
|
||||
<string name="settings_audio_transcode_download_priority_title">Prioriser les paramètres du serveurs, utilisés pour le streaming, dans les téléchargements</string>
|
||||
|
||||
@@ -277,4 +277,57 @@
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="tile_size_titles">
|
||||
<item>Bardzo mały</item>
|
||||
<item>Mały</item>
|
||||
<item>Średni</item>
|
||||
<item>Duży</item>
|
||||
<item>Domyślny</item>
|
||||
</string-array>
|
||||
<string-array name="tile_size_divisor">
|
||||
<item>6</item>
|
||||
<item>5</item>
|
||||
<item>4</item>
|
||||
<item>3</item>
|
||||
<item>2</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="aa_tab_titles">
|
||||
<item>Nie wyświetlaj</item>
|
||||
<item>Strona główna</item>
|
||||
<item>Ostatnie</item>
|
||||
<item>Albumy</item>
|
||||
<item>Wykonawcy</item>
|
||||
<item>Playlisty</item>
|
||||
<item>Podcasty</item>
|
||||
<item>Radio</item>
|
||||
<item>Foldery</item>
|
||||
<item>Najczęściej odtwarzane albumy</item>
|
||||
<item>Dodane albumy</item>
|
||||
<item>Utwory oznaczone gwiazdką</item>
|
||||
<item>Albumy oznaczone gwiazdką</item>
|
||||
<item>Wykonawcy oznaczeni gwiazdką</item>
|
||||
<item>Losowe</item>
|
||||
</string-array>
|
||||
<string-array name="aa_tab_values">
|
||||
<item>-1</item>
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,21 @@
|
||||
<resources>
|
||||
<string name="aa_albums">Albumy</string>
|
||||
<string name="aa_album_most_played">Najczęściej odtwarzane albumy</string>
|
||||
<string name="aa_album_recently_added">Dodane albumy</string>
|
||||
<string name="aa_artists">Wykonawcy</string>
|
||||
<string name="aa_home">Strona główna</string>
|
||||
<string name="aa_made_for_you">Dla ciebie</string>
|
||||
<string name="aa_more">Więcej</string>
|
||||
<string name="aa_music_folder">Foldery</string>
|
||||
<string name="aa_playlists">Playlisty</string>
|
||||
<string name="aa_podcast">Podcasty</string>
|
||||
<string name="aa_radio">Radio</string>
|
||||
<string name="aa_random">Losowe</string>
|
||||
<string name="aa_recent_albums">Ostatnie</string>
|
||||
<string name="aa_song_recently_played">Odtwarzane piosenki</string>
|
||||
<string name="aa_starred_albums">★ Albumy</string>
|
||||
<string name="aa_starred_artists">★ Wykonawcy</string>
|
||||
<string name="aa_starred_tracks">★ Utwory</string>
|
||||
<string name="activity_battery_optimizations_conclusion">Jeżeli masz problemy odwiedź stronę https://dontkillmyapp.com. Podaje ona dokładne instrukcje na temat tego jak wyłączyć funkcje oszczędzania energii które mogą wpływać na wydajność aplikacji.</string>
|
||||
<string name="activity_battery_optimizations_summary">Wyłącz optymalizacje baterii aby odtwarzać media przy wyłączonym ekranie.</string>
|
||||
<string name="activity_battery_optimizations_title">Optymalizcje Baterii</string>
|
||||
@@ -362,6 +379,16 @@
|
||||
<string name="settings_podcast">Pokazuj podcasty</string>
|
||||
<string name="settings_podcast_summary">Jeżeli włączone, widoczna będzie sekcja z podcastami. Zrestartuj aplikację aby, zmiany przyniosły pełny efekt.</string>
|
||||
<string name="settings_playlist_sort">Sortowanie playlist</string>
|
||||
<string name="settings_androidauto">Android Auto</string>
|
||||
<string name="settings_androidauto_album_view">Układ siatki dla albumów</string>
|
||||
<string name="settings_androidauto_home_view">Układ siatki dla strony głównej</string>
|
||||
<string name="settings_androidauto_playlist_view">Układ siatki dla playlist</string>
|
||||
<string name="settings_androidauto_podcast_view">Układ siatki dla podcastów</string>
|
||||
<string name="settings_androidauto_radio_view">Układ siatki dla radia</string>
|
||||
<string name="settings_androidauto_first_tab">Pierwsza zakładka</string>
|
||||
<string name="settings_androidauto_second_tab">Druga zakładka</string>
|
||||
<string name="settings_androidauto_third_tab">Trzecia zakładka</string>
|
||||
<string name="settings_androidauto_fourth_tab">Czwarta zakładka</string>
|
||||
<string name="settings_audio_quality">Pokaż jakość audio</string>
|
||||
<string name="settings_audio_quality_summary">Bitrate i format audio będzie pokazywany dla każdego utworu.</string>
|
||||
<string name="settings_song_rating">Pokaż ocenę piosenek w gwiazdkach</string>
|
||||
@@ -410,6 +437,7 @@
|
||||
<string name="settings_sync_starred_tracks_for_offline_use_summary">Jeżeli włączone, utwory oznaczone gwiazdką będą pobrane do użycia offline.</string>
|
||||
<string name="settings_sync_starred_tracks_for_offline_use_title">Zsynchronizuj utwory oznaczone gwiazdką do użycia offline</string>
|
||||
<string name="settings_theme">Motyw</string>
|
||||
<string name="settings_tile_size">Rozmiar kafelków</string>
|
||||
<string name="settings_title_data">Dane</string>
|
||||
<string name="settings_title_general">Ogólne</string>
|
||||
<string name="settings_title_playlist">Playlisty</string>
|
||||
|
||||
@@ -297,6 +297,7 @@
|
||||
<item>Избранные альбомы</item>
|
||||
<item>Избранные артисты</item>
|
||||
<item>Случайное</item>
|
||||
<item>Жанры</item>
|
||||
</string-array>
|
||||
<string-array name="aa_tab_values">
|
||||
<item>-1</item>
|
||||
@@ -316,6 +317,7 @@
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
</string-array>
|
||||
<!-- end Add by MFO -->
|
||||
|
||||
|
||||
@@ -402,6 +402,8 @@
|
||||
<string name="settings_androidauto_second_tab">Second tab display</string>
|
||||
<string name="settings_androidauto_third_tab">Third tab display</string>
|
||||
<string name="settings_androidauto_fourth_tab">Fourth tab display</string>
|
||||
<string name="settings_androidauto_shuffle_genre_songs">Перемешивать треки по жанру</string>
|
||||
<string name="settings_androidauto_shuffle_genre_songs_summary">Воспроизводить случайные треки при выборе жанра</string>
|
||||
<string name="settings_audio_quality">Показывать качество аудио</string>
|
||||
<string name="settings_audio_quality_summary">Битрейт и формат аудио будут отображаться для каждого трека.</string>
|
||||
<string name="settings_song_rating">Показывать рейтинг трека</string>
|
||||
|
||||
@@ -310,8 +310,9 @@
|
||||
<!-- <item>For you</item> -->
|
||||
<item>Star tracks</item>
|
||||
<item>Star albums</item>
|
||||
<item>Star artistes</item>
|
||||
<item>Star artists</item>
|
||||
<item>Random</item>
|
||||
<item>Genres</item>
|
||||
</string-array>
|
||||
<string-array name="aa_tab_values">
|
||||
<item>-1</item>
|
||||
@@ -331,6 +332,7 @@
|
||||
<item>13</item>
|
||||
<item>14</item>
|
||||
<item>15</item>
|
||||
<item>16</item>
|
||||
</string-array>
|
||||
<!-- end Add by MFO -->
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#626A75</color>
|
||||
</resources>
|
||||
@@ -11,6 +11,7 @@
|
||||
<string name="aa_podcast">Podcast</string>
|
||||
<string name="aa_radio">Radio</string>
|
||||
<string name="aa_random">Random</string>
|
||||
<string name="aa_genres">Genres</string>
|
||||
<string name="aa_recent_albums">Recent</string>
|
||||
<string name="aa_song_recently_played">Song played</string>
|
||||
<string name="aa_starred_albums">★ Albums</string>
|
||||
@@ -402,6 +403,8 @@
|
||||
<string name="settings_androidauto_second_tab">Second tab display</string>
|
||||
<string name="settings_androidauto_third_tab">Third tab display</string>
|
||||
<string name="settings_androidauto_fourth_tab">Fourth tab display</string>
|
||||
<string name="settings_androidauto_shuffle_genre_songs">Shuffle genre songs</string>
|
||||
<string name="settings_androidauto_shuffle_genre_songs_summary">Play random songs when selecting a genre</string>
|
||||
<string name="settings_audio_quality">Show audio quality</string>
|
||||
<string name="settings_audio_quality_summary">The bitrate and audio format will be shown for each audio track.</string>
|
||||
<string name="settings_song_rating">Show song star rating</string>
|
||||
@@ -415,8 +418,8 @@
|
||||
<string name="settings_show_mini_shuffle_button_summary">If enabled, show the shuffle button, remove the heart in the mini player</string>
|
||||
<string name="settings_radio">Show radio</string>
|
||||
<string name="settings_radio_summary">If enabled, show the radio section. Restart the app for it to take full effect.</string>
|
||||
<string name="settings_enable_drawer_on_landscape">Enable drawer on portrait [Experimental]</string>
|
||||
<string name="settings_enable_drawer_on_landscape_summary">Unlocks the lateral landscape menu drawer on portrait. The changes will take effect on restart.</string>
|
||||
<string name="settings_enable_drawer_on_landscape">Enable drawer on portrait</string>
|
||||
<string name="settings_enable_drawer_on_landscape_summary">Unlocks the lateral landscape menu drawer on portrait.</string>
|
||||
<string name="settings_hide_bottom_navbar_on_portrait">Hide bottom navbar on portrait [Experimental]</string>
|
||||
<string name="settings_hide_bottom_navbar_on_portrait_summary">Experimental.Increases vertical space by removing the bottom navbar. The changes will take effect on restart.</string>
|
||||
<string name="settings_auto_download_lyrics">Auto download lyrics</string>
|
||||
@@ -604,4 +607,7 @@
|
||||
|
||||
<string name="search_sort_title">Sort recent searches chronologically</string>
|
||||
<string name="search_sort_summary">If enabled, sort searches chronologically. Sort by name if disabled.</string>
|
||||
<string name="search_all_songs_loading">Getting all songs ...</string>
|
||||
<string name="search_all_songs">all %1$s songs</string>
|
||||
<string name="search_all_songs_play">Play %1$s</string>
|
||||
</resources>
|
||||
|
||||
@@ -519,7 +519,12 @@
|
||||
app:entryValues="@array/aa_tab_values"
|
||||
app:key="androidauto_fourth_tab"
|
||||
app:title="@string/settings_androidauto_fourth_tab"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_androidauto_shuffle_genre_songs"
|
||||
android:defaultValue="false"
|
||||
android:key="androidauto_shuffle_genre_songs" />
|
||||
|
||||
</PreferenceCategory>
|
||||
<!-- end Add by MFO -->
|
||||
|
||||
@@ -50,6 +50,7 @@ object MediaBrowserTree {
|
||||
private const val STARRED_ARTISTS_ID = "[starredArtistsID]"
|
||||
private const val RANDOM_ID = "[randomID]"
|
||||
private const val FOLDER_ID = "[folderID]"
|
||||
private const val GENRES_ID = "[genresID]"
|
||||
|
||||
// System functions
|
||||
private const val INDEX_ID = "[indexID]"
|
||||
@@ -178,7 +179,8 @@ object MediaBrowserTree {
|
||||
STARRED_TRACKS_ID,
|
||||
STARRED_ALBUMS_ID,
|
||||
STARRED_ARTISTS_ID,
|
||||
RANDOM_ID
|
||||
RANDOM_ID,
|
||||
GENRES_ID
|
||||
)
|
||||
|
||||
// Root level
|
||||
@@ -419,6 +421,19 @@ object MediaBrowserTree {
|
||||
)
|
||||
)
|
||||
|
||||
treeNodes[GENRES_ID] =
|
||||
MediaItemNode(
|
||||
buildMediaItem(
|
||||
gridView = albumView,
|
||||
title = appContext.getString(R.string.aa_genres),
|
||||
mediaId = GENRES_ID,
|
||||
isPlayable = false,
|
||||
isBrowsable = true,
|
||||
imageUri = iconUri(R.drawable.ic_aa_genres),
|
||||
mediaType = MediaMetadata.MEDIA_TYPE_FOLDER_MIXED
|
||||
)
|
||||
)
|
||||
|
||||
val root = treeNodes[ROOT_ID]!!
|
||||
val selectedIds = mutableSetOf<String>()
|
||||
|
||||
@@ -474,6 +489,7 @@ object MediaBrowserTree {
|
||||
STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id)
|
||||
STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id)
|
||||
RANDOM_ID -> automotiveRepository.getRandomSongs(100)
|
||||
GENRES_ID -> automotiveRepository.getGenres(id)
|
||||
|
||||
else -> {
|
||||
if (id.startsWith(LAST_PLAYED_ID)) {
|
||||
@@ -512,6 +528,13 @@ object MediaBrowserTree {
|
||||
return automotiveRepository.getArtistAlbum(STARRED_ALBUMS_ID,id.removePrefix(STARRED_ARTISTS_ID))
|
||||
}
|
||||
|
||||
if (id.startsWith(GENRES_ID)) {
|
||||
val shuffle = Preferences.isAndroidAutoShuffleGenreSongsEnabled()
|
||||
// If the user doesn't want random songs, it's likely it's for perusing them, so provide as many as possible
|
||||
val count = if (shuffle) 100 else 500
|
||||
return automotiveRepository.getSongsByGenre(id.removePrefix(GENRES_ID), count, shuffle)
|
||||
}
|
||||
|
||||
if (id.startsWith(PLAYLIST_ID)) {
|
||||
return automotiveRepository.getPlaylistSongs(id.removePrefix(PLAYLIST_ID))
|
||||
}
|
||||
|
||||
10
fastlane/metadata/android/en-US/changelogs/24.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
* chore(i18n): Improve Russian translation
|
||||
* feat: tile size manager
|
||||
* chore(i18n): Translated to zh_TW
|
||||
* fix: Show full album name when displaying details
|
||||
* chore(i18n): Update Spanish translation
|
||||
* fix: Relocate "Offline mode" text
|
||||
* chore(i18n): Update Polish translation
|
||||
* refactor: navigation and bottom sheet
|
||||
* feat: new Logo icon/adaptive icon update/refresh
|
||||
* feat: Added all-songs feature
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 327 KiB |
BIN
mockup/1_dark_tempus.png
Normal file
|
After Width: | Height: | Size: 195 KiB |
BIN
mockup/1_light_tempus.png
Normal file
|
After Width: | Height: | Size: 196 KiB |
BIN
mockup/2_dark_tempus.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
mockup/2_light_tempus.png
Normal file
|
After Width: | Height: | Size: 157 KiB |
BIN
mockup/3_dark_tempus.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
mockup/3_light_tempus.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
mockup/svg/tempus-horizontal-banner.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 34 KiB |