Compare commits
47 Commits
main
...
bleeding-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20cb7b8cad | ||
|
|
f32359a369 | ||
|
|
23a68011e2 | ||
|
|
07ced3308f | ||
|
|
ed9ebfc84b | ||
|
|
cc21e05957 | ||
|
|
acb8e54893 | ||
|
|
6dca81b937 | ||
|
|
ecaf61d31d | ||
|
|
a2a2fad444 | ||
|
|
022e3bf61b | ||
|
|
2aa4ccde91 | ||
|
|
1ef7ef7377 | ||
|
|
7151fda9c2 | ||
|
|
0b61653dcc | ||
|
|
5fc15c7173 | ||
|
|
7661d7aa4d | ||
|
|
84b690b765 | ||
|
|
17bf90827b | ||
|
|
76f434604f | ||
|
|
89e1b49ea2 | ||
|
|
b53d031701 | ||
|
|
3f16eca404 | ||
|
|
525608320e | ||
|
|
fe324b6f9b | ||
|
|
bca2b6ccab | ||
|
|
7fb08dc470 | ||
|
|
d856b325e9 | ||
|
|
5007d89b1c | ||
|
|
0a77afae14 | ||
|
|
91506a308d | ||
|
|
dba4e4b428 | ||
|
|
0b23d4355e | ||
|
|
4803ce676a | ||
|
|
ecec442e4b | ||
|
|
b38da77393 | ||
|
|
0268bb42c3 | ||
|
|
ae183122ac | ||
|
|
6ce1063639 | ||
|
|
d1851bcc5a | ||
|
|
2db9cb80d1 | ||
|
|
0b7d1e629b | ||
|
|
eeb125542d | ||
|
|
34d354d803 | ||
|
|
52cfd36b09 | ||
|
|
360929e772 | ||
|
|
82f9679da7 |
@@ -1,5 +1,5 @@
|
|||||||
<p align="center">
|
<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>
|
</p>
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -136,4 +136,4 @@ Tempus is released under the [GNU General Public License v3.0](LICENSE). Feel fr
|
|||||||
## Credits
|
## Credits
|
||||||
Thanks to the original repo/creator [CappielloAntonio](https://github.com/CappielloAntonio) (forked from v3.9.0)
|
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 albums
|
||||||
- Star artists
|
- Star artists
|
||||||
- Random : 100 random songs
|
- 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.
|
If all tabs are set to "Do not display", then "Home" tab will be created with all functions inside.
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ android {
|
|||||||
targetSdk 35
|
targetSdk 35
|
||||||
|
|
||||||
versionCode 23
|
versionCode 23
|
||||||
versionName '4.12.6'
|
versionName '4.13.0-DEV'
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
|
|
||||||
javaCompileOptions {
|
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"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="108dp"
|
android:width="108dp"
|
||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="512"
|
android:viewportWidth="108"
|
||||||
android:viewportHeight="512">
|
android:viewportHeight="108">
|
||||||
<group android:scaleX="0.49"
|
|
||||||
android:scaleY="0.49"
|
|
||||||
android:translateX="130.56"
|
|
||||||
android:translateY="130.56">
|
|
||||||
|
|
||||||
<path
|
<group
|
||||||
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:scaleX="0.13"
|
||||||
android:fillColor="#8CC152"/> <path
|
android:scaleY="0.13"
|
||||||
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:translateX="21.5"
|
||||||
android:fillColor="#62A43B"/> <path
|
android:translateY="21.5">
|
||||||
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
|
<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: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">
|
||||||
android:fillColor="#E6E9ED"/>
|
<aapt:attr name="android:fillColor">
|
||||||
<path
|
<gradient
|
||||||
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:startX="122.34"
|
||||||
android:fillColor="#E6E9ED"/>
|
android:startY="23.55"
|
||||||
<path
|
android:endX="377.69"
|
||||||
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:endY="465.83"
|
||||||
android:fillColor="#E6E9ED"/>
|
android:type="linear">
|
||||||
<path
|
<item android:offset="0.0" android:color="#FF36C12C" />
|
||||||
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"
|
<item android:offset="1.0" android:color="#FF36C12C" />
|
||||||
android:fillColor="#E6E9ED"/>
|
</gradient>
|
||||||
<path
|
</aapt:attr>
|
||||||
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"
|
</path>
|
||||||
android:fillColor="#CCD1D9"/>
|
|
||||||
<path
|
<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: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">
|
||||||
android:fillColor="#434A54"/>
|
<aapt:attr name="android:fillColor">
|
||||||
<path
|
<gradient
|
||||||
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:startX="116.21"
|
||||||
android:fillColor="#656D78"/>
|
android:startY="67.61"
|
||||||
<path
|
android:endX="403.29"
|
||||||
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:endY="429.34"
|
||||||
android:fillColor="#656D78"/>
|
android:type="linear">
|
||||||
<path
|
<item android:offset="0.0" android:color="#66060606" />
|
||||||
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"
|
<item android:offset="1.0" android:color="#CC060606" />
|
||||||
android:fillColor="#FFCE54"/>
|
</gradient>
|
||||||
<path
|
</aapt:attr>
|
||||||
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"
|
</path>
|
||||||
android:fillColor="#F6BB42"/>
|
|
||||||
<path
|
<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: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">
|
||||||
android:fillColor="#434A54"/>
|
<aapt:attr name="android:fillColor">
|
||||||
<path
|
<gradient
|
||||||
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:startX="420.63"
|
||||||
android:fillColor="#434A54"/>
|
android:startY="403.74"
|
||||||
</group>
|
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>
|
</vector>
|
||||||
@@ -1,53 +1,77 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="108dp"
|
android:width="108dp"
|
||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="512"
|
android:viewportWidth="108"
|
||||||
android:viewportHeight="512">
|
android:viewportHeight="108">
|
||||||
<group android:scaleX="0.55"
|
|
||||||
android:scaleY="0.55"
|
<group
|
||||||
android:translateX="150.56"
|
android:scaleX="0.13"
|
||||||
android:translateY="150.56">
|
android:scaleY="0.13"
|
||||||
|
android:translateX="21.5"
|
||||||
|
android:translateY="21.5">
|
||||||
<path
|
<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: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">
|
||||||
android:fillColor="#8CC152"/> <path
|
<aapt:attr name="android:fillColor">
|
||||||
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"
|
<gradient
|
||||||
android:fillColor="#62A43B"/> <path
|
android:startX="122.34"
|
||||||
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:startY="23.55"
|
||||||
android:fillColor="#8CC152"/> <path
|
android:endX="377.69"
|
||||||
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:endY="465.83"
|
||||||
android:fillColor="#E6E9ED"/>
|
android:type="linear">
|
||||||
|
<item android:offset="0.0" android:color="#FF36C12C" />
|
||||||
|
<item android:offset="1.0" android:color="#FF36C12C" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
|
||||||
<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: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">
|
||||||
android:fillColor="#E6E9ED"/>
|
<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
|
<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: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">
|
||||||
android:fillColor="#E6E9ED"/>
|
<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
|
<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: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">
|
||||||
android:fillColor="#E6E9ED"/>
|
<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
|
<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="#66FFFFFF"
|
||||||
android:fillColor="#CCD1D9"/>
|
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" />
|
||||||
<path
|
</group>
|
||||||
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>
|
|
||||||
</vector>
|
</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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<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"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||||
</adaptive-icon>
|
</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.MusicFolder;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
import com.cappielloantonio.tempo.subsonic.models.Playlist;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode;
|
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.DownloadUtil;
|
||||||
import com.cappielloantonio.tempo.util.MappingUtil;
|
import com.cappielloantonio.tempo.util.MappingUtil;
|
||||||
import com.cappielloantonio.tempo.util.MusicUtil;
|
import com.cappielloantonio.tempo.util.MusicUtil;
|
||||||
@@ -789,7 +790,7 @@ public class AutomotiveRepository {
|
|||||||
|
|
||||||
App.getSubsonicClientInstance(false)
|
App.getSubsonicClientInstance(false)
|
||||||
.getSearchingClient()
|
.getSearchingClient()
|
||||||
.search3(query, 20, 20, 20)
|
.search3(query, 20, 0, 20, 0, 20, 0)
|
||||||
.enqueue(new Callback<ApiResponse>() {
|
.enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||||
@@ -952,6 +953,116 @@ public class AutomotiveRepository {
|
|||||||
thread.start();
|
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 static class GetMediaItemThreadSafe implements Runnable {
|
||||||
private final SessionMediaItemDao sessionMediaItemDao;
|
private final SessionMediaItemDao sessionMediaItemDao;
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
package com.cappielloantonio.tempo.repository;
|
package com.cappielloantonio.tempo.repository;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
|
||||||
import com.cappielloantonio.tempo.App;
|
import com.cappielloantonio.tempo.App;
|
||||||
|
import com.cappielloantonio.tempo.R;
|
||||||
import com.cappielloantonio.tempo.database.AppDatabase;
|
import com.cappielloantonio.tempo.database.AppDatabase;
|
||||||
import com.cappielloantonio.tempo.database.dao.RecentSearchDao;
|
import com.cappielloantonio.tempo.database.dao.RecentSearchDao;
|
||||||
import com.cappielloantonio.tempo.model.RecentSearch;
|
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.AlbumID3;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
import com.cappielloantonio.tempo.subsonic.models.ArtistID3;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.Child;
|
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.SearchResult2;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.SearchResult3;
|
import com.cappielloantonio.tempo.subsonic.models.SearchResult3;
|
||||||
import com.cappielloantonio.tempo.util.Preferences;
|
import com.cappielloantonio.tempo.util.Preferences;
|
||||||
|
import com.cappielloantonio.tempo.ui.fragment.SearchFragment;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
@@ -31,7 +41,7 @@ public class SearchingRepository {
|
|||||||
|
|
||||||
App.getSubsonicClientInstance(false)
|
App.getSubsonicClientInstance(false)
|
||||||
.getSearchingClient()
|
.getSearchingClient()
|
||||||
.search3(query, 20, 20, 20)
|
.search3(query, 20, 0, 20, 0, 20, 0)
|
||||||
.enqueue(new Callback<ApiResponse>() {
|
.enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||||
@@ -49,12 +59,63 @@ public class SearchingRepository {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableLiveData<SearchResult3> search3(String query) {
|
@UnstableApi
|
||||||
|
public MutableLiveData<SearchResult3> search3(SearchFragment sf, String query) {
|
||||||
MutableLiveData<SearchResult3> result = new MutableLiveData<>();
|
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)
|
App.getSubsonicClientInstance(false)
|
||||||
.getSearchingClient()
|
.getSearchingClient()
|
||||||
.search3(query, 20, 20, 20)
|
.search3(query, 20, 0, 20, 0, 20, 0)
|
||||||
.enqueue(new Callback<ApiResponse>() {
|
.enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||||
@@ -77,7 +138,7 @@ public class SearchingRepository {
|
|||||||
|
|
||||||
App.getSubsonicClientInstance(false)
|
App.getSubsonicClientInstance(false)
|
||||||
.getSearchingClient()
|
.getSearchingClient()
|
||||||
.search3(query, 5, 5, 5)
|
.search3(query, 5, 0, 5, 0, 5, 0)
|
||||||
.enqueue(new Callback<ApiResponse>() {
|
.enqueue(new Callback<ApiResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
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);
|
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()");
|
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);
|
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")
|
@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.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.splashscreen.SplashScreen;
|
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.drawerlayout.widget.DrawerLayout;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
@@ -31,7 +24,6 @@ import androidx.media3.common.Player;
|
|||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.navigation.NavController;
|
import androidx.navigation.NavController;
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
import androidx.navigation.fragment.NavHostFragment;
|
||||||
import androidx.navigation.ui.NavigationUI;
|
|
||||||
|
|
||||||
import com.cappielloantonio.tempo.App;
|
import com.cappielloantonio.tempo.App;
|
||||||
import com.cappielloantonio.tempo.BuildConfig;
|
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.broadcast.receiver.ConnectivityStatusBroadcastReceiver;
|
||||||
import com.cappielloantonio.tempo.databinding.ActivityMainBinding;
|
import com.cappielloantonio.tempo.databinding.ActivityMainBinding;
|
||||||
import com.cappielloantonio.tempo.github.utils.UpdateUtil;
|
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.service.MediaManager;
|
||||||
import com.cappielloantonio.tempo.ui.activity.base.BaseActivity;
|
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.ConnectionAlertDialog;
|
||||||
import com.cappielloantonio.tempo.ui.dialog.GithubTempoUpdateDialog;
|
import com.cappielloantonio.tempo.ui.dialog.GithubTempoUpdateDialog;
|
||||||
import com.cappielloantonio.tempo.ui.dialog.ServerUnreachableDialog;
|
import com.cappielloantonio.tempo.ui.dialog.ServerUnreachableDialog;
|
||||||
@@ -70,10 +66,12 @@ public class MainActivity extends BaseActivity {
|
|||||||
private NavHostFragment navHostFragment;
|
private NavHostFragment navHostFragment;
|
||||||
private BottomNavigationView bottomNavigationView;
|
private BottomNavigationView bottomNavigationView;
|
||||||
private FrameLayout bottomNavigationViewFrame;
|
private FrameLayout bottomNavigationViewFrame;
|
||||||
public NavController navController;
|
|
||||||
private DrawerLayout drawerLayout;
|
private DrawerLayout drawerLayout;
|
||||||
private NavigationView navigationView;
|
private NavigationView navigationView;
|
||||||
private BottomSheetBehavior bottomSheetBehavior;
|
public NavController navController;
|
||||||
|
private NavigationController navigationController;
|
||||||
|
private BottomSheetController bottomSheetController;
|
||||||
|
public BottomSheetBehavior bottomSheetBehavior;
|
||||||
public boolean isLandscape = false;
|
public boolean isLandscape = false;
|
||||||
private AssetLinkNavigator assetLinkNavigator;
|
private AssetLinkNavigator assetLinkNavigator;
|
||||||
private AssetLinkUtil.AssetLink pendingAssetLink;
|
private AssetLinkUtil.AssetLink pendingAssetLink;
|
||||||
@@ -81,6 +79,10 @@ public class MainActivity extends BaseActivity {
|
|||||||
ConnectivityStatusBroadcastReceiver connectivityStatusBroadcastReceiver;
|
ConnectivityStatusBroadcastReceiver connectivityStatusBroadcastReceiver;
|
||||||
private Intent pendingDownloadPlaybackIntent;
|
private Intent pendingDownloadPlaybackIntent;
|
||||||
|
|
||||||
|
public ActivityMainBinding getBinding() {
|
||||||
|
return bind;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
SplashScreen.installSplashScreen(this);
|
SplashScreen.installSplashScreen(this);
|
||||||
@@ -147,7 +149,6 @@ public class MainActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
fragmentManager = getSupportFragmentManager();
|
|
||||||
|
|
||||||
initBottomSheet();
|
initBottomSheet();
|
||||||
initNavigation();
|
initNavigation();
|
||||||
@@ -162,49 +163,74 @@ public class MainActivity extends BaseActivity {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BOTTOM SHEET/NAVIGATION
|
private void initNavigation() {
|
||||||
private void initBottomSheet() {
|
// We link the nav_graph.xml with our navigationController
|
||||||
bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.player_bottom_sheet));
|
NavHostFragment navHostFragment = (NavHostFragment) this
|
||||||
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallback);
|
.getSupportFragmentManager()
|
||||||
fragmentManager.beginTransaction().replace(R.id.player_bottom_sheet, new PlayerBottomSheetFragment(), "PlayerBottomSheet").commit();
|
.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) {
|
public void setBottomSheetInPeek(Boolean isVisible) {
|
||||||
if (isVisible) {
|
bottomSheetController.setStateInPeek(isVisible);
|
||||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
||||||
} else {
|
|
||||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBottomSheetVisibility(boolean visibility) {
|
public void setBottomSheetVisibility(boolean visibility) {
|
||||||
if (visibility) {
|
bottomSheetController.setVisibility(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void collapseBottomSheetDelayed() {
|
public void collapseBottomSheetDelayed() {
|
||||||
final Handler handler = new Handler();
|
bottomSheetController.collapseDelayed();
|
||||||
final Runnable runnable = () -> bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
||||||
handler.postDelayed(runnable, 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expandBottomSheet() {
|
public void expandBottomSheet() {
|
||||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
bottomSheetController.expand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBottomSheetDraggableState(Boolean isDraggable) {
|
public void setBottomSheetDraggableState(Boolean isDraggable) {
|
||||||
bottomSheetBehavior.setDraggable(isDraggable);
|
bottomSheetController.setDraggable(isDraggable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BottomSheetBehavior.BottomSheetCallback bottomSheetCallback =
|
private final BottomSheetBehavior.BottomSheetCallback bottomSheetCallback =
|
||||||
@@ -217,7 +243,7 @@ public class MainActivity extends BaseActivity {
|
|||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case BottomSheetBehavior.STATE_HIDDEN:
|
case BottomSheetBehavior.STATE_HIDDEN:
|
||||||
resetMusicSession();
|
resetMusicSession(); // I can't put the callback inside BottomSheetHelper because of this line
|
||||||
break;
|
break;
|
||||||
case BottomSheetBehavior.STATE_COLLAPSED:
|
case BottomSheetBehavior.STATE_COLLAPSED:
|
||||||
if (playerBottomSheetFragment != null)
|
if (playerBottomSheetFragment != null)
|
||||||
@@ -241,12 +267,7 @@ public class MainActivity extends BaseActivity {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private void animateBottomSheet(float slideOffset) {
|
private void animateBottomSheet(float slideOffset) {
|
||||||
PlayerBottomSheetFragment playerBottomSheetFragment = (PlayerBottomSheetFragment) getSupportFragmentManager().findFragmentByTag("PlayerBottomSheet");
|
bottomSheetController.animate(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void animateBottomNavigation(float slideOffset, int navigationHeight) {
|
private void animateBottomNavigation(float slideOffset, int navigationHeight) {
|
||||||
@@ -261,117 +282,56 @@ public class MainActivity extends BaseActivity {
|
|||||||
bind.bottomNavigation.setTranslationY(slideY);
|
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) {
|
public void setBottomNavigationBarVisibility(boolean visibility) {
|
||||||
if (visibility) {
|
navigationController.setNavbarVisibility(visibility);
|
||||||
bottomNavigationView.setVisibility(View.VISIBLE);
|
|
||||||
bottomNavigationViewFrame.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
bottomNavigationView.setVisibility(View.GONE);
|
|
||||||
bottomNavigationViewFrame.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleBottomNavigationBarVisibilityOnOrientationChange() {
|
public void toggleBottomNavigationBarVisibilityOnOrientationChange() {
|
||||||
|
float displayDensity = getResources().getDisplayMetrics().density;
|
||||||
// Ignore orientation change, bottom navbar always hidden
|
// Ignore orientation change, bottom navbar always hidden
|
||||||
if (Preferences.getHideBottomNavbarOnPortrait()) {
|
if (Preferences.getHideBottomNavbarOnPortrait()) {
|
||||||
setBottomNavigationBarVisibility(false);
|
navigationController.setNavbarVisibility(false);
|
||||||
setPortraitPlayerBottomSheetPeekHeight(56);
|
bottomSheetController.setPeekHeight(56, displayDensity);
|
||||||
setSystemBarsVisibility(!isLandscape);
|
navigationController.setSystemBarsVisibility(this, !isLandscape);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLandscape) {
|
if (!isLandscape) {
|
||||||
// Show app navbar + show system bars
|
// Show app navbar + show system bars
|
||||||
setPortraitPlayerBottomSheetPeekHeight(136);
|
bottomSheetController.setPeekHeight(136, displayDensity);
|
||||||
setBottomNavigationBarVisibility(true);
|
navigationController.setNavbarVisibility(true);
|
||||||
setSystemBarsVisibility(true);
|
navigationController.setSystemBarsVisibility(this, true);
|
||||||
} else {
|
} else {
|
||||||
// Hide app navbar + hide system bars
|
// Hide app navbar + hide system bars
|
||||||
setPortraitPlayerBottomSheetPeekHeight(56);
|
bottomSheetController.setPeekHeight(56, displayDensity);
|
||||||
setBottomNavigationBarVisibility(false);
|
navigationController.setNavbarVisibility(false);
|
||||||
setSystemBarsVisibility(false);
|
navigationController.setSystemBarsVisibility(this, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNavigationDrawerLock(boolean locked) {
|
public void setNavigationDrawerLock(boolean locked) {
|
||||||
int mode = locked
|
navigationController.setDrawerLock(locked);
|
||||||
? DrawerLayout.LOCK_MODE_LOCKED_CLOSED
|
}
|
||||||
: DrawerLayout.LOCK_MODE_UNLOCKED;
|
|
||||||
drawerLayout.setDrawerLockMode(mode);
|
public boolean isNavigationDrawerLocked() {
|
||||||
|
return navigationController.isNavigationDrawerLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleNavigationDrawerLockOnOrientationChange() {
|
public void toggleNavigationDrawerLockOnOrientationChange() {
|
||||||
// Ignore orientation check, drawer always unlocked
|
navigationController.toggleDrawerLockOnOrientation(this);
|
||||||
if (Preferences.getEnableDrawerOnPortrait()) {
|
|
||||||
setNavigationDrawerLock(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!isLandscape) {
|
|
||||||
setNavigationDrawerLock(true);
|
|
||||||
} else {
|
|
||||||
setNavigationDrawerLock(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSystemBarsVisibility(boolean visibility) {
|
public void setSystemBarsVisibility(boolean visibility) {
|
||||||
WindowInsetsControllerCompat insetsController;
|
navigationController.setSystemBarsVisibility(this, visibility);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPortraitPlayerBottomSheetPeekHeight(int peekHeight) {
|
/*
|
||||||
FrameLayout bottomSheet = findViewById(R.id.player_bottom_sheet);
|
There are only 4 init functions that must exist up to here
|
||||||
BottomSheetBehavior<FrameLayout> behavior =
|
1. init()
|
||||||
BottomSheetBehavior.from(bottomSheet);
|
2. initNavigation()
|
||||||
|
3. initBottomSheet()
|
||||||
int newPeekPx = (int) (peekHeight * getResources().getDisplayMetrics().density);
|
4. bottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() { ... }
|
||||||
behavior.setPeekHeight(newPeekPx);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
private void initService() {
|
private void initService() {
|
||||||
MediaManager.check(getMediaBrowserListenableFuture());
|
MediaManager.check(getMediaBrowserListenableFuture());
|
||||||
@@ -407,7 +367,7 @@ public class MainActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void goToHome() {
|
private void goToHome() {
|
||||||
bottomNavigationView.setVisibility(View.VISIBLE);
|
setBottomNavigationBarVisibility(true);
|
||||||
|
|
||||||
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
|
if (Objects.requireNonNull(navController.getCurrentDestination()).getId() == R.id.landingFragment) {
|
||||||
navController.navigate(R.id.action_landingFragment_to_homeFragment);
|
navController.navigate(R.id.action_landingFragment_to_homeFragment);
|
||||||
|
|||||||
@@ -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.interfaces.ClickCallback;
|
||||||
import com.cappielloantonio.tempo.service.MediaManager;
|
import com.cappielloantonio.tempo.service.MediaManager;
|
||||||
import com.cappielloantonio.tempo.service.MediaService;
|
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.activity.MainActivity;
|
||||||
import com.cappielloantonio.tempo.ui.adapter.AlbumAdapter;
|
import com.cappielloantonio.tempo.ui.adapter.AlbumAdapter;
|
||||||
import com.cappielloantonio.tempo.ui.adapter.ArtistAdapter;
|
import com.cappielloantonio.tempo.ui.adapter.ArtistAdapter;
|
||||||
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
|
||||||
|
import com.cappielloantonio.tempo.ui.adapter.PlaylistHorizontalAdapter;
|
||||||
import com.cappielloantonio.tempo.util.Constants;
|
import com.cappielloantonio.tempo.util.Constants;
|
||||||
import com.cappielloantonio.tempo.viewmodel.PlaybackViewModel;
|
import com.cappielloantonio.tempo.viewmodel.PlaybackViewModel;
|
||||||
import com.cappielloantonio.tempo.viewmodel.SearchViewModel;
|
import com.cappielloantonio.tempo.viewmodel.SearchViewModel;
|
||||||
|
import com.cappielloantonio.tempo.subsonic.models.PlaylistWithSongs;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public class SearchFragment extends Fragment implements ClickCallback {
|
public class SearchFragment extends Fragment implements ClickCallback {
|
||||||
@@ -49,6 +53,7 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
|||||||
private ArtistAdapter artistAdapter;
|
private ArtistAdapter artistAdapter;
|
||||||
private AlbumAdapter albumAdapter;
|
private AlbumAdapter albumAdapter;
|
||||||
private SongHorizontalAdapter songHorizontalAdapter;
|
private SongHorizontalAdapter songHorizontalAdapter;
|
||||||
|
private PlaylistHorizontalAdapter playlistHorizontalAdapter;
|
||||||
|
|
||||||
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
|
||||||
|
|
||||||
@@ -126,6 +131,12 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
|||||||
reapplyPlayback();
|
reapplyPlayback();
|
||||||
|
|
||||||
bind.searchResultTracksRecyclerView.setAdapter(songHorizontalAdapter);
|
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() {
|
private void initSearchView() {
|
||||||
@@ -216,13 +227,23 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
|||||||
|
|
||||||
public void search(String query) {
|
public void search(String query) {
|
||||||
searchViewModel.setQuery(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.searchBar.setText(query);
|
||||||
bind.searchView.hide();
|
bind.searchView.hide();
|
||||||
performSearch(query);
|
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) {
|
private void performSearch(String query) {
|
||||||
searchViewModel.search3(query).observe(getViewLifecycleOwner(), result -> {
|
searchViewModel.search3(this, query).observe(getViewLifecycleOwner(), result -> {
|
||||||
if (bind != null) {
|
if (bind != null) {
|
||||||
if (result.getArtists() != null) {
|
if (result.getArtists() != null) {
|
||||||
bind.searchArtistSector.setVisibility(!result.getArtists().isEmpty() ? View.VISIBLE : View.GONE);
|
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);
|
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
|
@Override
|
||||||
public void onAlbumClick(Bundle bundle) {
|
public void onAlbumClick(Bundle bundle) {
|
||||||
Navigation.findNavController(requireView()).navigate(R.id.albumPageFragment, 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;
|
package com.cappielloantonio.tempo.ui.fragment;
|
||||||
|
|
||||||
import android.app.Activity;
|
import static com.google.android.material.internal.ViewUtils.hideKeyboard;
|
||||||
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 android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.text.InputFilter;
|
|
||||||
import android.text.InputType;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.OptIn;
|
import androidx.fragment.app.Fragment;
|
||||||
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.R;
|
||||||
import com.cappielloantonio.tempo.helper.ThemeHelper;
|
import com.cappielloantonio.tempo.databinding.FragmentSettingsBinding;
|
||||||
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.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.Preferences;
|
||||||
import com.cappielloantonio.tempo.util.UIUtil;
|
|
||||||
import com.cappielloantonio.tempo.util.ExternalAudioReader;
|
|
||||||
import com.cappielloantonio.tempo.viewmodel.SettingViewModel;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
public class SettingsFragment extends Fragment {
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@OptIn(markerClass = UnstableApi.class)
|
|
||||||
public class SettingsFragment extends PreferenceFragmentCompat {
|
|
||||||
private static final String TAG = "SettingsFragment";
|
|
||||||
|
|
||||||
private MainActivity activity;
|
private MainActivity activity;
|
||||||
private SettingViewModel settingViewModel;
|
private FragmentSettingsBinding bind;
|
||||||
|
|
||||||
private ActivityResultLauncher<Intent> equalizerResultLauncher;
|
|
||||||
private ActivityResultLauncher<Intent> directoryPickerLauncher;
|
|
||||||
|
|
||||||
private MediaService.LocalBinder mediaServiceBinder;
|
|
||||||
private boolean isServiceBound = false;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
equalizerResultLauncher = registerForActivityResult(
|
activity = (MainActivity) getActivity();
|
||||||
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
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
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);
|
initAppBar();
|
||||||
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;
|
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
|
@Override
|
||||||
@@ -134,479 +67,21 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
activity.setSystemBarsVisibility(!activity.isLandscape);
|
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
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
activity.setBottomSheetVisibility(true);
|
activity.setBottomSheetVisibility(true);
|
||||||
activity.toggleNavigationDrawerLockOnOrientationChange();
|
|
||||||
activity.setSystemBarsVisibility(!activity.isLandscape);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (activity.isLandscape) {
|
||||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
activity.setNavigationDrawerLock(false);
|
||||||
setPreferencesFromResource(R.xml.global_preferences, rootKey);
|
} else if (Preferences.getEnableDrawerOnPortrait()) {
|
||||||
ListPreference themePreference = findPreference(Preferences.THEME);
|
activity.setNavigationDrawerLock(false);
|
||||||
if (themePreference != null) {
|
|
||||||
themePreference.setOnPreferenceChangeListener(
|
|
||||||
(preference, newValue) -> {
|
|
||||||
String themeOption = (String) newValue;
|
|
||||||
ThemeHelper.applyTheme(themeOption);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSystemEqualizer() {
|
private void initAppBar() {
|
||||||
Preference equalizer = findPreference("system_equalizer");
|
bind.settingsToolbar.setNavigationOnClickListener(v -> {
|
||||||
|
activity.navController.navigateUp();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_SECOND_TAB = "androidauto_second_tab"
|
||||||
private const val AA_THIRD_TAB = "androidauto_third_tab"
|
private const val AA_THIRD_TAB = "androidauto_third_tab"
|
||||||
private const val AA_FOURTH_TAB = "androidauto_fourth_tab"
|
private const val AA_FOURTH_TAB = "androidauto_fourth_tab"
|
||||||
|
private const val AA_SHUFFLE_GENRE_SONGS = "androidauto_shuffle_genre_songs"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getServer(): String? {
|
fun getServer(): String? {
|
||||||
@@ -818,4 +819,14 @@ object Preferences {
|
|||||||
return App.getInstance().preferences.getString(AA_FOURTH_TAB, "3")!!.toInt()
|
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.annotation.NonNull;
|
||||||
import androidx.lifecycle.AndroidViewModel;
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
|
||||||
import com.cappielloantonio.tempo.model.RecentSearch;
|
import com.cappielloantonio.tempo.model.RecentSearch;
|
||||||
import com.cappielloantonio.tempo.repository.SearchingRepository;
|
import com.cappielloantonio.tempo.repository.SearchingRepository;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.SearchResult2;
|
import com.cappielloantonio.tempo.subsonic.models.SearchResult2;
|
||||||
import com.cappielloantonio.tempo.subsonic.models.SearchResult3;
|
import com.cappielloantonio.tempo.subsonic.models.SearchResult3;
|
||||||
|
import com.cappielloantonio.tempo.ui.fragment.SearchFragment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -43,8 +45,9 @@ public class SearchViewModel extends AndroidViewModel {
|
|||||||
return searchingRepository.search2(title);
|
return searchingRepository.search2(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<SearchResult3> search3(String title) {
|
@UnstableApi
|
||||||
return searchingRepository.search3(title);
|
public LiveData<SearchResult3> search3(SearchFragment sf, String title) {
|
||||||
|
return searchingRepository.search3(sf, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insertNewSearch(String search) {
|
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"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="108dp"
|
android:width="108dp"
|
||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="512"
|
android:viewportWidth="108"
|
||||||
android:viewportHeight="512">
|
android:viewportHeight="108">
|
||||||
<group android:scaleX="0.49"
|
|
||||||
android:scaleY="0.49"
|
<group
|
||||||
android:translateX="130.56"
|
android:scaleX="0.13"
|
||||||
android:translateY="130.56">
|
android:scaleY="0.13"
|
||||||
<path
|
android:translateX="21.5"
|
||||||
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:translateY="21.5">
|
||||||
android:fillColor="#DA4453"/>
|
<path
|
||||||
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#ED5564"/>
|
<gradient
|
||||||
<path
|
android:startX="122.34"
|
||||||
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:startY="23.55"
|
||||||
android:fillColor="#DA4453"/>
|
android:endX="377.69"
|
||||||
<path
|
android:endY="465.83"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#E6E9ED"/>
|
<item android:offset="0.0" android:color="#FFEC4A4A" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#FFEC4A4A" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#E6E9ED"/>
|
</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"/>
|
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#E6E9ED"/>
|
<gradient
|
||||||
<path
|
android:startX="116.21"
|
||||||
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:startY="67.61"
|
||||||
android:fillColor="#CCD1D9"/>
|
android:endX="403.29"
|
||||||
<path
|
android:endY="429.34"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#434A54"/>
|
<item android:offset="0.0" android:color="#66060606" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#CC060606" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#656D78"/>
|
</aapt:attr>
|
||||||
<path
|
</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
|
||||||
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#FFCE54"/>
|
<gradient
|
||||||
<path
|
android:startX="420.63"
|
||||||
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:startY="403.74"
|
||||||
android:fillColor="#F6BB42"/>
|
android:endX="78.4"
|
||||||
<path
|
android:endY="117.92"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#434A54"/>
|
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#434A54"/>
|
</aapt:attr>
|
||||||
</group>
|
</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>
|
</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"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:width="108dp"
|
android:width="108dp"
|
||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="512"
|
android:viewportWidth="108"
|
||||||
android:viewportHeight="512">
|
android:viewportHeight="108">
|
||||||
<group android:scaleX="0.55"
|
|
||||||
android:scaleY="0.55"
|
<group
|
||||||
android:translateX="150.56"
|
android:scaleX="0.13"
|
||||||
android:translateY="150.56">
|
android:scaleY="0.13"
|
||||||
<path
|
android:translateX="21.5"
|
||||||
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:translateY="21.5">
|
||||||
android:fillColor="#DA4453"/>
|
<path
|
||||||
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#ED5564"/>
|
<gradient
|
||||||
<path
|
android:startX="122.34"
|
||||||
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:startY="23.55"
|
||||||
android:fillColor="#DA4453"/>
|
android:endX="377.69"
|
||||||
<path
|
android:endY="465.83"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#E6E9ED"/>
|
<item android:offset="0.0" android:color="#FFEC4A4A" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#FFEC4A4A" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#E6E9ED"/>
|
</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"/>
|
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#E6E9ED"/>
|
<gradient
|
||||||
<path
|
android:startX="116.21"
|
||||||
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:startY="67.61"
|
||||||
android:fillColor="#CCD1D9"/>
|
android:endX="403.29"
|
||||||
<path
|
android:endY="429.34"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#434A54"/>
|
<item android:offset="0.0" android:color="#66060606" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#CC060606" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#656D78"/>
|
</aapt:attr>
|
||||||
<path
|
</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
|
||||||
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#FFCE54"/>
|
<gradient
|
||||||
<path
|
android:startX="420.63"
|
||||||
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:startY="403.74"
|
||||||
android:fillColor="#F6BB42"/>
|
android:endX="78.4"
|
||||||
<path
|
android:endY="117.92"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#434A54"/>
|
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#434A54"/>
|
</aapt:attr>
|
||||||
</group>
|
</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>
|
</vector>
|
||||||
@@ -1,52 +1,77 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:height="24dp"
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
android:viewportWidth="512"
|
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
|
<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: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">
|
||||||
android:fillColor="#DA4453"/>
|
<aapt:attr name="android:fillColor">
|
||||||
<path
|
<gradient
|
||||||
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:startX="122.34"
|
||||||
android:fillColor="#ED5564"/>
|
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"
|
<path
|
||||||
android:fillColor="#DA4453"/>
|
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">
|
||||||
<path
|
<aapt:attr name="android:fillColor">
|
||||||
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"
|
<gradient
|
||||||
android:fillColor="#E6E9ED"/>
|
android:startX="116.21"
|
||||||
<path
|
android:startY="67.61"
|
||||||
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:endX="403.29"
|
||||||
android:fillColor="#E6E9ED"/>
|
android:endY="429.34"
|
||||||
<path
|
android:type="linear">
|
||||||
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"
|
<item android:offset="0.0" android:color="#66060606" />
|
||||||
android:fillColor="#E6E9ED"/>
|
<item android:offset="1.0" android:color="#CC060606" />
|
||||||
<path
|
</gradient>
|
||||||
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"
|
</aapt:attr>
|
||||||
android:fillColor="#E6E9ED"/>
|
</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"
|
<path
|
||||||
android:fillColor="#CCD1D9"/>
|
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">
|
||||||
<path
|
<aapt:attr name="android:fillColor">
|
||||||
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"
|
<gradient
|
||||||
android:fillColor="#434A54"/>
|
android:startX="420.63"
|
||||||
<path
|
android:startY="403.74"
|
||||||
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:endX="78.4"
|
||||||
android:fillColor="#656D78"/>
|
android:endY="117.92"
|
||||||
<path
|
android:type="linear">
|
||||||
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"
|
<item android:offset="0.0" android:color="#33FFFFFF" />
|
||||||
android:fillColor="#656D78"/>
|
<item android:offset="1.0" android:color="#4DFFFFFF" />
|
||||||
<path
|
</gradient>
|
||||||
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"
|
</aapt:attr>
|
||||||
android:fillColor="#FFCE54"/>
|
</path>
|
||||||
<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"
|
<path
|
||||||
android:fillColor="#F6BB42"/>
|
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">
|
||||||
<path
|
<aapt:attr name="android:fillColor">
|
||||||
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"
|
<gradient
|
||||||
android:fillColor="#434A54"/>
|
android:startX="420.63"
|
||||||
<path
|
android:startY="403.74"
|
||||||
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:endX="78.4"
|
||||||
android:fillColor="#434A54"/>
|
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>
|
</vector>
|
||||||
@@ -1,51 +1,78 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="800dp"
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
android:height="800dp"
|
android:width="108dp"
|
||||||
android:viewportWidth="512"
|
android:height="108dp"
|
||||||
android:viewportHeight="512">
|
android:viewportWidth="108"
|
||||||
<path
|
android:viewportHeight="108">
|
||||||
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"/>
|
<group
|
||||||
<path
|
android:scaleX="0.16"
|
||||||
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:scaleY="0.16"
|
||||||
android:fillColor="#ED5564"/>
|
android:translateX="14.0"
|
||||||
<path
|
android:translateY="14.0">
|
||||||
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
|
||||||
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#E6E9ED"/>
|
<gradient
|
||||||
<path
|
android:startX="122.34"
|
||||||
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:startY="23.55"
|
||||||
android:fillColor="#E6E9ED"/>
|
android:endX="377.69"
|
||||||
<path
|
android:endY="465.83"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#E6E9ED"/>
|
<item android:offset="0.0" android:color="#FFEC4A4A" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#FFEC4A4A" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#E6E9ED"/>
|
</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
|
||||||
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#434A54"/>
|
<gradient
|
||||||
<path
|
android:startX="116.21"
|
||||||
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:startY="67.61"
|
||||||
android:fillColor="#656D78"/>
|
android:endX="403.29"
|
||||||
<path
|
android:endY="429.34"
|
||||||
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:type="linear">
|
||||||
android:fillColor="#656D78"/>
|
<item android:offset="0.0" android:color="#66060606" />
|
||||||
<path
|
<item android:offset="1.0" android:color="#CC060606" />
|
||||||
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"
|
</gradient>
|
||||||
android:fillColor="#FFCE54"/>
|
</aapt:attr>
|
||||||
<path
|
</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
|
||||||
<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">
|
||||||
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"
|
<aapt:attr name="android:fillColor">
|
||||||
android:fillColor="#434A54"/>
|
<gradient
|
||||||
<path
|
android:startX="420.63"
|
||||||
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:startY="403.74"
|
||||||
android:fillColor="#434A54"/>
|
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>
|
</vector>
|
||||||
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:clipToPadding="false"
|
||||||
android:paddingTop="8dp"
|
android:paddingTop="8dp"
|
||||||
android:paddingBottom="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>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:paddingTop="20dp"
|
|
||||||
android:paddingBottom="@dimen/global_padding_bottom" />
|
<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>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<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"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
|
||||||
</adaptive-icon>
|
</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:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.SongBottomSheetDialog"
|
||||||
android:label="SongBottomSheetDialog"
|
android:label="SongBottomSheetDialog"
|
||||||
tools:layout="@layout/bottom_sheet_song_dialog" />
|
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
|
<dialog
|
||||||
android:id="@+id/artistBottomSheetDialog"
|
android:id="@+id/artistBottomSheetDialog"
|
||||||
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.ArtistBottomSheetDialog"
|
android:name="com.cappielloantonio.tempo.ui.fragment.bottomsheetdialog.ArtistBottomSheetDialog"
|
||||||
|
|||||||
@@ -288,6 +288,7 @@
|
|||||||
<item>Albums favoris</item>
|
<item>Albums favoris</item>
|
||||||
<item>Artistes favoris</item>
|
<item>Artistes favoris</item>
|
||||||
<item>Aléatoire</item>
|
<item>Aléatoire</item>
|
||||||
|
<item>Genres</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="aa_tab_values">
|
<string-array name="aa_tab_values">
|
||||||
<item>-1</item>
|
<item>-1</item>
|
||||||
@@ -307,6 +308,7 @@
|
|||||||
<item>13</item>
|
<item>13</item>
|
||||||
<item>14</item>
|
<item>14</item>
|
||||||
<item>15</item>
|
<item>15</item>
|
||||||
|
<item>16</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<!-- end Add by MFO -->
|
<!-- end Add by MFO -->
|
||||||
|
|
||||||
|
|||||||
@@ -338,6 +338,8 @@
|
|||||||
<string name="settings_androidauto_second_tab">Affichage du deuxième onglet</string>
|
<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_third_tab">Affichage du troisième onglet</string>
|
||||||
<string name="settings_androidauto_fourth_tab">Affichage du quatriè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_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_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>
|
<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>
|
||||||
|
|||||||
@@ -297,6 +297,7 @@
|
|||||||
<item>Избранные альбомы</item>
|
<item>Избранные альбомы</item>
|
||||||
<item>Избранные артисты</item>
|
<item>Избранные артисты</item>
|
||||||
<item>Случайное</item>
|
<item>Случайное</item>
|
||||||
|
<item>Жанры</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="aa_tab_values">
|
<string-array name="aa_tab_values">
|
||||||
<item>-1</item>
|
<item>-1</item>
|
||||||
@@ -316,6 +317,7 @@
|
|||||||
<item>13</item>
|
<item>13</item>
|
||||||
<item>14</item>
|
<item>14</item>
|
||||||
<item>15</item>
|
<item>15</item>
|
||||||
|
<item>16</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<!-- end Add by MFO -->
|
<!-- end Add by MFO -->
|
||||||
|
|
||||||
|
|||||||
@@ -402,6 +402,8 @@
|
|||||||
<string name="settings_androidauto_second_tab">Second tab display</string>
|
<string name="settings_androidauto_second_tab">Second tab display</string>
|
||||||
<string name="settings_androidauto_third_tab">Third 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_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">Показывать качество аудио</string>
|
||||||
<string name="settings_audio_quality_summary">Битрейт и формат аудио будут отображаться для каждого трека.</string>
|
<string name="settings_audio_quality_summary">Битрейт и формат аудио будут отображаться для каждого трека.</string>
|
||||||
<string name="settings_song_rating">Показывать рейтинг трека</string>
|
<string name="settings_song_rating">Показывать рейтинг трека</string>
|
||||||
|
|||||||
@@ -310,8 +310,9 @@
|
|||||||
<!-- <item>For you</item> -->
|
<!-- <item>For you</item> -->
|
||||||
<item>Star tracks</item>
|
<item>Star tracks</item>
|
||||||
<item>Star albums</item>
|
<item>Star albums</item>
|
||||||
<item>Star artistes</item>
|
<item>Star artists</item>
|
||||||
<item>Random</item>
|
<item>Random</item>
|
||||||
|
<item>Genres</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="aa_tab_values">
|
<string-array name="aa_tab_values">
|
||||||
<item>-1</item>
|
<item>-1</item>
|
||||||
@@ -331,6 +332,7 @@
|
|||||||
<item>13</item>
|
<item>13</item>
|
||||||
<item>14</item>
|
<item>14</item>
|
||||||
<item>15</item>
|
<item>15</item>
|
||||||
|
<item>16</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<!-- end Add by MFO -->
|
<!-- 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_podcast">Podcast</string>
|
||||||
<string name="aa_radio">Radio</string>
|
<string name="aa_radio">Radio</string>
|
||||||
<string name="aa_random">Random</string>
|
<string name="aa_random">Random</string>
|
||||||
|
<string name="aa_genres">Genres</string>
|
||||||
<string name="aa_recent_albums">Recent</string>
|
<string name="aa_recent_albums">Recent</string>
|
||||||
<string name="aa_song_recently_played">Song played</string>
|
<string name="aa_song_recently_played">Song played</string>
|
||||||
<string name="aa_starred_albums">★ Albums</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_second_tab">Second tab display</string>
|
||||||
<string name="settings_androidauto_third_tab">Third 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_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">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_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>
|
<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_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">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_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">Enable drawer on portrait</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_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">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_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>
|
<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_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_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>
|
</resources>
|
||||||
|
|||||||
@@ -521,6 +521,11 @@
|
|||||||
app:title="@string/settings_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>
|
</PreferenceCategory>
|
||||||
<!-- end Add by MFO -->
|
<!-- end Add by MFO -->
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ object MediaBrowserTree {
|
|||||||
private const val STARRED_ARTISTS_ID = "[starredArtistsID]"
|
private const val STARRED_ARTISTS_ID = "[starredArtistsID]"
|
||||||
private const val RANDOM_ID = "[randomID]"
|
private const val RANDOM_ID = "[randomID]"
|
||||||
private const val FOLDER_ID = "[folderID]"
|
private const val FOLDER_ID = "[folderID]"
|
||||||
|
private const val GENRES_ID = "[genresID]"
|
||||||
|
|
||||||
// System functions
|
// System functions
|
||||||
private const val INDEX_ID = "[indexID]"
|
private const val INDEX_ID = "[indexID]"
|
||||||
@@ -178,7 +179,8 @@ object MediaBrowserTree {
|
|||||||
STARRED_TRACKS_ID,
|
STARRED_TRACKS_ID,
|
||||||
STARRED_ALBUMS_ID,
|
STARRED_ALBUMS_ID,
|
||||||
STARRED_ARTISTS_ID,
|
STARRED_ARTISTS_ID,
|
||||||
RANDOM_ID
|
RANDOM_ID,
|
||||||
|
GENRES_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
// Root level
|
// 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 root = treeNodes[ROOT_ID]!!
|
||||||
val selectedIds = mutableSetOf<String>()
|
val selectedIds = mutableSetOf<String>()
|
||||||
|
|
||||||
@@ -474,6 +489,7 @@ object MediaBrowserTree {
|
|||||||
STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id)
|
STARRED_ALBUMS_ID -> automotiveRepository.getStarredAlbums(id)
|
||||||
STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id)
|
STARRED_ARTISTS_ID -> automotiveRepository.getStarredArtists(id)
|
||||||
RANDOM_ID -> automotiveRepository.getRandomSongs(100)
|
RANDOM_ID -> automotiveRepository.getRandomSongs(100)
|
||||||
|
GENRES_ID -> automotiveRepository.getGenres(id)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
if (id.startsWith(LAST_PLAYED_ID)) {
|
if (id.startsWith(LAST_PLAYED_ID)) {
|
||||||
@@ -512,6 +528,13 @@ object MediaBrowserTree {
|
|||||||
return automotiveRepository.getArtistAlbum(STARRED_ALBUMS_ID,id.removePrefix(STARRED_ARTISTS_ID))
|
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)) {
|
if (id.startsWith(PLAYLIST_ID)) {
|
||||||
return automotiveRepository.getPlaylistSongs(id.removePrefix(PLAYLIST_ID))
|
return automotiveRepository.getPlaylistSongs(id.removePrefix(PLAYLIST_ID))
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 41 KiB |
BIN
mockup/svg/tempus-horizontal-banner.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 34 KiB |