1
0
mirror of https://github.com/ultrasonic/ultrasonic synced 2025-02-05 11:37:31 +01:00

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>() {
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
fun getChildren(
includeDirs: Boolean = true,

View File

@ -55,7 +55,7 @@
errorLine2=" ^">
<location
file="src/main/res/values-de/strings.xml"
line="290"
line="289"
column="76"/>
</issue>
@ -66,29 +66,18 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="132"
line="134"
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_selected&quot;>%d tracks selected.&lt;/string>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
errorLine1=" &lt;string name=&quot;select_album.n_selected&quot;>%d tracks selected&lt;/string>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="149"
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"
line="151"
column="5"/>
</issue>
@ -136,17 +125,6 @@
column="10"/>
</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
id="ObsoleteLayoutParam"
message="Invalid layout param in a `LinearLayout`: `layout_above`"
@ -230,9 +208,9 @@
errorLine1=" a:background=&quot;?android:attr/selectableItemBackground&quot;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/layout/select_folder_header.xml"
line="11"
column="5"/>
file="src/main/res/drawable/ic_baseline_info_24.xml"
line="1"
column="1"/>
</issue>
<issue
@ -264,7 +242,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="112"
line="114"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -323,7 +301,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="126"
line="128"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -382,7 +360,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="131"
line="133"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -441,7 +419,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="132"
line="134"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -500,7 +478,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="133"
line="135"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -559,7 +537,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="134"
line="136"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -618,7 +596,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="139"
line="141"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -677,7 +655,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="145"
line="147"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
@ -736,55 +714,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="158"
line="159"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="141"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="140"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="139"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="156"
line="155"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="153"
line="152"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="151"
line="150"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="137"
line="136"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="156"
line="155"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="139"
line="138"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="139"
line="138"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="153"
line="152"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="153"
line="152"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="152"
line="151"
column="13"/>
</issue>
@ -795,7 +773,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="159"
line="160"
column="13"/>
</issue>
@ -806,7 +784,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="160"
line="161"
column="13"/>
</issue>
@ -817,55 +795,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="176"
line="177"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="157"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="156"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="155"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="172"
line="171"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="169"
line="168"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="167"
line="166"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="153"
line="152"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="172"
line="171"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="155"
line="154"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="155"
line="154"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="169"
line="168"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="169"
line="168"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="168"
line="167"
column="13"/>
</issue>
@ -876,55 +854,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="228"
line="229"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="209"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="208"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="207"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="224"
line="223"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="221"
line="220"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="219"
line="218"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="204"
line="203"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="224"
line="223"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="207"
line="206"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="207"
line="206"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="221"
line="220"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="221"
line="220"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="218"
line="217"
column="13"/>
</issue>
@ -935,55 +913,55 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="297"
line="298"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="274"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="273"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="272"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="293"
line="292"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="288"
line="287"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="286"
line="285"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="267"
line="266"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="293"
line="292"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="272"
line="271"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="272"
line="271"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="290"
line="289"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="288"
line="287"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="286"
line="285"
column="13"/>
</issue>
@ -994,51 +972,51 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="300"
line="301"
column="13"/>
<location
file="src/main/res/values-cs/strings.xml"
line="277"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="276"
column="13"/>
<location
file="src/main/res/values-de/strings.xml"
line="275"
column="13"/>
<location
file="src/main/res/values-es/strings.xml"
line="296"
line="295"
column="13"/>
<location
file="src/main/res/values-fr/strings.xml"
line="291"
line="290"
column="13"/>
<location
file="src/main/res/values-hu/strings.xml"
line="289"
line="288"
column="13"/>
<location
file="src/main/res/values-it/strings.xml"
line="270"
line="269"
column="13"/>
<location
file="src/main/res/values-nl/strings.xml"
line="296"
line="295"
column="13"/>
<location
file="src/main/res/values-pl/strings.xml"
line="275"
line="274"
column="13"/>
<location
file="src/main/res/values-pt/strings.xml"
line="275"
line="274"
column="13"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="293"
line="292"
column="13"/>
<location
file="src/main/res/values-ru/strings.xml"
line="291"
line="290"
column="13"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
@ -1053,7 +1031,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="397"
line="387"
column="13"/>
</issue>
@ -1064,47 +1042,47 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/main/res/values/strings.xml"
line="476"
line="470"
column="14"/>
<location
file="src/main/res/values-cs/strings.xml"
line="448"
line="436"
column="14"/>
<location
file="src/main/res/values-es/strings.xml"
line="470"
line="458"
column="14"/>
<location
file="src/main/res/values-fr/strings.xml"
line="459"
line="447"
column="14"/>
<location
file="src/main/res/values-hu/strings.xml"
line="454"
line="442"
column="14"/>
<location
file="src/main/res/values-nl/strings.xml"
line="470"
line="458"
column="14"/>
<location
file="src/main/res/values-pl/strings.xml"
line="401"
line="389"
column="14"/>
<location
file="src/main/res/values-pt/strings.xml"
line="388"
line="376"
column="14"/>
<location
file="src/main/res/values-pt-rBR/strings.xml"
line="463"
line="451"
column="14"/>
<location
file="src/main/res/values-ru/strings.xml"
line="471"
line="459"
column="14"/>
<location
file="src/main/res/values-zh-rCN/strings.xml"
line="452"
line="440"
column="14"/>
</issue>
@ -1194,17 +1172,6 @@
column="4"/>
</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
id="ClickableViewAccessibility"
message="Custom view ``AutoRepeatButton`` has `setOnTouchListener` called on it but does not override `performClick`"
@ -1216,149 +1183,6 @@
column="3"/>
</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
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
@ -1568,116 +1392,6 @@
column="6"/>
</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
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
@ -1728,30 +1442,19 @@
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/select_folder_header.xml"
file="src/main/res/layout/list_header_folder.xml"
line="15"
column="6"/>
</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
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/song_list_item.xml"
line="38"
file="src/main/res/layout/list_item_track.xml"
line="39"
column="10"/>
</issue>
@ -1761,8 +1464,8 @@
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/song_list_item.xml"
line="48"
file="src/main/res/layout/list_item_track.xml"
line="49"
column="10"/>
</issue>
@ -1772,8 +1475,8 @@
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/song_list_item.xml"
line="58"
file="src/main/res/layout/list_item_track.xml"
line="59"
column="10"/>
</issue>
@ -1783,8 +1486,8 @@
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/song_list_item.xml"
line="68"
file="src/main/res/layout/list_item_track.xml"
line="69"
column="10"/>
</issue>
@ -1794,22 +1497,11 @@
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src/main/res/layout/song_list_item.xml"
line="78"
file="src/main/res/layout/list_item_track.xml"
line="79"
column="10"/>
</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
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
@ -1953,17 +1645,6 @@
column="17"/>
</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
id="HardcodedText"
message="Hardcoded string &quot;0 dB&quot;, should use `@string` resource"
@ -1975,28 +1656,6 @@
column="13"/>
</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
id="HardcodedText"
message="Hardcoded string &quot;http://&quot;, should use `@string` resource"
@ -2015,7 +1674,7 @@
errorLine2=" ~~~~~~~~~~~~">
<location
file="src/main/res/layout/player_media_info.xml"
line="50"
line="52"
column="6"/>
</issue>

View File

@ -19,8 +19,6 @@
package org.moire.ultrasonic.view;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -28,6 +26,9 @@ import android.widget.ArrayAdapter;
import android.widget.SectionIndexer;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.moire.ultrasonic.R;
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)
{
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);
@ -81,7 +82,7 @@ public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexe
) {
View rowView = convertView;
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());

View File

@ -48,7 +48,7 @@ public class GenreAdapter extends ArrayAdapter<Genre> implements SectionIndexer
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);
@ -75,7 +75,7 @@ public class GenreAdapter extends ArrayAdapter<Genre> implements SectionIndexer
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View rowView = convertView;
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());

View File

@ -43,15 +43,15 @@ class AlbumRowBinder(
Util.getDrawableFromAttribute(context, R.attr.star_hollow)
// Set our layout files
val layout = R.layout.album_list_item
val contextMenuLayout = R.menu.artist_context_menu
val layout = R.layout.list_item_album
val contextMenuLayout = R.menu.context_menu_artist
override fun onBindViewHolder(holder: ViewHolder, item: MusicDirectory.Album) {
holder.album.text = item.title
holder.artist.text = item.artist
holder.details.setOnClickListener { onItemClick(item) }
holder.details.setOnLongClickListener {
val popup = Helper.createPopupMenu(holder.itemView)
val popup = Utils.createPopupMenu(holder.itemView)
popup.setOnMenuItemClickListener { menuItem ->
onContextMenuClick(menuItem, item)
@ -78,7 +78,7 @@ class AlbumRowBinder(
var album: TextView = view.findViewById(R.id.album_title)
var artist: TextView = view.findViewById(R.id.album_artist)
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 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
* FIXME: On click wrong display...
*/
class ArtistRowBinder(
val onItemClick: (ArtistOrIndex) -> Unit,
@ -35,8 +34,8 @@ class ArtistRowBinder(
private val enableSections: Boolean = true
) : ItemViewBinder<ArtistOrIndex, ArtistRowBinder.ViewHolder>(), KoinComponent {
val layout = R.layout.artist_list_item
val contextMenuLayout = R.menu.artist_context_menu
val layout = R.layout.list_item_artist
val contextMenuLayout = R.menu.context_menu_artist
override fun onBindViewHolder(holder: ViewHolder, item: ArtistOrIndex) {
holder.textView.text = item.name
@ -44,7 +43,7 @@ class ArtistRowBinder(
holder.section.isVisible = enableSections
holder.layout.setOnClickListener { onItemClick(item) }
holder.layout.setOnLongClickListener {
val popup = Helper.createPopupMenu(holder.itemView)
val popup = Utils.createPopupMenu(holder.itemView, contextMenuLayout)
popup.setOnMenuItemClickListener { menuItem ->
onContextMenuClick(menuItem, item)
@ -106,8 +105,8 @@ class ArtistRowBinder(
) : RecyclerView.ViewHolder(itemView) {
var section: TextView = itemView.findViewById(R.id.row_section)
var textView: TextView = itemView.findViewById(R.id.row_artist_name)
var layout: RelativeLayout = itemView.findViewById(R.id.row_artist_layout)
var coverArt: ImageView = itemView.findViewById(R.id.artist_coverart)
var layout: RelativeLayout = itemView.findViewById(R.id.containing_layout)
var coverArt: ImageView = itemView.findViewById(R.id.coverart)
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.
* 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() {

View File

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

View File

@ -29,7 +29,7 @@ class FolderSelectorBinder(context: Context) :
private val weakContext: WeakReference<Context> = WeakReference(context)
// 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 {
return ViewHolder(inflater.inflate(layout, parent, false), weakContext)

View File

@ -30,7 +30,7 @@ class HeaderViewBinder(
private val imageLoaderProvider: ImageLoaderProvider by inject()
// 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 {
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
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.view.LayoutInflater
import android.view.View
import android.view.MenuItem
import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import com.drakeet.multitype.ItemViewBinder
@ -15,24 +15,26 @@ import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.Downloader
class TrackViewBinder(
val onItemClick: (DownloadFile) -> Unit,
val onContextMenuClick: ((MenuItem, DownloadFile) -> Boolean)? = null,
val checkable: Boolean,
val draggable: Boolean,
context: Context,
val lifecycleOwner: LifecycleOwner,
private val onClickCallback: ((View, DownloadFile?) -> Unit)? = null
) : ItemViewBinder<Identifiable, TrackViewHolder>(), KoinComponent {
// Set our layout files
val layout = R.layout.song_list_item
val contextMenuLayout = R.menu.artist_context_menu
val layout = R.layout.list_item_track
val contextMenuLayout = R.menu.context_menu_track
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 {
return TrackViewHolder(inflater.inflate(layout, parent, false))
}
@Suppress("LongMethod")
override fun onBindViewHolder(holder: TrackViewHolder, item: Identifiable) {
val downloadFile: DownloadFile?
val diffAdapter = adapter as BaseAdapter<*>
@ -58,6 +60,32 @@ class TrackViewBinder(
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
holder.observableChecked.observe(
lifecycleOwner,
@ -95,7 +123,5 @@ class TrackViewBinder(
holder.updateProgress(it)
}
)
holder.itemClickListener = onClickCallback
}
}

View File

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

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
import android.os.Bundle
@ -26,13 +33,7 @@ class AlbumListFragment : EntryListFragment<MusicDirectory.Album>() {
/**
* The id of the main layout
*/
override val mainLayout: Int = R.layout.generic_list
/**
* 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 val mainLayout: Int = R.layout.list_layout_generic
/**
* 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()
)
)
emptyTextView.setText(R.string.select_album_empty)
}
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.putString(Constants.INTENT_EXTRA_NAME_NAME, item.title)
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
*/
override val mainLayout = R.layout.generic_list
/**
* 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
override val mainLayout = R.layout.list_layout_generic
/**
* 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.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 1000)
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.
*
* FIXME: use restore for playback
*/
class BookmarksFragment : TrackCollectionFragment() {
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.moire.ultrasonic.R
import org.moire.ultrasonic.adapters.TrackViewBinder
import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.model.GenericListModel
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.Downloader
@ -26,8 +27,10 @@ import org.moire.ultrasonic.util.Util
* Displays currently running downloads.
* 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
* buttons useful to manipulate the list.
* TODO: A consideration would be to base this class on TrackCollectionFragment and thereby inheriting the
* buttons useful to manipulate the list.
*
* TODO: Add code to enable manipulation of the download list
*/
class DownloadsFragment : MultiListFragment<DownloadFile>() {
@ -36,13 +39,6 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
*/
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
*/
@ -50,15 +46,6 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
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?) {
FragmentTitle.setTitle(this, Util.appContext().getString(R.string.menu_downloads))
}
@ -68,6 +55,8 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
viewAdapter.register(
TrackViewBinder(
{ },
{ _,_ -> true },
checkable = false,
draggable = false,
context = requireContext(),
@ -82,6 +71,15 @@ class DownloadsFragment : MultiListFragment<DownloadFile>() {
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) {

View File

@ -3,6 +3,7 @@ package org.moire.ultrasonic.fragment
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import org.moire.ultrasonic.R
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.subsonic.DownloadHandler
import org.moire.ultrasonic.util.Constants
import androidx.fragment.app.Fragment
import org.moire.ultrasonic.util.Settings
/**
@ -30,7 +30,6 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
!listModel.isOffline() && !Settings.shouldUseId3Tags
}
override fun onContextMenuItemSelected(menuItem: MenuItem, item: T): Boolean {
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_PARENT_ID, item.id)
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?) {
@ -149,6 +148,7 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
unpin = false,
isArtist = isArtist
)
else -> return false
}
return true
}

View File

@ -76,16 +76,10 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
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
*/
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
@ -95,7 +89,6 @@ abstract class MultiListFragment<T : Identifiable> : Fragment() {
open val emptyViewId = R.id.empty_list_view
open val emptyTextId = R.id.empty_list_text
open fun setTitle(title: String?) {
if (title == null) {
FragmentTitle.setTitle(

View File

@ -229,7 +229,7 @@ class PlayerFragment :
val ratingLinearLayout = view.findViewById<LinearLayout>(R.id.song_rating)
if (!useFiveStarRating) ratingLinearLayout.isVisible = false
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) }
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 {
return menuItemSelected(item.itemId, null) || super.onOptionsItemSelected(item)
}
@ -856,7 +848,7 @@ class PlayerFragment :
}
// Create listener
val listener: ((View, DownloadFile?) -> Unit) = { _, file ->
val listener: ((DownloadFile) -> Unit) = { file ->
val list = mediaPlayerController.playList
val index = list.indexOf(file)
mediaPlayerController.play(index)
@ -866,11 +858,12 @@ class PlayerFragment :
viewAdapter.register(
TrackViewBinder(
onItemClick = listener,
onContextMenuClick = {_,_ -> true},
checkable = false,
draggable = true,
context = requireContext(),
lifecycleOwner = viewLifecycleOwner,
listener
)
)

View File

@ -3,20 +3,15 @@ package org.moire.ultrasonic.fragment
import android.app.SearchManager
import android.content.Context
import android.os.Bundle
import android.view.ContextMenu
import android.view.ContextMenu.ContextMenuInfo
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.widget.AdapterView.AdapterContextMenuInfo
import android.widget.ListAdapter
import androidx.appcompat.widget.SearchView
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation
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.fragment.FragmentTitle.Companion.setTitle
import org.moire.ultrasonic.model.SearchListModel
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.MediaPlayerController
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
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
*
* FIXME: Handle context click on song
*/
class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
private var moreArtistsButton: View? = null
@ -107,18 +105,7 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
// expandSongs()
// } else {
// 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.
viewAdapter.register(
ArtistRowBinder(
onItemClick = { entry -> onItemClick(entry) },
onContextMenuClick = { menuItem, entry ->
onContextMenuItemSelected(
menuItem,
entry
)
},
onItemClick = ::onItemClick,
onContextMenuClick = ::onContextMenuItemSelected,
imageLoader = imageLoaderProvider.getImageLoader(),
enableSections = false
)
@ -143,13 +125,8 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
viewAdapter.register(
AlbumRowBinder(
onItemClick = { entry -> onItemClick(entry) },
onContextMenuClick = { menuItem, entry ->
onContextMenuItemSelected(
menuItem,
entry
)
},
onItemClick = ::onItemClick,
onContextMenuClick = ::onContextMenuItemSelected,
imageLoader = imageLoaderProvider.getImageLoader(),
context = requireContext()
)
@ -157,6 +134,8 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
viewAdapter.register(
TrackViewBinder(
onItemClick = ::onItemClick,
onContextMenuClick = ::onContextMenuItemSelected,
checkable = false,
draggable = false,
context = requireContext(),
@ -193,7 +172,7 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
val arguments = arguments
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)
// If started with a query, enter it to the searchView
@ -236,200 +215,11 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
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() {
cancellationToken?.cancel()
super.onDestroyView()
}
// OK!
private fun downloadBackground(save: Boolean, songs: List<MusicDirectory.Entry?>) {
val onValid = Runnable {
networkAndStorageChecker.warnIfNetworkOrStorageUnavailable()
@ -515,13 +305,13 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
// mergeAdapter!!.removeAdapter(moreSongsAdapter)
// mergeAdapter!!.notifyDataSetChanged()
// }
//
// private fun onArtistSelected(artist: Artist) {
// val bundle = Bundle()
// bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id)
// bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.id)
// Navigation.findNavController(requireView()).navigate(R.id.searchToSelectAlbum, bundle)
// }
private fun onArtistSelected(artist: Artist) {
val bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id)
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.id)
Navigation.findNavController(requireView()).navigate(R.id.searchToSelectAlbum, bundle)
}
private fun onAlbumSelected(album: MusicDirectory.Album, autoplay: Boolean) {
val bundle = Bundle()
@ -559,15 +349,112 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
var DEFAULT_SONGS = Settings.defaultSongs
}
// FIXME
override val itemClickTarget: Int = 0
// FIXME
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 {
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.MenuItem
import android.view.View
import android.widget.AdapterView.AdapterContextMenuInfo
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
@ -81,13 +79,7 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
/**
* The id of the main layout
*/
override val mainLayout: Int = R.layout.track_list
/**
* 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 val mainLayout: Int = R.layout.list_layout_track
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -127,6 +119,8 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
viewAdapter.register(
TrackViewBinder(
onItemClick = { onItemClick(it.song) },
onContextMenuClick = { menu, id -> onContextMenuItemSelected(menu, id.song) },
checkable = true,
draggable = false,
context = requireContext(),
@ -209,78 +203,6 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
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) {
super.onPrepareOptionsMenu(menu)
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 ->
// 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
)
) {
@ -700,12 +622,74 @@ open class TrackCollectionFragment : MultiListFragment<MusicDirectory.Entry>() {
return listModel.currentList
}
@Suppress("LongMethod")
override fun onContextMenuItemSelected(
menuItem: MenuItem,
item: MusicDirectory.Entry
): Boolean {
// TODO
return false
val entryId = item.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(item)
shareHandler.createShare(
this, entries, refreshListView,
cancellationToken!!
)
return true
}
else -> {
return super.onContextItemSelected(menuItem)
}
}
return true
}
override fun onItemClick(item: MusicDirectory.Entry) {

View File

@ -118,6 +118,4 @@ open class GenericListModel(application: Application) :
internal fun hasOnlyFolders(musicDirectory: MusicDirectory) =
musicDirectory.getChildren(includeDirs = true, includeFiles = false).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 androidx.lifecycle.MutableLiveData
import java.util.LinkedList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.moire.ultrasonic.domain.MusicDirectory
@ -38,33 +37,15 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
withContext(Dispatchers.IO) {
val service = MusicServiceFactory.getMusicService()
val musicDirectory = service.getMusicDirectory(id, name, refresh)
var root = 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)
currentDirectory.postValue(musicDirectory)
updateList(musicDirectory)
}
}
// Given a Music directory "songs" it recursively adds all children to "songs"
@Suppress("unused")
private fun getSongsRecursively(
parent: MusicDirectory,
songs: MutableList<MusicDirectory.Entry>
@ -78,13 +59,8 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
}
for ((id1, _, _, title) in parent.getAlbums()) {
var root: MusicDirectory
if (allSongsId != id1) {
root = service.getMusicDirectory(id1, title, false)
getSongsRecursively(root, songs)
}
val root: MusicDirectory = service.getMusicDirectory(id1, title, false)
getSongsRecursively(root, songs)
}
}
@ -93,39 +69,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
withContext(Dispatchers.IO) {
val service = MusicServiceFactory.getMusicService()
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)
}
val musicDirectory: MusicDirectory = service.getAlbum(id, name, refresh)
currentDirectory.postValue(musicDirectory)
updateList(musicDirectory)
@ -217,7 +161,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
for (share in shares) {
if (share.id == shareId) {
for (entry in share.getEntries()) {
musicDirectory.addChild(entry)
musicDirectory.add(entry)
}
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(
R.string.search_more,
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) }
if (content != null) {
if (content.getChildren().count() > 1)
if (content.size > 1)
mediaItems.addPlayAllItem(
listOf(MEDIA_PLAYLIST_ITEM, id, name).joinToString("|")
)
@ -928,7 +928,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
val songs = callWithErrorHandling { musicService.getRandomSongs(DISPLAY_LIMIT) }
if (songs != null) {
if (songs.getChildren().count() > 1)
if (songs.size > 1)
mediaItems.addPlayAllItem(listOf(MEDIA_SONG_RANDOM_ID).joinToString("|"))
// 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)
if (filename != null && !seen.contains(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 entryName = getName(entryFile)
if (entryFile.exists() && entryName != null) {
playlist.addChild(createEntry(entryFile, entryName))
playlist.add(createEntry(entryFile, entryName))
}
}
playlist
@ -260,7 +260,7 @@ class OfflineMusicService : MusicService, KoinComponent {
val finalSize: Int = children.size.coerceAtMost(size)
for (i in 0 until finalSize) {
val file = children[i % children.size]
result.addChild(createEntry(file, getName(file)))
result.add(createEntry(file, getName(file)))
}
return result
}

View File

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

View File

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

View File

@ -519,7 +519,7 @@ object Util {
fun getSongsFromSearchResult(searchResult: SearchResult): MusicDirectory {
val musicDirectory = MusicDirectory()
for (entry in searchResult.songs) {
musicDirectory.addChild(entry)
musicDirectory.add(entry)
}
return musicDirectory
}
@ -531,7 +531,7 @@ object Util {
for (bookmark in bookmarks) {
song = bookmark.entry
song.bookmarkPosition = bookmark.position
musicDirectory.addChild(song)
musicDirectory.add(song)
}
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"
xmlns:app="http://schemas.android.com/apk/res-auto"
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_height="wrap_content"
a:background="?android:attr/selectableItemBackground"
@ -10,7 +10,7 @@
a:focusable="true">
<com.google.android.material.imageview.ShapeableImageView
a:id="@+id/album_coverart"
a:id="@+id/coverart"
a:layout_width="64dp"
a:layout_height="64dp"
a:layout_gravity="center_horizontal|center_vertical"
@ -35,8 +35,8 @@
a:paddingEnd="3dip"
a:textAppearance="?android:attr/textAppearanceMedium"
app:layout_constraintEnd_toStartOf="@+id/album_star"
app:layout_constraintLeft_toRightOf="@+id/album_coverart"
app:layout_constraintStart_toEndOf="@+id/album_coverart"
app:layout_constraintLeft_toRightOf="@+id/coverart"
app:layout_constraintStart_toEndOf="@+id/coverart"
app:layout_constraintTop_toTopOf="parent">
<TextView
@ -72,6 +72,7 @@
app:layout_constraintLeft_toRightOf="@+id/row_album_details"
app:layout_constraintStart_toEndOf="@+id/row_album_details"
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>

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
a:layout_height="match_parent"
a:orientation="vertical">
<include layout="@layout/empty_view" />
<include layout="@layout/list_parts_empty_view" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
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) {
name `should be equal to` null
getChildren().size `should be equal to` entity.songList.size
getChildren()[0] `should be equal to` entity.songList[0].toDomainEntity()
size `should be equal to` entity.songList.size
this[0] `should be equal to` entity.songList[0].toDomainEntity()
}
}

View File

@ -24,7 +24,7 @@ class APIMusicDirectoryConverterTest {
with(convertedEntity) {
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
.map { it.toDomainEntity() }.toMutableList()
}

View File

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