Fix context menus.

Also cleanup files, rename layouts
This commit is contained in:
tzugen 2021-11-27 00:51:41 +01:00
parent b33fe2d451
commit 82d90a6aee
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
53 changed files with 541 additions and 1174 deletions

View File

@ -8,16 +8,6 @@ import java.util.Date
class MusicDirectory : ArrayList<MusicDirectory.Child>() { class MusicDirectory : ArrayList<MusicDirectory.Child>() {
var name: String? = null var name: String? = null
fun addFirst(child: Child) {
add(0, child)
}
fun addChild(child: Child) {
add(child)
}
fun findChild(id: String): GenericEntry? = lastOrNull { it.id == id }
@JvmOverloads @JvmOverloads
fun getChildren( fun getChildren(
includeDirs: Boolean = true, includeDirs: Boolean = true,

View File

@ -55,7 +55,7 @@
errorLine2=" ^"> errorLine2=" ^">
<location <location
file="src/main/res/values-de/strings.xml" file="src/main/res/values-de/strings.xml"
line="290" line="289"
column="76"/> column="76"/>
</issue> </issue>
@ -66,29 +66,18 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="132" line="134"
column="5"/> column="5"/>
</issue> </issue>
<issue <issue
id="PluralsCandidate" id="PluralsCandidate"
message="Formatting %d followed by words (&quot;tracks&quot;): This should probably be a plural rather than a string" message="Formatting %d followed by words (&quot;tracks&quot;): This should probably be a plural rather than a string"
errorLine1=" &lt;string name=&quot;select_album.n_selected&quot;>%d tracks selected.&lt;/string>" errorLine1=" &lt;string name=&quot;select_album.n_selected&quot;>%d tracks selected&lt;/string>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="149" line="151"
column="5"/>
</issue>
<issue
id="PluralsCandidate"
message="Formatting %d followed by words (&quot;tracks&quot;): This should probably be a plural rather than a string"
errorLine1=" &lt;string name=&quot;select_album.n_unselected&quot;>%d tracks unselected.&lt;/string>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="150"
column="5"/> column="5"/>
</issue> </issue>
@ -136,17 +125,6 @@
column="10"/> column="10"/>
</issue> </issue>
<issue
id="ObsoleteLayoutParam"
message="Invalid layout param in a `LinearLayout`: `layout_alignParentLeft`"
errorLine1=" a:layout_alignParentLeft=&quot;true&quot;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/layout/media_buttons.xml"
line="14"
column="9"/>
</issue>
<issue <issue
id="ObsoleteLayoutParam" id="ObsoleteLayoutParam"
message="Invalid layout param in a `LinearLayout`: `layout_above`" message="Invalid layout param in a `LinearLayout`: `layout_above`"
@ -230,9 +208,9 @@
errorLine1=" a:background=&quot;?android:attr/selectableItemBackground&quot;" errorLine1=" a:background=&quot;?android:attr/selectableItemBackground&quot;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/layout/select_folder_header.xml" file="src/main/res/drawable/ic_baseline_info_24.xml"
line="11" line="1"
column="5"/> column="1"/>
</issue> </issue>
<issue <issue
@ -264,7 +242,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="112" line="114"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -323,7 +301,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="126" line="128"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -382,7 +360,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="131" line="133"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -441,7 +419,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="132" line="134"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -500,7 +478,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="133" line="135"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -559,7 +537,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="134" line="136"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -618,7 +596,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="139" line="141"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -677,7 +655,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="145" line="147"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
@ -736,55 +714,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="158" line="159"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
line="141"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="140" line="140"
column="13"/> column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="139"
column="13"/>
<location <location
file="src/main/res/values-es/strings.xml" file="src/main/res/values-es/strings.xml"
line="156" line="155"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-fr/strings.xml" file="src/main/res/values-fr/strings.xml"
line="153" line="152"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-hu/strings.xml" file="src/main/res/values-hu/strings.xml"
line="151" line="150"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-it/strings.xml" file="src/main/res/values-it/strings.xml"
line="137" line="136"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-nl/strings.xml" file="src/main/res/values-nl/strings.xml"
line="156" line="155"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pl/strings.xml" file="src/main/res/values-pl/strings.xml"
line="139" line="138"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt/strings.xml" file="src/main/res/values-pt/strings.xml"
line="139" line="138"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt-rBR/strings.xml" file="src/main/res/values-pt-rBR/strings.xml"
line="153" line="152"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-ru/strings.xml" file="src/main/res/values-ru/strings.xml"
line="153" line="152"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-zh-rCN/strings.xml" file="src/main/res/values-zh-rCN/strings.xml"
line="152" line="151"
column="13"/> column="13"/>
</issue> </issue>
@ -795,7 +773,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="159" line="160"
column="13"/> column="13"/>
</issue> </issue>
@ -806,7 +784,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="160" line="161"
column="13"/> column="13"/>
</issue> </issue>
@ -817,55 +795,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="176" line="177"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
line="157"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="156" line="156"
column="13"/> column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="155"
column="13"/>
<location <location
file="src/main/res/values-es/strings.xml" file="src/main/res/values-es/strings.xml"
line="172" line="171"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-fr/strings.xml" file="src/main/res/values-fr/strings.xml"
line="169" line="168"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-hu/strings.xml" file="src/main/res/values-hu/strings.xml"
line="167" line="166"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-it/strings.xml" file="src/main/res/values-it/strings.xml"
line="153" line="152"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-nl/strings.xml" file="src/main/res/values-nl/strings.xml"
line="172" line="171"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pl/strings.xml" file="src/main/res/values-pl/strings.xml"
line="155" line="154"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt/strings.xml" file="src/main/res/values-pt/strings.xml"
line="155" line="154"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt-rBR/strings.xml" file="src/main/res/values-pt-rBR/strings.xml"
line="169" line="168"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-ru/strings.xml" file="src/main/res/values-ru/strings.xml"
line="169" line="168"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-zh-rCN/strings.xml" file="src/main/res/values-zh-rCN/strings.xml"
line="168" line="167"
column="13"/> column="13"/>
</issue> </issue>
@ -876,55 +854,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="228" line="229"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
line="209"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="208" line="208"
column="13"/> column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="207"
column="13"/>
<location <location
file="src/main/res/values-es/strings.xml" file="src/main/res/values-es/strings.xml"
line="224" line="223"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-fr/strings.xml" file="src/main/res/values-fr/strings.xml"
line="221" line="220"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-hu/strings.xml" file="src/main/res/values-hu/strings.xml"
line="219" line="218"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-it/strings.xml" file="src/main/res/values-it/strings.xml"
line="204" line="203"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-nl/strings.xml" file="src/main/res/values-nl/strings.xml"
line="224" line="223"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pl/strings.xml" file="src/main/res/values-pl/strings.xml"
line="207" line="206"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt/strings.xml" file="src/main/res/values-pt/strings.xml"
line="207" line="206"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt-rBR/strings.xml" file="src/main/res/values-pt-rBR/strings.xml"
line="221" line="220"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-ru/strings.xml" file="src/main/res/values-ru/strings.xml"
line="221" line="220"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-zh-rCN/strings.xml" file="src/main/res/values-zh-rCN/strings.xml"
line="218" line="217"
column="13"/> column="13"/>
</issue> </issue>
@ -935,55 +913,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="297" line="298"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
line="274"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="273" line="273"
column="13"/> column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="272"
column="13"/>
<location <location
file="src/main/res/values-es/strings.xml" file="src/main/res/values-es/strings.xml"
line="293" line="292"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-fr/strings.xml" file="src/main/res/values-fr/strings.xml"
line="288" line="287"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-hu/strings.xml" file="src/main/res/values-hu/strings.xml"
line="286" line="285"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-it/strings.xml" file="src/main/res/values-it/strings.xml"
line="267" line="266"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-nl/strings.xml" file="src/main/res/values-nl/strings.xml"
line="293" line="292"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pl/strings.xml" file="src/main/res/values-pl/strings.xml"
line="272" line="271"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt/strings.xml" file="src/main/res/values-pt/strings.xml"
line="272" line="271"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt-rBR/strings.xml" file="src/main/res/values-pt-rBR/strings.xml"
line="290" line="289"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-ru/strings.xml" file="src/main/res/values-ru/strings.xml"
line="288" line="287"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-zh-rCN/strings.xml" file="src/main/res/values-zh-rCN/strings.xml"
line="286" line="285"
column="13"/> column="13"/>
</issue> </issue>
@ -994,51 +972,51 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="300" line="301"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
line="277"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="276" line="276"
column="13"/> column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="275"
column="13"/>
<location <location
file="src/main/res/values-es/strings.xml" file="src/main/res/values-es/strings.xml"
line="296" line="295"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-fr/strings.xml" file="src/main/res/values-fr/strings.xml"
line="291" line="290"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-hu/strings.xml" file="src/main/res/values-hu/strings.xml"
line="289" line="288"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-it/strings.xml" file="src/main/res/values-it/strings.xml"
line="270" line="269"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-nl/strings.xml" file="src/main/res/values-nl/strings.xml"
line="296" line="295"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pl/strings.xml" file="src/main/res/values-pl/strings.xml"
line="275" line="274"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt/strings.xml" file="src/main/res/values-pt/strings.xml"
line="275" line="274"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-pt-rBR/strings.xml" file="src/main/res/values-pt-rBR/strings.xml"
line="293" line="292"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-ru/strings.xml" file="src/main/res/values-ru/strings.xml"
line="291" line="290"
column="13"/> column="13"/>
<location <location
file="src/main/res/values-zh-rCN/strings.xml" file="src/main/res/values-zh-rCN/strings.xml"
@ -1053,7 +1031,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="397" line="387"
column="13"/> column="13"/>
</issue> </issue>
@ -1064,47 +1042,47 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location <location
file="src/main/res/values/strings.xml" file="src/main/res/values/strings.xml"
line="476" line="470"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-cs/strings.xml" file="src/main/res/values-cs/strings.xml"
line="448" line="436"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-es/strings.xml" file="src/main/res/values-es/strings.xml"
line="470" line="458"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-fr/strings.xml" file="src/main/res/values-fr/strings.xml"
line="459" line="447"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-hu/strings.xml" file="src/main/res/values-hu/strings.xml"
line="454" line="442"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-nl/strings.xml" file="src/main/res/values-nl/strings.xml"
line="470" line="458"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-pl/strings.xml" file="src/main/res/values-pl/strings.xml"
line="401" line="389"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-pt/strings.xml" file="src/main/res/values-pt/strings.xml"
line="388" line="376"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-pt-rBR/strings.xml" file="src/main/res/values-pt-rBR/strings.xml"
line="463" line="451"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-ru/strings.xml" file="src/main/res/values-ru/strings.xml"
line="471" line="459"
column="14"/> column="14"/>
<location <location
file="src/main/res/values-zh-rCN/strings.xml" file="src/main/res/values-zh-rCN/strings.xml"
line="452" line="440"
column="14"/> column="14"/>
</issue> </issue>
@ -1194,17 +1172,6 @@
column="4"/> column="4"/>
</issue> </issue>
<issue
id="ViewConstructor"
message="Custom view `AlbumView` is missing constructor used by tools: `(Context)` or `(Context,AttributeSet)` or `(Context,AttributeSet,int)`"
errorLine1="public class AlbumView extends UpdateView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/java/org/moire/ultrasonic/view/AlbumView.java"
line="40"
column="14"/>
</issue>
<issue <issue
id="ClickableViewAccessibility" id="ClickableViewAccessibility"
message="Custom view ``AutoRepeatButton`` has `setOnTouchListener` called on it but does not override `performClick`" message="Custom view ``AutoRepeatButton`` has `setOnTouchListener` called on it but does not override `performClick`"
@ -1216,149 +1183,6 @@
column="3"/> column="3"/>
</issue> </issue>
<issue
id="ClickableViewAccessibility"
message="`onTouch` lambda should call `View#performClick` when a click is detected"
errorLine1=" getView().setOnTouchListener((v, event) -> handleOnTouch(event));"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/java/org/moire/ultrasonic/fragment/NowPlayingFragment.java"
line="133"
column="42"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="9"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="18"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="27"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="36"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="45"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="54"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="63"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="72"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_buttons.xml"
line="81"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_list_item.xml"
line="61"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_list_item_legacy.xml"
line="8"
column="6"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/album_list_item_legacy.xml"
line="41"
column="6"/>
</issue>
<issue <issue
id="ContentDescription" id="ContentDescription"
message="Missing `contentDescription` attribute on image" message="Missing `contentDescription` attribute on image"
@ -1568,116 +1392,6 @@
column="6"/> column="6"/>
</issue> </issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/current_playing.xml"
line="45"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout-land/current_playing.xml"
line="46"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/current_playing.xml"
line="57"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout-land/current_playing.xml"
line="58"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/current_playing.xml"
line="69"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout-land/current_playing.xml"
line="70"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/current_playing.xml"
line="81"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout-land/current_playing.xml"
line="82"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/current_playing.xml"
line="93"
column="22"/>
</issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout-land/current_playing.xml"
line="94"
column="22"/>
</issue>
<issue <issue
id="ContentDescription" id="ContentDescription"
message="Missing `contentDescription` attribute on image" message="Missing `contentDescription` attribute on image"
@ -1728,30 +1442,19 @@
errorLine1=" &lt;ImageView" errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~"> errorLine2=" ~~~~~~~~~">
<location <location
file="src/main/res/layout/select_folder_header.xml" file="src/main/res/layout/list_header_folder.xml"
line="15" line="15"
column="6"/> column="6"/>
</issue> </issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/song_list_item.xml"
line="9"
column="6"/>
</issue>
<issue <issue
id="ContentDescription" id="ContentDescription"
message="Missing `contentDescription` attribute on image" message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView" errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~"> errorLine2=" ~~~~~~~~~">
<location <location
file="src/main/res/layout/song_list_item.xml" file="src/main/res/layout/list_item_track.xml"
line="38" line="39"
column="10"/> column="10"/>
</issue> </issue>
@ -1761,8 +1464,8 @@
errorLine1=" &lt;ImageView" errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~"> errorLine2=" ~~~~~~~~~">
<location <location
file="src/main/res/layout/song_list_item.xml" file="src/main/res/layout/list_item_track.xml"
line="48" line="49"
column="10"/> column="10"/>
</issue> </issue>
@ -1772,8 +1475,8 @@
errorLine1=" &lt;ImageView" errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~"> errorLine2=" ~~~~~~~~~">
<location <location
file="src/main/res/layout/song_list_item.xml" file="src/main/res/layout/list_item_track.xml"
line="58" line="59"
column="10"/> column="10"/>
</issue> </issue>
@ -1783,8 +1486,8 @@
errorLine1=" &lt;ImageView" errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~"> errorLine2=" ~~~~~~~~~">
<location <location
file="src/main/res/layout/song_list_item.xml" file="src/main/res/layout/list_item_track.xml"
line="68" line="69"
column="10"/> column="10"/>
</issue> </issue>
@ -1794,22 +1497,11 @@
errorLine1=" &lt;ImageView" errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~"> errorLine2=" ~~~~~~~~~">
<location <location
file="src/main/res/layout/song_list_item.xml" file="src/main/res/layout/list_item_track.xml"
line="78" line="79"
column="10"/> column="10"/>
</issue> </issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/song_list_item.xml"
line="91"
column="6"/>
</issue>
<issue <issue
id="ContentDescription" id="ContentDescription"
message="Missing `contentDescription` attribute on image" message="Missing `contentDescription` attribute on image"
@ -1953,17 +1645,6 @@
column="17"/> column="17"/>
</issue> </issue>
<issue
id="HardcodedText"
message="Hardcoded string &quot;A&quot;, should use `@string` resource"
errorLine1=" a:text=&quot;A&quot;"
errorLine2=" ~~~~~~~~~~">
<location
file="src/main/res/layout/artist_list_item.xml"
line="20"
column="9"/>
</issue>
<issue <issue
id="HardcodedText" id="HardcodedText"
message="Hardcoded string &quot;0 dB&quot;, should use `@string` resource" message="Hardcoded string &quot;0 dB&quot;, should use `@string` resource"
@ -1975,28 +1656,6 @@
column="13"/> column="13"/>
</issue> </issue>
<issue
id="HardcodedText"
message="Hardcoded string &quot;0 / 0&quot;, should use `@string` resource"
errorLine1=" a:text=&quot;0 / 0&quot;"
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="src/main/res/layout/player_media_info.xml"
line="64"
column="13"/>
</issue>
<issue
id="HardcodedText"
message="Hardcoded string &quot;Share&quot;, should use `@string` resource"
errorLine1=" a:title=&quot;Share&quot;/>"
errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="src/main/res/menu/select_song_context.xml"
line="24"
column="9"/>
</issue>
<issue <issue
id="HardcodedText" id="HardcodedText"
message="Hardcoded string &quot;http://&quot;, should use `@string` resource" message="Hardcoded string &quot;http://&quot;, should use `@string` resource"
@ -2015,7 +1674,7 @@
errorLine2=" ~~~~~~~~~~~~"> errorLine2=" ~~~~~~~~~~~~">
<location <location
file="src/main/res/layout/player_media_info.xml" file="src/main/res/layout/player_media_info.xml"
line="50" line="52"
column="6"/> column="6"/>
</issue> </issue>

View File

@ -19,8 +19,6 @@
package org.moire.ultrasonic.view; package org.moire.ultrasonic.view;
import android.content.Context; import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -28,6 +26,9 @@ import android.widget.ArrayAdapter;
import android.widget.SectionIndexer; import android.widget.SectionIndexer;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.moire.ultrasonic.R; import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.Artist; import org.moire.ultrasonic.domain.Artist;
@ -49,7 +50,7 @@ public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexe
public ArtistAdapter(Context context, List<Artist> artists) public ArtistAdapter(Context context, List<Artist> artists)
{ {
super(context, R.layout.generic_text_list_item, artists); super(context, R.layout.list_item_generic, artists);
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@ -81,7 +82,7 @@ public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexe
) { ) {
View rowView = convertView; View rowView = convertView;
if (rowView == null) { if (rowView == null) {
rowView = layoutInflater.inflate(R.layout.generic_text_list_item, parent, false); rowView = layoutInflater.inflate(R.layout.list_item_generic, parent, false);
} }
((TextView) rowView).setText(getItem(position).getName()); ((TextView) rowView).setText(getItem(position).getName());

View File

@ -48,7 +48,7 @@ public class GenreAdapter extends ArrayAdapter<Genre> implements SectionIndexer
public GenreAdapter(Context context, List<Genre> genres) public GenreAdapter(Context context, List<Genre> genres)
{ {
super(context, R.layout.generic_text_list_item, genres); super(context, R.layout.list_item_generic, genres);
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@ -75,7 +75,7 @@ public class GenreAdapter extends ArrayAdapter<Genre> implements SectionIndexer
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View rowView = convertView; View rowView = convertView;
if (rowView == null) { if (rowView == null) {
rowView = layoutInflater.inflate(R.layout.generic_text_list_item, parent, false); rowView = layoutInflater.inflate(R.layout.list_item_generic, parent, false);
} }
((TextView) rowView).setText(getItem(position).getName()); ((TextView) rowView).setText(getItem(position).getName());

View File

@ -43,15 +43,15 @@ class AlbumRowBinder(
Util.getDrawableFromAttribute(context, R.attr.star_hollow) Util.getDrawableFromAttribute(context, R.attr.star_hollow)
// Set our layout files // Set our layout files
val layout = R.layout.album_list_item val layout = R.layout.list_item_album
val contextMenuLayout = R.menu.artist_context_menu val contextMenuLayout = R.menu.context_menu_artist
override fun onBindViewHolder(holder: ViewHolder, item: MusicDirectory.Album) { override fun onBindViewHolder(holder: ViewHolder, item: MusicDirectory.Album) {
holder.album.text = item.title holder.album.text = item.title
holder.artist.text = item.artist holder.artist.text = item.artist
holder.details.setOnClickListener { onItemClick(item) } holder.details.setOnClickListener { onItemClick(item) }
holder.details.setOnLongClickListener { holder.details.setOnLongClickListener {
val popup = Helper.createPopupMenu(holder.itemView) val popup = Utils.createPopupMenu(holder.itemView)
popup.setOnMenuItemClickListener { menuItem -> popup.setOnMenuItemClickListener { menuItem ->
onContextMenuClick(menuItem, item) onContextMenuClick(menuItem, item)
@ -78,7 +78,7 @@ class AlbumRowBinder(
var album: TextView = view.findViewById(R.id.album_title) var album: TextView = view.findViewById(R.id.album_title)
var artist: TextView = view.findViewById(R.id.album_artist) var artist: TextView = view.findViewById(R.id.album_artist)
var details: LinearLayout = view.findViewById(R.id.row_album_details) var details: LinearLayout = view.findViewById(R.id.row_album_details)
var coverArt: ImageView = view.findViewById(R.id.album_coverart) var coverArt: ImageView = view.findViewById(R.id.coverart)
var star: ImageView = view.findViewById(R.id.album_star) var star: ImageView = view.findViewById(R.id.album_star)
var coverArtId: String? = null var coverArtId: String? = null
} }

View File

@ -26,7 +26,6 @@ import org.moire.ultrasonic.util.Settings
/** /**
* Creates a Row in a RecyclerView which contains the details of an Artist * Creates a Row in a RecyclerView which contains the details of an Artist
* FIXME: On click wrong display...
*/ */
class ArtistRowBinder( class ArtistRowBinder(
val onItemClick: (ArtistOrIndex) -> Unit, val onItemClick: (ArtistOrIndex) -> Unit,
@ -35,8 +34,8 @@ class ArtistRowBinder(
private val enableSections: Boolean = true private val enableSections: Boolean = true
) : ItemViewBinder<ArtistOrIndex, ArtistRowBinder.ViewHolder>(), KoinComponent { ) : ItemViewBinder<ArtistOrIndex, ArtistRowBinder.ViewHolder>(), KoinComponent {
val layout = R.layout.artist_list_item val layout = R.layout.list_item_artist
val contextMenuLayout = R.menu.artist_context_menu val contextMenuLayout = R.menu.context_menu_artist
override fun onBindViewHolder(holder: ViewHolder, item: ArtistOrIndex) { override fun onBindViewHolder(holder: ViewHolder, item: ArtistOrIndex) {
holder.textView.text = item.name holder.textView.text = item.name
@ -44,7 +43,7 @@ class ArtistRowBinder(
holder.section.isVisible = enableSections holder.section.isVisible = enableSections
holder.layout.setOnClickListener { onItemClick(item) } holder.layout.setOnClickListener { onItemClick(item) }
holder.layout.setOnLongClickListener { holder.layout.setOnLongClickListener {
val popup = Helper.createPopupMenu(holder.itemView) val popup = Utils.createPopupMenu(holder.itemView, contextMenuLayout)
popup.setOnMenuItemClickListener { menuItem -> popup.setOnMenuItemClickListener { menuItem ->
onContextMenuClick(menuItem, item) onContextMenuClick(menuItem, item)
@ -106,8 +105,8 @@ class ArtistRowBinder(
) : RecyclerView.ViewHolder(itemView) { ) : RecyclerView.ViewHolder(itemView) {
var section: TextView = itemView.findViewById(R.id.row_section) var section: TextView = itemView.findViewById(R.id.row_section)
var textView: TextView = itemView.findViewById(R.id.row_artist_name) var textView: TextView = itemView.findViewById(R.id.row_artist_name)
var layout: RelativeLayout = itemView.findViewById(R.id.row_artist_layout) var layout: RelativeLayout = itemView.findViewById(R.id.containing_layout)
var coverArt: ImageView = itemView.findViewById(R.id.artist_coverart) var coverArt: ImageView = itemView.findViewById(R.id.coverart)
var coverArtId: String? = null var coverArtId: String? = null
} }

View File

@ -22,7 +22,7 @@ import org.moire.ultrasonic.util.BoundedTreeSet
* The BaseAdapter which extends the MultiTypeAdapter from an external library. * The BaseAdapter which extends the MultiTypeAdapter from an external library.
* It provides selection support as well as Diffing the submitted lists for performance. * It provides selection support as well as Diffing the submitted lists for performance.
* *
* It should be kept generic enought that it can be used a Base for all lists in the app. * It should be kept generic enough that it can be used a Base for all lists in the app.
*/ */
class BaseAdapter<T : Identifiable> : MultiTypeAdapter() { class BaseAdapter<T : Identifiable> : MultiTypeAdapter() {

View File

@ -15,7 +15,7 @@ import org.moire.ultrasonic.domain.Identifiable
class DividerBinder : ItemViewBinder<DividerBinder.Divider, DividerBinder.ViewHolder>() { class DividerBinder : ItemViewBinder<DividerBinder.Divider, DividerBinder.ViewHolder>() {
// Set our layout files // Set our layout files
val layout = R.layout.row_divider val layout = R.layout.list_item_divider
override fun onBindViewHolder(holder: ViewHolder, item: Divider) { override fun onBindViewHolder(holder: ViewHolder, item: Divider) {
// Set text // Set text

View File

@ -29,7 +29,7 @@ class FolderSelectorBinder(context: Context) :
private val weakContext: WeakReference<Context> = WeakReference(context) private val weakContext: WeakReference<Context> = WeakReference(context)
// Set our layout files // Set our layout files
val layout = R.layout.select_album_header val layout = R.layout.list_header_folder
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder { override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
return ViewHolder(inflater.inflate(layout, parent, false), weakContext) return ViewHolder(inflater.inflate(layout, parent, false), weakContext)

View File

@ -30,7 +30,7 @@ class HeaderViewBinder(
private val imageLoaderProvider: ImageLoaderProvider by inject() private val imageLoaderProvider: ImageLoaderProvider by inject()
// Set our layout files // Set our layout files
val layout = R.layout.select_album_header val layout = R.layout.list_header_album
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder { override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {
return ViewHolder(inflater.inflate(layout, parent, false)) return ViewHolder(inflater.inflate(layout, parent, false))

View File

@ -1,22 +0,0 @@
package org.moire.ultrasonic.adapters
import android.view.MenuInflater
import android.view.View
import android.widget.PopupMenu
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider
object Helper {
@JvmStatic
fun createPopupMenu(view: View, layout: Int = R.menu.artist_context_menu): PopupMenu {
val popup = PopupMenu(view.context, view)
val inflater: MenuInflater = popup.menuInflater
inflater.inflate(layout, popup.menu)
val downloadMenuItem = popup.menu.findItem(R.id.menu_download)
downloadMenuItem?.isVisible = !ActiveServerProvider.isOffline()
popup.show()
return popup
}
}

View File

@ -1,47 +1,2 @@
package org.moire.ultrasonic.adapters package org.moire.ultrasonic.adapters
import android.content.Context
import android.graphics.drawable.Drawable
import org.moire.ultrasonic.R
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
/**
* Provides cached drawables for the UI
*/
class ImageHelper(context: Context) {
lateinit var errorImage: Drawable
lateinit var starHollowDrawable: Drawable
lateinit var starDrawable: Drawable
lateinit var pinImage: Drawable
lateinit var downloadedImage: Drawable
lateinit var downloadingImage: Drawable
lateinit var playingImage: Drawable
var theme: String
fun rebuild(context: Context, force: Boolean = false) {
val currentTheme = Settings.theme
val themesMatch = theme == currentTheme
if (!themesMatch) theme = currentTheme
if (!themesMatch || force) {
getDrawables(context)
}
}
init {
theme = Settings.theme
getDrawables(context)
}
private fun getDrawables(context: Context) {
starHollowDrawable = Util.getDrawableFromAttribute(context, R.attr.star_hollow)
starDrawable = Util.getDrawableFromAttribute(context, R.attr.star_full)
pinImage = Util.getDrawableFromAttribute(context, R.attr.pin)
downloadedImage = Util.getDrawableFromAttribute(context, R.attr.downloaded)
errorImage = Util.getDrawableFromAttribute(context, R.attr.error)
downloadingImage = Util.getDrawableFromAttribute(context, R.attr.downloading)
playingImage = Util.getDrawableFromAttribute(context, R.attr.media_play_small)
}
}

View File

@ -2,7 +2,7 @@ package org.moire.ultrasonic.adapters
import android.content.Context import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.MenuItem
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import com.drakeet.multitype.ItemViewBinder import com.drakeet.multitype.ItemViewBinder
@ -15,24 +15,26 @@ import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.Downloader import org.moire.ultrasonic.service.Downloader
class TrackViewBinder( class TrackViewBinder(
val onItemClick: (DownloadFile) -> Unit,
val onContextMenuClick: ((MenuItem, DownloadFile) -> Boolean)? = null,
val checkable: Boolean, val checkable: Boolean,
val draggable: Boolean, val draggable: Boolean,
context: Context, context: Context,
val lifecycleOwner: LifecycleOwner, val lifecycleOwner: LifecycleOwner,
private val onClickCallback: ((View, DownloadFile?) -> Unit)? = null
) : ItemViewBinder<Identifiable, TrackViewHolder>(), KoinComponent { ) : ItemViewBinder<Identifiable, TrackViewHolder>(), KoinComponent {
// Set our layout files // Set our layout files
val layout = R.layout.song_list_item val layout = R.layout.list_item_track
val contextMenuLayout = R.menu.artist_context_menu val contextMenuLayout = R.menu.context_menu_track
private val downloader: Downloader by inject() private val downloader: Downloader by inject()
private val imageHelper: ImageHelper = ImageHelper(context) private val imageHelper: Utils.ImageHelper = Utils.ImageHelper(context)
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): TrackViewHolder { override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): TrackViewHolder {
return TrackViewHolder(inflater.inflate(layout, parent, false)) return TrackViewHolder(inflater.inflate(layout, parent, false))
} }
@Suppress("LongMethod")
override fun onBindViewHolder(holder: TrackViewHolder, item: Identifiable) { override fun onBindViewHolder(holder: TrackViewHolder, item: Identifiable) {
val downloadFile: DownloadFile? val downloadFile: DownloadFile?
val diffAdapter = adapter as BaseAdapter<*> val diffAdapter = adapter as BaseAdapter<*>
@ -58,6 +60,32 @@ class TrackViewBinder(
diffAdapter.isSelected(item.longId) diffAdapter.isSelected(item.longId)
) )
holder.itemView.setOnLongClickListener {
if (onContextMenuClick != null) {
val popup = Utils.createPopupMenu(holder.itemView, contextMenuLayout)
popup.setOnMenuItemClickListener { menuItem ->
onContextMenuClick?.invoke(menuItem, downloadFile)
}
} else {
// Minimize or maximize the Text view (if song title is very long)
if (!downloadFile.song.isDirectory) {
holder.maximizeOrMinimize()
}
}
true
}
holder.itemView.setOnClickListener {
if (!checkable) {
onItemClick(downloadFile)
} else {
val nowChecked = !holder.check.isChecked
holder.isChecked = nowChecked
}
}
// Notify the adapter of selection changes // Notify the adapter of selection changes
holder.observableChecked.observe( holder.observableChecked.observe(
lifecycleOwner, lifecycleOwner,
@ -95,7 +123,5 @@ class TrackViewBinder(
holder.updateProgress(it) holder.updateProgress(it)
} }
) )
holder.itemClickListener = onClickCallback
} }
} }

View File

@ -7,6 +7,7 @@ import android.widget.Checkable
import android.widget.CheckedTextView import android.widget.CheckedTextView
import android.widget.ImageView import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@ -29,6 +30,7 @@ import timber.log.Timber
/** /**
* Used to display songs and videos in a `ListView`. * Used to display songs and videos in a `ListView`.
* FIXME: Add video List item * FIXME: Add video List item
* FIXME: CHECKED bug
*/ */
class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable, KoinComponent { class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable, KoinComponent {
@ -47,8 +49,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
var duration: TextView = view.findViewById(R.id.song_duration) var duration: TextView = view.findViewById(R.id.song_duration)
var progress: TextView = view.findViewById(R.id.song_status) var progress: TextView = view.findViewById(R.id.song_status)
var itemClickListener: ((View, DownloadFile?) -> Unit)? = null
var entry: MusicDirectory.Entry? = null var entry: MusicDirectory.Entry? = null
private set private set
var downloadFile: DownloadFile? = null var downloadFile: DownloadFile? = null
@ -66,18 +66,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
features.isFeatureEnabled(Feature.FIVE_STAR_RATING) features.isFeatureEnabled(Feature.FIVE_STAR_RATING)
} }
lateinit var imageHelper: ImageHelper lateinit var imageHelper: Utils.ImageHelper
init {
itemView.setOnClickListener {
if (itemClickListener != null) {
itemClickListener?.invoke(it, downloadFile)
} else {
val nowChecked = !check.isChecked
isChecked = nowChecked
}
}
}
fun setSong( fun setSong(
file: DownloadFile, file: DownloadFile,
@ -85,7 +74,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
draggable: Boolean, draggable: Boolean,
isSelected: Boolean = false isSelected: Boolean = false
) { ) {
Timber.e("BINDING %s", isSelected)
val song = file.song val song = file.song
downloadFile = file downloadFile = file
entry = song entry = song
@ -125,15 +113,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
RxBus.playerStateObservable.subscribe { RxBus.playerStateObservable.subscribe {
setPlayIcon(it.track == downloadFile) setPlayIcon(it.track == downloadFile)
} }
// Minimize or maximize the Text view (if song title is very long)
itemView.setOnLongClickListener {
if (!song.isDirectory) {
maximizeOrMinimize()
true
}
false
}
} }
private fun setPlayIcon(isPlaying: Boolean) { private fun setPlayIcon(isPlaying: Boolean) {

View File

@ -0,0 +1,72 @@
package org.moire.ultrasonic.adapters
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.MenuInflater
import android.view.View
import android.widget.PopupMenu
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
object Utils {
@JvmStatic
fun createPopupMenu(view: View, layout: Int = R.menu.context_menu_artist): PopupMenu {
val popup = PopupMenu(view.context, view)
val inflater: MenuInflater = popup.menuInflater
inflater.inflate(layout, popup.menu)
val downloadMenuItem = popup.menu.findItem(R.id.menu_download)
downloadMenuItem?.isVisible = !ActiveServerProvider.isOffline()
var shareButton = popup.menu.findItem(R.id.menu_item_share)
shareButton?.isVisible = !ActiveServerProvider.isOffline()
shareButton = popup.menu.findItem(R.id.song_menu_share)
shareButton?.isVisible = !ActiveServerProvider.isOffline()
popup.show()
return popup
}
/**
* Provides cached drawables for the UI
*/
class ImageHelper(context: Context) {
lateinit var errorImage: Drawable
lateinit var starHollowDrawable: Drawable
lateinit var starDrawable: Drawable
lateinit var pinImage: Drawable
lateinit var downloadedImage: Drawable
lateinit var downloadingImage: Drawable
lateinit var playingImage: Drawable
var theme: String
fun rebuild(context: Context, force: Boolean = false) {
val currentTheme = Settings.theme
val themesMatch = theme == currentTheme
if (!themesMatch) theme = currentTheme
if (!themesMatch || force) {
getDrawables(context)
}
}
init {
theme = Settings.theme
getDrawables(context)
}
private fun getDrawables(context: Context) {
starHollowDrawable = Util.getDrawableFromAttribute(context, R.attr.star_hollow)
starDrawable = Util.getDrawableFromAttribute(context, R.attr.star_full)
pinImage = Util.getDrawableFromAttribute(context, R.attr.pin)
downloadedImage = Util.getDrawableFromAttribute(context, R.attr.downloaded)
errorImage = Util.getDrawableFromAttribute(context, R.attr.error)
downloadingImage = Util.getDrawableFromAttribute(context, R.attr.downloading)
playingImage = Util.getDrawableFromAttribute(context, R.attr.media_play_small)
}
}
}

View File

@ -1,3 +1,10 @@
/*
* AlbumListFragment.kt
* Copyright (C) 2009-2021 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.fragment package org.moire.ultrasonic.fragment
import android.os.Bundle import android.os.Bundle
@ -26,13 +33,7 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Album>() {
/** /**
* The id of the main layout * The id of the main layout
*/ */
override val mainLayout: Int = R.layout.generic_list override val mainLayout: Int = R.layout.list_layout_generic
/**
* The id of the target in the navigation graph where we should go,
* after the user has clicked on an item
*/
override val itemClickTarget: Int = R.id.trackCollectionFragment
/** /**
* The central function to pass a query to the model and return a LiveData object * The central function to pass a query to the model and return a LiveData object
@ -71,6 +72,8 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Album>() {
context = requireContext() context = requireContext()
) )
) )
emptyTextView.setText(R.string.select_album_empty)
} }
override fun onItemClick(item: MusicDirectory.Album) { override fun onItemClick(item: MusicDirectory.Album) {
@ -79,6 +82,6 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Album>() {
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, item.isDirectory) bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, item.isDirectory)
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, item.title) bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, item.title)
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.parent) bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.parent)
findNavController().navigate(itemClickTarget, bundle) findNavController().navigate(R.id.trackCollectionFragment, bundle)
} }
} }

View File

@ -25,13 +25,7 @@ class ArtistListFragment : EntryListFragment<ArtistOrIndex>() {
/** /**
* The id of the main layout * The id of the main layout
*/ */
override val mainLayout = R.layout.generic_list override val mainLayout = R.layout.list_layout_generic
/**
* The id of the target in the navigation graph where we should go,
* after the user has clicked on an item
*/
override val itemClickTarget = R.id.selectArtistToSelectAlbum
/** /**
* The central function to pass a query to the model and return a LiveData object * The central function to pass a query to the model and return a LiveData object
@ -63,6 +57,6 @@ class ArtistListFragment : EntryListFragment<ArtistOrIndex>() {
bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, item.name) bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, item.name)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 1000) bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 1000)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0) bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0)
findNavController().navigate(itemClickTarget, bundle) findNavController().navigate(R.id.selectArtistToSelectAlbum, bundle)
} }
} }

View File

@ -25,7 +25,6 @@ import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
* *
* Therefore this fragment allows only for singular selection and playback. * Therefore this fragment allows only for singular selection and playback.
* *
* FIXME: use restore for playback
*/ */
class BookmarksFragment : TrackCollectionFragment() { class BookmarksFragment : TrackCollectionFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@ -17,6 +17,7 @@ import androidx.lifecycle.LiveData
import org.koin.core.component.inject import org.koin.core.component.inject
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.adapters.TrackViewBinder import org.moire.ultrasonic.adapters.TrackViewBinder
import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.model.GenericListModel import org.moire.ultrasonic.model.GenericListModel
import org.moire.ultrasonic.service.DownloadFile import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.Downloader import org.moire.ultrasonic.service.Downloader
@ -26,8 +27,10 @@ import org.moire.ultrasonic.util.Util
* Displays currently running downloads. * Displays currently running downloads.
* For now its a read-only view, there are no manipulations of the download list possible. * For now its a read-only view, there are no manipulations of the download list possible.
* *
* A consideration would be to base this class on TrackCollectionFragment and thereby inheriting the * TODO: A consideration would be to base this class on TrackCollectionFragment and thereby inheriting the
* buttons useful to manipulate the list. * buttons useful to manipulate the list.
*
* TODO: Add code to enable manipulation of the download list
*/ */
class DownloadsFragment : MultiListFragment<DownloadFile>() { class DownloadsFragment : MultiListFragment<DownloadFile>() {
@ -36,13 +39,6 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
*/ */
override val listModel: DownloadListModel by viewModels() override val listModel: DownloadListModel by viewModels()
/**
* The id of the target in the navigation graph where we should go,
* after the user has clicked on an item
*/
// FIXME
override val itemClickTarget: Int = R.id.trackCollectionFragment
/** /**
* The central function to pass a query to the model and return a LiveData object * The central function to pass a query to the model and return a LiveData object
*/ */
@ -50,15 +46,6 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
return listModel.getList() return listModel.getList()
} }
override fun onContextMenuItemSelected(menuItem: MenuItem, item: DownloadFile): Boolean {
// TODO: Add code to enable manipulation of the download list
return true
}
override fun onItemClick(item: DownloadFile) {
// TODO: Add code to enable manipulation of the download list
}
override fun setTitle(title: String?) { override fun setTitle(title: String?) {
FragmentTitle.setTitle(this, Util.appContext().getString(R.string.menu_downloads)) FragmentTitle.setTitle(this, Util.appContext().getString(R.string.menu_downloads))
} }
@ -68,6 +55,8 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
viewAdapter.register( viewAdapter.register(
TrackViewBinder( TrackViewBinder(
{ },
{ _,_ -> true },
checkable = false, checkable = false,
draggable = false, draggable = false,
context = requireContext(), context = requireContext(),
@ -82,6 +71,15 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
viewAdapter.submitList(liveDataList.value) viewAdapter.submitList(liveDataList.value)
} }
override fun onContextMenuItemSelected(menuItem: MenuItem, item: DownloadFile): Boolean {
// TODO: Add code to enable manipulation of the download list
return true
}
override fun onItemClick(item: DownloadFile) {
// TODO: Add code to enable manipulation of the download list
}
} }
class DownloadListModel(application: Application) : GenericListModel(application) { class DownloadListModel(application: Application) : GenericListModel(application) {

View File

@ -3,6 +3,7 @@ package org.moire.ultrasonic.fragment
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.Artist import org.moire.ultrasonic.domain.Artist
@ -11,7 +12,6 @@ import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.service.RxBus import org.moire.ultrasonic.service.RxBus
import org.moire.ultrasonic.subsonic.DownloadHandler import org.moire.ultrasonic.subsonic.DownloadHandler
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import androidx.fragment.app.Fragment
import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Settings
/** /**
@ -30,7 +30,6 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
!listModel.isOffline() && !Settings.shouldUseId3Tags !listModel.isOffline() && !Settings.shouldUseId3Tags
} }
override fun onContextMenuItemSelected(menuItem: MenuItem, item: T): Boolean { override fun onContextMenuItemSelected(menuItem: MenuItem, item: T): Boolean {
val isArtist = (item is Artist) val isArtist = (item is Artist)
@ -43,7 +42,7 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, item.name) bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, item.name)
bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.id) bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, item.id)
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, (item is Artist)) bundle.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, (item is Artist))
findNavController().navigate(itemClickTarget, bundle) findNavController().navigate(R.id.trackCollectionFragment, bundle)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -149,6 +148,7 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
unpin = false, unpin = false,
isArtist = isArtist isArtist = isArtist
) )
else -> return false
} }
return true return true
} }

View File

@ -76,16 +76,10 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
return MutableLiveData() return MutableLiveData()
} }
/**
* The id of the target in the navigation graph where we should go,
* after the user has clicked on an item
*/
protected abstract val itemClickTarget: Int
/** /**
* The id of the main layout * The id of the main layout
*/ */
open val mainLayout: Int = R.layout.generic_list open val mainLayout: Int = R.layout.list_layout_generic
/** /**
* The ids of the swipe refresh view, the recycler view and the empty text view * The ids of the swipe refresh view, the recycler view and the empty text view
@ -95,7 +89,6 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
open val emptyViewId = R.id.empty_list_view open val emptyViewId = R.id.empty_list_view
open val emptyTextId = R.id.empty_list_text open val emptyTextId = R.id.empty_list_text
open fun setTitle(title: String?) { open fun setTitle(title: String?) {
if (title == null) { if (title == null) {
FragmentTitle.setTitle( FragmentTitle.setTitle(

View File

@ -229,7 +229,7 @@ class PlayerFragment :
val ratingLinearLayout = view.findViewById<LinearLayout>(R.id.song_rating) val ratingLinearLayout = view.findViewById<LinearLayout>(R.id.song_rating)
if (!useFiveStarRating) ratingLinearLayout.isVisible = false if (!useFiveStarRating) ratingLinearLayout.isVisible = false
hollowStar = Util.getDrawableFromAttribute(view.context, R.attr.star_hollow) hollowStar = Util.getDrawableFromAttribute(view.context, R.attr.star_hollow)
fullStar = Util.getDrawableFromAttribute(context!!, R.attr.star_full) fullStar = Util.getDrawableFromAttribute(view.context, R.attr.star_full)
fiveStar1ImageView.setOnClickListener { setSongRating(1) } fiveStar1ImageView.setOnClickListener { setSongRating(1) }
fiveStar2ImageView.setOnClickListener { setSongRating(2) } fiveStar2ImageView.setOnClickListener { setSongRating(2) }
@ -561,14 +561,6 @@ class PlayerFragment :
} }
} }
override fun onContextItemSelected(menuItem: MenuItem): Boolean {
val info = menuItem.menuInfo as AdapterContextMenuInfo
val downloadFile = viewAdapter.getCurrentList()[info.position] as DownloadFile
return menuItemSelected(menuItem.itemId, downloadFile) || super.onContextItemSelected(
menuItem
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return menuItemSelected(item.itemId, null) || super.onOptionsItemSelected(item) return menuItemSelected(item.itemId, null) || super.onOptionsItemSelected(item)
} }
@ -856,7 +848,7 @@ class PlayerFragment :
} }
// Create listener // Create listener
val listener: ((View, DownloadFile?) -> Unit) = { _, file -> val listener: ((DownloadFile) -> Unit) = { file ->
val list = mediaPlayerController.playList val list = mediaPlayerController.playList
val index = list.indexOf(file) val index = list.indexOf(file)
mediaPlayerController.play(index) mediaPlayerController.play(index)
@ -866,11 +858,12 @@ class PlayerFragment :
viewAdapter.register( viewAdapter.register(
TrackViewBinder( TrackViewBinder(
onItemClick = listener,
onContextMenuClick = {_,_ -> true},
checkable = false, checkable = false,
draggable = true, draggable = true,
context = requireContext(), context = requireContext(),
lifecycleOwner = viewLifecycleOwner, lifecycleOwner = viewLifecycleOwner,
listener
) )
) )

View File

@ -3,20 +3,15 @@ package org.moire.ultrasonic.fragment
import android.app.SearchManager import android.app.SearchManager
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.ContextMenu
import android.view.ContextMenu.ContextMenuInfo
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.AdapterView.AdapterContextMenuInfo
import android.widget.ListAdapter import android.widget.ListAdapter
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation import androidx.navigation.Navigation
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
@ -34,6 +29,7 @@ import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.SearchResult import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
import org.moire.ultrasonic.model.SearchListModel import org.moire.ultrasonic.model.SearchListModel
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.MediaPlayerController import org.moire.ultrasonic.service.MediaPlayerController
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
import org.moire.ultrasonic.subsonic.ShareHandler import org.moire.ultrasonic.subsonic.ShareHandler
@ -48,6 +44,8 @@ import timber.log.Timber
/** /**
* Initiates a search on the media library and displays the results * Initiates a search on the media library and displays the results
*
* FIXME: Handle context click on song
*/ */
class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent { class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
private var moreArtistsButton: View? = null private var moreArtistsButton: View? = null
@ -107,18 +105,7 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
// expandSongs() // expandSongs()
// } else { // } else {
// val item = parent.getItemAtPosition(position) // val item = parent.getItemAtPosition(position)
// if (item is Artist) { //
// onArtistSelected(item)
// } else if (item is MusicDirectory.Entry) {
// val entry = item
// if (entry.isDirectory) {
// onAlbumSelected(entry, false)
// } else if (entry.isVideo) {
// onVideoSelected(entry)
// } else {
// onSongSelected(entry, true)
// }
// }
// } // }
// }) // })
@ -129,13 +116,8 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
// They need to be added in the order of most specific -> least specific. // They need to be added in the order of most specific -> least specific.
viewAdapter.register( viewAdapter.register(
ArtistRowBinder( ArtistRowBinder(
onItemClick = { entry -> onItemClick(entry) }, onItemClick = ::onItemClick,
onContextMenuClick = { menuItem, entry -> onContextMenuClick = ::onContextMenuItemSelected,
onContextMenuItemSelected(
menuItem,
entry
)
},
imageLoader = imageLoaderProvider.getImageLoader(), imageLoader = imageLoaderProvider.getImageLoader(),
enableSections = false enableSections = false
) )
@ -143,13 +125,8 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
viewAdapter.register( viewAdapter.register(
AlbumRowBinder( AlbumRowBinder(
onItemClick = { entry -> onItemClick(entry) }, onItemClick = ::onItemClick,
onContextMenuClick = { menuItem, entry -> onContextMenuClick = ::onContextMenuItemSelected,
onContextMenuItemSelected(
menuItem,
entry
)
},
imageLoader = imageLoaderProvider.getImageLoader(), imageLoader = imageLoaderProvider.getImageLoader(),
context = requireContext() context = requireContext()
) )
@ -157,6 +134,8 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
viewAdapter.register( viewAdapter.register(
TrackViewBinder( TrackViewBinder(
onItemClick = ::onItemClick,
onContextMenuClick = ::onContextMenuItemSelected,
checkable = false, checkable = false,
draggable = false, draggable = false,
context = requireContext(), context = requireContext(),
@ -193,7 +172,7 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
val arguments = arguments val arguments = arguments
val autoPlay = arguments != null && val autoPlay = arguments != null &&
arguments.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false) arguments.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false)
val query = arguments?.getString(Constants.INTENT_EXTRA_NAME_QUERY) val query = arguments?.getString(Constants.INTENT_EXTRA_NAME_QUERY)
// If started with a query, enter it to the searchView // If started with a query, enter it to the searchView
@ -236,200 +215,11 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
searchItem.expandActionView() searchItem.expandActionView()
} }
// FIXME
override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) {
super.onCreateContextMenu(menu, view, menuInfo)
if (activity == null) return
val info = menuInfo as AdapterContextMenuInfo?
// val selectedItem = list!!.getItemAtPosition(info!!.position)
// val isArtist = selectedItem is Artist
// val isAlbum = selectedItem is MusicDirectory.Entry && selectedItem.isDirectory
// val inflater = requireActivity().menuInflater
// if (!isArtist && !isAlbum) {
// inflater.inflate(R.menu.select_song_context, menu)
// } else {
// inflater.inflate(R.menu.generic_context_menu, menu)
// }
// val shareButton = menu.findItem(R.id.menu_item_share)
// val downloadMenuItem = menu.findItem(R.id.menu_download)
// if (downloadMenuItem != null) {
// downloadMenuItem.isVisible = !isOffline()
// }
// if (isOffline() || isArtist) {
// if (shareButton != null) {
// shareButton.isVisible = false
// }
// }
}
// FIXME
override fun onContextItemSelected(menuItem: MenuItem): Boolean {
val info = menuItem.menuInfo as AdapterContextMenuInfo
// val selectedItem = list!!.getItemAtPosition(info.position)
// val artist = if (selectedItem is Artist) selectedItem else null
// val entry = if (selectedItem is MusicDirectory.Entry) selectedItem else null
// var entryId: String? = null
// if (entry != null) {
// entryId = entry.id
// }
// val id = artist?.id ?: entryId ?: return true
// var songs: MutableList<MusicDirectory.Entry?> = ArrayList(1)
// val itemId = menuItem.itemId
// if (itemId == R.id.menu_play_now) {
// downloadHandler.downloadRecursively(
// this,
// id,
// false,
// false,
// true,
// false,
// false,
// false,
// false,
// false
// )
// } else if (itemId == R.id.menu_play_next) {
// downloadHandler.downloadRecursively(
// this,
// id,
// false,
// true,
// false,
// true,
// false,
// true,
// false,
// false
// )
// } else if (itemId == R.id.menu_play_last) {
// downloadHandler.downloadRecursively(
// this,
// id,
// false,
// true,
// false,
// false,
// false,
// false,
// false,
// false
// )
// } else if (itemId == R.id.menu_pin) {
// downloadHandler.downloadRecursively(
// this,
// id,
// true,
// true,
// false,
// false,
// false,
// false,
// false,
// false
// )
// } else if (itemId == R.id.menu_unpin) {
// downloadHandler.downloadRecursively(
// this,
// id,
// false,
// false,
// false,
// false,
// false,
// false,
// true,
// false
// )
// } else if (itemId == R.id.menu_download) {
// downloadHandler.downloadRecursively(
// this,
// id,
// false,
// false,
// false,
// false,
// true,
// false,
// false,
// false
// )
// } else if (itemId == R.id.song_menu_play_now) {
// if (entry != null) {
// songs = ArrayList(1)
// songs.add(entry)
// downloadHandler.download(this, false, false, true, false, false, songs)
// }
// } else if (itemId == R.id.song_menu_play_next) {
// if (entry != null) {
// songs = ArrayList(1)
// songs.add(entry)
// downloadHandler.download(this, true, false, false, true, false, songs)
// }
// } else if (itemId == R.id.song_menu_play_last) {
// if (entry != null) {
// songs = ArrayList(1)
// songs.add(entry)
// downloadHandler.download(this, true, false, false, false, false, songs)
// }
// } else if (itemId == R.id.song_menu_pin) {
// if (entry != null) {
// songs.add(entry)
// toast(
// context,
// resources.getQuantityString(
// R.plurals.select_album_n_songs_pinned,
// songs.size,
// songs.size
// )
// )
// downloadBackground(true, songs)
// }
// } else if (itemId == R.id.song_menu_download) {
// if (entry != null) {
// songs.add(entry)
// toast(
// context,
// resources.getQuantityString(
// R.plurals.select_album_n_songs_downloaded,
// songs.size,
// songs.size
// )
// )
// downloadBackground(false, songs)
// }
// } else if (itemId == R.id.song_menu_unpin) {
// if (entry != null) {
// songs.add(entry)
// toast(
// context,
// resources.getQuantityString(
// R.plurals.select_album_n_songs_unpinned,
// songs.size,
// songs.size
// )
// )
// mediaPlayerController.unpin(songs)
// }
// } else if (itemId == R.id.menu_item_share) {
// if (entry != null) {
// songs = ArrayList(1)
// songs.add(entry)
// shareHandler.createShare(this, songs, searchRefresh, cancellationToken!!)
// }
// return super.onContextItemSelected(menuItem)
// } else {
// return super.onContextItemSelected(menuItem)
// }
return true
}
// OK!
override fun onDestroyView() { override fun onDestroyView() {
cancellationToken?.cancel() cancellationToken?.cancel()
super.onDestroyView() super.onDestroyView()
} }
// OK!
private fun downloadBackground(save: Boolean, songs: List<MusicDirectory.Entry?>) { private fun downloadBackground(save: Boolean, songs: List<MusicDirectory.Entry?>) {
val onValid = Runnable { val onValid = Runnable {
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable() networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
@ -515,13 +305,13 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
// mergeAdapter!!.removeAdapter(moreSongsAdapter) // mergeAdapter!!.removeAdapter(moreSongsAdapter)
// mergeAdapter!!.notifyDataSetChanged() // mergeAdapter!!.notifyDataSetChanged()
// } // }
//
// private fun onArtistSelected(artist: Artist) { private fun onArtistSelected(artist: Artist) {
// val bundle = Bundle() val bundle = Bundle()
// bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id) bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id)
// bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.id) bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.id)
// Navigation.findNavController(requireView()).navigate(R.id.searchToSelectAlbum, bundle) Navigation.findNavController(requireView()).navigate(R.id.searchToSelectAlbum, bundle)
// } }
private fun onAlbumSelected(album: MusicDirectory.Album, autoplay: Boolean) { private fun onAlbumSelected(album: MusicDirectory.Album, autoplay: Boolean) {
val bundle = Bundle() val bundle = Bundle()
@ -559,15 +349,112 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
var DEFAULT_SONGS = Settings.defaultSongs var DEFAULT_SONGS = Settings.defaultSongs
} }
// FIXME
override val itemClickTarget: Int = 0
// FIXME
override fun onItemClick(item: Identifiable) { override fun onItemClick(item: Identifiable) {
when (item) {
is Artist -> {
onArtistSelected(item)
}
is MusicDirectory.Entry -> {
if (item.isVideo) {
onVideoSelected(item)
} else {
onSongSelected(item, true)
}
}
is MusicDirectory.Album -> {
onAlbumSelected(item, false)
}
}
} }
@Suppress("LongMethod")
override fun onContextMenuItemSelected(menuItem: MenuItem, item: Identifiable): Boolean { override fun onContextMenuItemSelected(menuItem: MenuItem, item: Identifiable): Boolean {
val isArtist = (item is Artist) val isArtist = (item is Artist)
return EntryListFragment.handleContextMenu(menuItem, item, isArtist, downloadHandler, this) val found = EntryListFragment.handleContextMenu(menuItem, item, isArtist, downloadHandler, this)
if (found || item !is DownloadFile) return true
val songs = mutableListOf<MusicDirectory.Entry>()
when (menuItem.itemId) {
R.id.song_menu_play_now -> {
songs.add(item.song)
downloadHandler.download(
fragment = this,
append = false,
save = false,
autoPlay = true,
playNext = false,
shuffle = false,
songs = songs
)
}
R.id.song_menu_play_next -> {
songs.add(item.song)
downloadHandler.download(
fragment = this,
append = true,
save = false,
autoPlay = false,
playNext = true,
shuffle = false,
songs = songs
)
}
R.id.song_menu_play_last -> {
songs.add(item.song)
downloadHandler.download(
fragment = this,
append = true,
save = false,
autoPlay = false,
playNext = false,
shuffle = false,
songs = songs
)
}
R.id.song_menu_pin -> {
songs.add(item.song)
toast(
context,
resources.getQuantityString(
R.plurals.select_album_n_songs_pinned,
songs.size,
songs.size
)
)
downloadBackground(true, songs)
}
R.id.song_menu_download -> {
songs.add(item.song)
toast(
context,
resources.getQuantityString(
R.plurals.select_album_n_songs_downloaded,
songs.size,
songs.size
)
)
downloadBackground(false, songs)
}
R.id.song_menu_unpin -> {
songs.add(item.song)
toast(
context,
resources.getQuantityString(
R.plurals.select_album_n_songs_unpinned,
songs.size,
songs.size
)
)
mediaPlayerController.unpin(songs)
}
R.id.song_menu_share -> {
songs.add(item.song)
shareHandler.createShare(this, songs, searchRefresh, cancellationToken!!)
}
}
return true
} }
} }

View File

@ -14,9 +14,7 @@ import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.AdapterView.AdapterContextMenuInfo
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
@ -81,13 +79,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
/** /**
* The id of the main layout * The id of the main layout
*/ */
override val mainLayout: Int = R.layout.track_list override val mainLayout: Int = R.layout.list_layout_track
/**
* The id of the target in the navigation graph where we should go,
* after the user has clicked on an item
*/
override val itemClickTarget: Int = R.id.trackCollectionFragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -127,6 +119,8 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
viewAdapter.register( viewAdapter.register(
TrackViewBinder( TrackViewBinder(
onItemClick = { onItemClick(it.song) },
onContextMenuClick = { menu, id -> onContextMenuItemSelected(menu, id.song) },
checkable = true, checkable = true,
draggable = false, draggable = false,
context = requireContext(), context = requireContext(),
@ -209,78 +203,6 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
getLiveData(args) getLiveData(args)
} }
override fun onContextItemSelected(menuItem: MenuItem): Boolean {
Timber.d("onContextItemSelected")
val info = menuItem.menuInfo as AdapterContextMenuInfo? ?: return true
val entry = viewAdapter.getCurrentList()[info.position] as MusicDirectory.Entry?
?: return true
val entryId = entry.id
when (menuItem.itemId) {
R.id.menu_play_now -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = true, shuffle = false, background = false,
playNext = false, unpin = false, isArtist = false
)
}
R.id.menu_play_next -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = false, shuffle = false, background = false,
playNext = true, unpin = false, isArtist = false
)
}
R.id.menu_play_last -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = true,
autoPlay = false, shuffle = false, background = false,
playNext = false, unpin = false, isArtist = false
)
}
R.id.menu_pin -> {
downloadHandler.downloadRecursively(
this, entryId, save = true, append = true,
autoPlay = false, shuffle = false, background = false,
playNext = false, unpin = false, isArtist = false
)
}
R.id.menu_unpin -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = false, shuffle = false, background = false,
playNext = false, unpin = true, isArtist = false
)
}
R.id.menu_download -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = false, shuffle = false, background = true,
playNext = false, unpin = false, isArtist = false
)
}
R.id.select_album_play_all -> {
// TODO: Why is this being handled here?!
playAll()
}
R.id.menu_item_share -> {
val entries: MutableList<MusicDirectory.Entry?> = ArrayList(1)
entries.add(entry)
shareHandler.createShare(
this, entries, refreshListView,
cancellationToken!!
)
return true
}
else -> {
return super.onContextItemSelected(menuItem)
}
}
return true
}
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
playAllButton = menu.findItem(R.id.select_album_play_all) playAllButton = menu.findItem(R.id.select_album_play_all)
@ -503,7 +425,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
private val songsForGenreObserver = Observer<MusicDirectory> { musicDirectory -> private val songsForGenreObserver = Observer<MusicDirectory> { musicDirectory ->
// Hide more button when results are less than album list size // Hide more button when results are less than album list size
if (musicDirectory.getChildren().size < requireArguments().getInt( if (musicDirectory.size < requireArguments().getInt(
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0
) )
) { ) {
@ -700,12 +622,74 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
return listModel.currentList return listModel.currentList
} }
@Suppress("LongMethod")
override fun onContextMenuItemSelected( override fun onContextMenuItemSelected(
menuItem: MenuItem, menuItem: MenuItem,
item: MusicDirectory.Entry item: MusicDirectory.Entry
): Boolean { ): Boolean {
// TODO val entryId = item.id
return false
when (menuItem.itemId) {
R.id.menu_play_now -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = true, shuffle = false, background = false,
playNext = false, unpin = false, isArtist = false
)
}
R.id.menu_play_next -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = false, shuffle = false, background = false,
playNext = true, unpin = false, isArtist = false
)
}
R.id.menu_play_last -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = true,
autoPlay = false, shuffle = false, background = false,
playNext = false, unpin = false, isArtist = false
)
}
R.id.menu_pin -> {
downloadHandler.downloadRecursively(
this, entryId, save = true, append = true,
autoPlay = false, shuffle = false, background = false,
playNext = false, unpin = false, isArtist = false
)
}
R.id.menu_unpin -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = false, shuffle = false, background = false,
playNext = false, unpin = true, isArtist = false
)
}
R.id.menu_download -> {
downloadHandler.downloadRecursively(
this, entryId, save = false, append = false,
autoPlay = false, shuffle = false, background = true,
playNext = false, unpin = false, isArtist = false
)
}
R.id.select_album_play_all -> {
// TODO: Why is this being handled here?!
playAll()
}
R.id.menu_item_share -> {
val entries: MutableList<MusicDirectory.Entry?> = ArrayList(1)
entries.add(item)
shareHandler.createShare(
this, entries, refreshListView,
cancellationToken!!
)
return true
}
else -> {
return super.onContextItemSelected(menuItem)
}
}
return true
} }
override fun onItemClick(item: MusicDirectory.Entry) { override fun onItemClick(item: MusicDirectory.Entry) {

View File

@ -118,6 +118,4 @@ open class GenericListModel(application: Application) :
internal fun hasOnlyFolders(musicDirectory: MusicDirectory) = internal fun hasOnlyFolders(musicDirectory: MusicDirectory) =
musicDirectory.getChildren(includeDirs = true, includeFiles = false).size == musicDirectory.getChildren(includeDirs = true, includeFiles = false).size ==
musicDirectory.getChildren(includeDirs = true, includeFiles = true).size musicDirectory.getChildren(includeDirs = true, includeFiles = true).size
internal val allSongsId = "-1"
} }

View File

@ -9,7 +9,6 @@ package org.moire.ultrasonic.model
import android.app.Application import android.app.Application
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import java.util.LinkedList
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.domain.MusicDirectory
@ -38,33 +37,15 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val service = MusicServiceFactory.getMusicService() val service = MusicServiceFactory.getMusicService()
val musicDirectory = service.getMusicDirectory(id, name, refresh)
var root = MusicDirectory() currentDirectory.postValue(musicDirectory)
updateList(musicDirectory)
if (allSongsId == id && parentId != null) {
val musicDirectory = service.getMusicDirectory(
parentId, name, refresh
)
val songs: MutableList<MusicDirectory.Entry> = LinkedList()
getSongsRecursively(musicDirectory, songs)
for (song in songs) {
if (!song.isDirectory) {
root.addChild(song)
}
}
} else {
val musicDirectory = service.getMusicDirectory(id, name, refresh)
root = musicDirectory
}
currentDirectory.postValue(root)
updateList(root)
} }
} }
// Given a Music directory "songs" it recursively adds all children to "songs" // Given a Music directory "songs" it recursively adds all children to "songs"
@Suppress("unused")
private fun getSongsRecursively( private fun getSongsRecursively(
parent: MusicDirectory, parent: MusicDirectory,
songs: MutableList<MusicDirectory.Entry> songs: MutableList<MusicDirectory.Entry>
@ -78,13 +59,8 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
} }
for ((id1, _, _, title) in parent.getAlbums()) { for ((id1, _, _, title) in parent.getAlbums()) {
var root: MusicDirectory val root: MusicDirectory = service.getMusicDirectory(id1, title, false)
getSongsRecursively(root, songs)
if (allSongsId != id1) {
root = service.getMusicDirectory(id1, title, false)
getSongsRecursively(root, songs)
}
} }
} }
@ -93,39 +69,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val service = MusicServiceFactory.getMusicService() val service = MusicServiceFactory.getMusicService()
val musicDirectory: MusicDirectory = service.getAlbum(id, name, refresh)
val musicDirectory: MusicDirectory
if (allSongsId == id && parentId != null) {
val root = MusicDirectory()
val songs: MutableCollection<MusicDirectory.Entry> = LinkedList()
val artist = service.getArtist(parentId, "", false)
// FIXME is still working?
for ((id1) in artist) {
if (allSongsId != id1) {
val albumDirectory = service.getAlbum(
id1, "", false
)
for (song in albumDirectory.getTracks()) {
if (!song.isVideo) {
songs.add(song)
}
}
}
}
for (song in songs) {
if (!song.isDirectory) {
root.addChild(song)
}
}
musicDirectory = root
} else {
musicDirectory = service.getAlbum(id, name, refresh)
}
currentDirectory.postValue(musicDirectory) currentDirectory.postValue(musicDirectory)
updateList(musicDirectory) updateList(musicDirectory)
@ -217,7 +161,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
for (share in shares) { for (share in shares) {
if (share.id == shareId) { if (share.id == shareId) {
for (entry in share.getEntries()) { for (entry in share.getEntries()) {
musicDirectory.addChild(entry) musicDirectory.add(entry)
} }
break break
} }

View File

@ -584,7 +584,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
) )
} }
if (albums?.getChildren()?.count() ?: 0 >= DISPLAY_LIMIT) if (albums?.size ?: 0 >= DISPLAY_LIMIT)
mediaItems.add( mediaItems.add(
R.string.search_more, R.string.search_more,
listOf(MEDIA_ALBUM_PAGE_ID, type.typeName, (page ?: 0) + 1).joinToString("|"), listOf(MEDIA_ALBUM_PAGE_ID, type.typeName, (page ?: 0) + 1).joinToString("|"),
@ -626,7 +626,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
val content = callWithErrorHandling { musicService.getPlaylist(id, name) } val content = callWithErrorHandling { musicService.getPlaylist(id, name) }
if (content != null) { if (content != null) {
if (content.getChildren().count() > 1) if (content.size > 1)
mediaItems.addPlayAllItem( mediaItems.addPlayAllItem(
listOf(MEDIA_PLAYLIST_ITEM, id, name).joinToString("|") listOf(MEDIA_PLAYLIST_ITEM, id, name).joinToString("|")
) )
@ -928,7 +928,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
val songs = callWithErrorHandling { musicService.getRandomSongs(DISPLAY_LIMIT) } val songs = callWithErrorHandling { musicService.getRandomSongs(DISPLAY_LIMIT) }
if (songs != null) { if (songs != null) {
if (songs.getChildren().count() > 1) if (songs.size > 1)
mediaItems.addPlayAllItem(listOf(MEDIA_SONG_RANDOM_ID).joinToString("|")) mediaItems.addPlayAllItem(listOf(MEDIA_SONG_RANDOM_ID).joinToString("|"))
// TODO: Paging is not implemented for songs, is it necessary at all? // TODO: Paging is not implemented for songs, is it necessary at all?

View File

@ -109,7 +109,7 @@ class OfflineMusicService : MusicService, KoinComponent {
val filename = getName(file) val filename = getName(file)
if (filename != null && !seen.contains(filename)) { if (filename != null && !seen.contains(filename)) {
seen.add(filename) seen.add(filename)
result.addChild(createEntry(file, filename)) result.add(createEntry(file, filename))
} }
} }
@ -207,7 +207,7 @@ class OfflineMusicService : MusicService, KoinComponent {
val entryFile = File(line) val entryFile = File(line)
val entryName = getName(entryFile) val entryName = getName(entryFile)
if (entryFile.exists() && entryName != null) { if (entryFile.exists() && entryName != null) {
playlist.addChild(createEntry(entryFile, entryName)) playlist.add(createEntry(entryFile, entryName))
} }
} }
playlist playlist
@ -260,7 +260,7 @@ class OfflineMusicService : MusicService, KoinComponent {
val finalSize: Int = children.size.coerceAtMost(size) val finalSize: Int = children.size.coerceAtMost(size)
for (i in 0 until finalSize) { for (i in 0 until finalSize) {
val file = children[i % children.size] val file = children[i % children.size]
result.addChild(createEntry(file, getName(file))) result.add(createEntry(file, getName(file)))
} }
return result return result
} }

View File

@ -319,7 +319,7 @@ open class RESTMusicService(
) { ) {
val entry = podcastEntry.toDomainEntity() val entry = podcastEntry.toDomainEntity()
entry.track = null entry.track = null
musicDirectory.addChild(entry) musicDirectory.add(entry)
} }
} }

View File

@ -219,7 +219,7 @@ class DownloadHandler(
for (share in shares) { for (share in shares) {
if (share.id == id) { if (share.id == id) {
for (entry in share.getEntries()) { for (entry in share.getEntries()) {
root.addChild(entry) root.add(entry)
} }
break break
} }

View File

@ -519,7 +519,7 @@ object Util {
fun getSongsFromSearchResult(searchResult: SearchResult): MusicDirectory { fun getSongsFromSearchResult(searchResult: SearchResult): MusicDirectory {
val musicDirectory = MusicDirectory() val musicDirectory = MusicDirectory()
for (entry in searchResult.songs) { for (entry in searchResult.songs) {
musicDirectory.addChild(entry) musicDirectory.add(entry)
} }
return musicDirectory return musicDirectory
} }
@ -531,7 +531,7 @@ object Util {
for (bookmark in bookmarks) { for (bookmark in bookmarks) {
song = bookmark.entry song = bookmark.entry
song.bookmarkPosition = bookmark.position song.bookmarkPosition = bookmark.position
musicDirectory.addChild(song) musicDirectory.add(song)
} }
return musicDirectory return musicDirectory
} }

View File

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
</vector>

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:orientation="horizontal"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:minHeight="?android:attr/listPreferredItemHeight">
<ImageView
a:id="@+id/album_coverart"
a:layout_width="64dp"
a:layout_height="64dp"
a:layout_gravity="start|center_vertical"
a:paddingStart="3dip" />
<LinearLayout
a:orientation="vertical"
a:layout_width="0dip"
a:layout_height="wrap_content"
a:layout_weight="1"
a:layout_gravity="start|center_vertical"
a:paddingStart="6dip"
a:paddingEnd="3dip">
<TextView
a:id="@+id/album_title"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium"
a:singleLine="true"
a:ellipsize="marquee" />
<TextView
a:id="@+id/album_artist"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceSmall"
a:singleLine="true" />
</LinearLayout>
<ImageView
a:id="@+id/album_star"
a:layout_width="38dp"
a:layout_height="fill_parent"
a:gravity="center_vertical"
a:background="@android:color/transparent"
a:src="?attr/star_hollow"
a:focusable="false"
a:paddingEnd="3dip" />
</LinearLayout>

View File

@ -2,7 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:a="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
a:id="@+id/row_artist_layout" a:id="@+id/containing_layout"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:background="?android:attr/selectableItemBackground" a:background="?android:attr/selectableItemBackground"
@ -10,7 +10,7 @@
a:focusable="true"> a:focusable="true">
<com.google.android.material.imageview.ShapeableImageView <com.google.android.material.imageview.ShapeableImageView
a:id="@+id/album_coverart" a:id="@+id/coverart"
a:layout_width="64dp" a:layout_width="64dp"
a:layout_height="64dp" a:layout_height="64dp"
a:layout_gravity="center_horizontal|center_vertical" a:layout_gravity="center_horizontal|center_vertical"
@ -35,8 +35,8 @@
a:paddingEnd="3dip" a:paddingEnd="3dip"
a:textAppearance="?android:attr/textAppearanceMedium" a:textAppearance="?android:attr/textAppearanceMedium"
app:layout_constraintEnd_toStartOf="@+id/album_star" app:layout_constraintEnd_toStartOf="@+id/album_star"
app:layout_constraintLeft_toRightOf="@+id/album_coverart" app:layout_constraintLeft_toRightOf="@+id/coverart"
app:layout_constraintStart_toEndOf="@+id/album_coverart" app:layout_constraintStart_toEndOf="@+id/coverart"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<TextView <TextView
@ -72,6 +72,7 @@
app:layout_constraintLeft_toRightOf="@+id/row_album_details" app:layout_constraintLeft_toRightOf="@+id/row_album_details"
app:layout_constraintStart_toEndOf="@+id/row_album_details" app:layout_constraintStart_toEndOf="@+id/row_album_details"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_star_hollow_dark" /> tools:src="@drawable/ic_star_hollow_dark"
a:contentDescription="@string/download.menu_star" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
a:id="@+id/row_artist_layout" xmlns:tools="http://schemas.android.com/tools"
a:layout_height="wrap_content" a:id="@+id/containing_layout"
a:layout_width="match_parent" a:layout_width="match_parent"
a:layout_height="wrap_content"
a:background="?android:attr/selectableItemBackground" a:background="?android:attr/selectableItemBackground"
a:clickable="true" a:clickable="true"
a:focusable="true"> a:focusable="true">
@ -17,17 +18,17 @@
a:minHeight="56dip" a:minHeight="56dip"
a:paddingStart="8dip" a:paddingStart="8dip"
a:paddingEnd="8dip" a:paddingEnd="8dip"
a:text="A"
a:textAppearance="?android:attr/textAppearanceLarge" a:textAppearance="?android:attr/textAppearanceLarge"
a:textColor="@color/cyan" /> a:textColor="@color/cyan"
tools:text="A" />
<com.google.android.material.imageview.ShapeableImageView <com.google.android.material.imageview.ShapeableImageView
a:id="@+id/artist_coverart" a:id="@+id/coverart"
a:layout_width="40dp" a:layout_width="40dp"
a:layout_height="40dp" a:layout_height="40dp"
a:layout_gravity="center_horizontal|center_vertical" a:layout_gravity="center_horizontal|center_vertical"
a:layout_marginTop="8dp"
a:layout_marginStart="2dp" a:layout_marginStart="2dp"
a:layout_marginTop="8dp"
a:layout_marginEnd="10dp" a:layout_marginEnd="10dp"
a:layout_toEndOf="@+id/row_section" a:layout_toEndOf="@+id/row_section"
a:scaleType="fitCenter" a:scaleType="fitCenter"
@ -38,13 +39,13 @@
a:id="@+id/row_artist_name" a:id="@+id/row_artist_name"
a:layout_width="fill_parent" a:layout_width="fill_parent"
a:layout_height="wrap_content" a:layout_height="wrap_content"
a:layout_toEndOf="@+id/artist_coverart" a:layout_marginEnd="12dp"
a:layout_toEndOf="@+id/coverart"
a:drawablePadding="6dip" a:drawablePadding="6dip"
a:gravity="center_vertical" a:gravity="center_vertical"
a:minHeight="56dip" a:minHeight="56dip"
a:paddingStart="3dip" a:paddingStart="3dip"
a:paddingEnd="3dip" a:paddingEnd="3dip"
a:layout_marginEnd="12dp"
a:textAppearance="?android:attr/textAppearanceMedium" /> a:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout> </RelativeLayout>

View File

@ -26,7 +26,7 @@
a:gravity="center_vertical" a:gravity="center_vertical"
a:paddingEnd="4dip"/> a:paddingEnd="4dip"/>
<include layout="@layout/song_details" /> <include layout="@layout/list_item_track_details" />
<LinearLayout <LinearLayout
a:id="@+id/song_rating" a:id="@+id/song_rating"

View File

@ -4,7 +4,7 @@
a:layout_height="fill_parent" a:layout_height="fill_parent"
a:orientation="vertical"> a:orientation="vertical">
<include layout="@layout/empty_view" /> <include layout="@layout/list_parts_empty_view" />
<include layout="@layout/recycler_view" /> <include layout="@layout/list_parts_recycler" />
</LinearLayout> </LinearLayout>

View File

@ -4,8 +4,8 @@
a:layout_height="fill_parent" a:layout_height="fill_parent"
a:orientation="vertical" > a:orientation="vertical" >
<include layout="@layout/empty_view" /> <include layout="@layout/list_parts_empty_view" />
<include layout="@layout/recycler_view" /> <include layout="@layout/list_parts_recycler" />
<include layout="@layout/album_buttons" /> <include layout="@layout/album_buttons" />
</LinearLayout> </LinearLayout>

View File

@ -5,7 +5,7 @@
a:layout_height="match_parent" a:layout_height="match_parent"
a:orientation="vertical"> a:orientation="vertical">
<include layout="@layout/empty_view" /> <include layout="@layout/list_parts_empty_view" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
a:id="@+id/swipe_refresh_view" a:id="@+id/swipe_refresh_view"

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:a="http://schemas.android.com/apk/res/android">
<item
a:id="@+id/song_menu_play_now"
a:title="@string/common.play_now" />
<item
a:id="@+id/song_menu_play_next"
a:title="@string/common.play_next" />
<item
a:id="@+id/song_menu_play_last"
a:title="@string/common.play_last" />
<item
a:id="@+id/song_menu_pin"
a:title="@string/common.pin" />
<item
a:id="@+id/song_menu_unpin"
a:title="@string/common.unpin" />
<item
a:id="@+id/song_menu_download"
a:title="@string/common.download" />
<item
a:id="@+id/song_menu_share"
a:title="@string/menu.share" />
</menu>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:a="http://schemas.android.com/apk/res/android" >
<item
a:id="@+id/menu_play_now"
a:title="@string/common.play_now"/>
<item
a:id="@+id/album_menu_play_next"
a:title="@string/common.play_next"/>
<item
a:id="@+id/menu_play_last"
a:title="@string/common.play_last"/>
<item
a:id="@+id/menu_pin"
a:title="@string/common.pin"/>
<item
a:id="@+id/menu_unpin"
a:title="@string/common.unpin"/>
<item
a:id="@+id/menu_download"
a:title="@string/common.download"/>
<item
a:id="@+id/menu_item_share"
a:title="@string/menu.share"/>
</menu>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:a="http://schemas.android.com/apk/res/android" >
<item
a:id="@+id/song_menu_play_now"
a:title="@string/common.play_now"/>
<item
a:id="@+id/song_menu_play_next"
a:title="@string/common.play_next"/>
<item
a:id="@+id/song_menu_play_last"
a:title="@string/common.play_last"/>
<item
a:id="@+id/song_menu_pin"
a:title="@string/common.pin"/>
<item
a:id="@+id/song_menu_unpin"
a:title="@string/common.unpin"/>
<item
a:id="@+id/song_menu_download"
a:title="@string/common.download"/>
<item
a:id="@+id/menu_item_share"
a:title="Share"/>
</menu>

View File

@ -50,8 +50,8 @@ class APIAlbumConverterTest {
with(convertedEntity) { with(convertedEntity) {
name `should be equal to` null name `should be equal to` null
getChildren().size `should be equal to` entity.songList.size size `should be equal to` entity.songList.size
getChildren()[0] `should be equal to` entity.songList[0].toDomainEntity() this[0] `should be equal to` entity.songList[0].toDomainEntity()
} }
} }

View File

@ -24,7 +24,7 @@ class APIMusicDirectoryConverterTest {
with(convertedEntity) { with(convertedEntity) {
name `should be equal to` entity.name name `should be equal to` entity.name
getChildren().size `should be equal to` entity.childList.size size `should be equal to` entity.childList.size
getChildren() `should be equal to` entity.childList getChildren() `should be equal to` entity.childList
.map { it.toDomainEntity() }.toMutableList() .map { it.toDomainEntity() }.toMutableList()
} }

View File

@ -26,9 +26,9 @@ class APIPlaylistConverterTest {
with(convertedEntity) { with(convertedEntity) {
name `should be equal to` entity.name name `should be equal to` entity.name
getChildren().size `should be equal to` entity.entriesList.size size `should be equal to` entity.entriesList.size
getChildren()[0] `should be equal to` entity.entriesList[0].toDomainEntity() this[0] `should be equal to` entity.entriesList[0].toDomainEntity()
getChildren()[1] `should be equal to` entity.entriesList[1].toDomainEntity() this[1] `should be equal to` entity.entriesList[1].toDomainEntity()
} }
} }