mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2025-06-14 06:22:09 +03:00
Merge branch 'safeArgs2' into 'develop'
Finish SafeArgs Closes #510 See merge request ultrasonic/ultrasonic!802
This commit is contained in:
commit
1a354765f9
@ -1,103 +0,0 @@
|
|||||||
package org.moire.ultrasonic.fragment;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
||||||
|
|
||||||
import org.moire.ultrasonic.R;
|
|
||||||
import org.moire.ultrasonic.domain.Lyrics;
|
|
||||||
import org.moire.ultrasonic.service.MusicService;
|
|
||||||
import org.moire.ultrasonic.service.MusicServiceFactory;
|
|
||||||
import org.moire.ultrasonic.util.BackgroundTask;
|
|
||||||
import org.moire.ultrasonic.util.CancellationToken;
|
|
||||||
import org.moire.ultrasonic.util.Constants;
|
|
||||||
import org.moire.ultrasonic.util.FragmentBackgroundTask;
|
|
||||||
import org.moire.ultrasonic.util.Util;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the lyrics of a song
|
|
||||||
*/
|
|
||||||
public class LyricsFragment extends Fragment {
|
|
||||||
|
|
||||||
private TextView artistView;
|
|
||||||
private TextView titleView;
|
|
||||||
private TextView textView;
|
|
||||||
private SwipeRefreshLayout swipe;
|
|
||||||
private CancellationToken cancellationToken;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
Util.applyTheme(this.getContext());
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
return inflater.inflate(R.layout.lyrics, container, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
||||||
cancellationToken = new CancellationToken();
|
|
||||||
Timber.d("Lyrics set title");
|
|
||||||
FragmentTitle.Companion.setTitle(this, R.string.download_menu_lyrics);
|
|
||||||
|
|
||||||
swipe = view.findViewById(R.id.lyrics_refresh);
|
|
||||||
swipe.setEnabled(false);
|
|
||||||
artistView = view.findViewById(R.id.lyrics_artist);
|
|
||||||
titleView = view.findViewById(R.id.lyrics_title);
|
|
||||||
textView = view.findViewById(R.id.lyrics_text);
|
|
||||||
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
cancellationToken.cancel();
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
BackgroundTask<Lyrics> task = new FragmentBackgroundTask<Lyrics>(getActivity(), true, swipe, cancellationToken)
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected Lyrics doInBackground() throws Throwable
|
|
||||||
{
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
if (arguments == null) return null;
|
|
||||||
String artist = arguments.getString(Constants.INTENT_ARTIST);
|
|
||||||
String title = arguments.getString(Constants.INTENT_TITLE);
|
|
||||||
MusicService musicService = MusicServiceFactory.getMusicService();
|
|
||||||
return musicService.getLyrics(artist, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void done(Lyrics result)
|
|
||||||
{
|
|
||||||
if (result != null && result.getArtist() != null)
|
|
||||||
{
|
|
||||||
artistView.setText(result.getArtist());
|
|
||||||
titleView.setText(result.getTitle());
|
|
||||||
textView.setText(result.getText());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
artistView.setText(R.string.lyrics_nomatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
task.execute();
|
|
||||||
}
|
|
||||||
}
|
|
@ -49,6 +49,7 @@ import org.moire.ultrasonic.R
|
|||||||
import org.moire.ultrasonic.app.UApp
|
import org.moire.ultrasonic.app.UApp
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
import org.moire.ultrasonic.data.ActiveServerProvider
|
||||||
import org.moire.ultrasonic.data.ServerSettingDao
|
import org.moire.ultrasonic.data.ServerSettingDao
|
||||||
|
import org.moire.ultrasonic.fragment.MainFragmentDirections
|
||||||
import org.moire.ultrasonic.fragment.OnBackPressedHandler
|
import org.moire.ultrasonic.fragment.OnBackPressedHandler
|
||||||
import org.moire.ultrasonic.model.ServerSettingsModel
|
import org.moire.ultrasonic.model.ServerSettingsModel
|
||||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider
|
import org.moire.ultrasonic.provider.SearchSuggestionProvider
|
||||||
@ -377,10 +378,8 @@ class NavigationActivity : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
suggestions.saveRecentQuery(query, null)
|
suggestions.saveRecentQuery(query, null)
|
||||||
|
|
||||||
val bundle = Bundle()
|
val action = MainFragmentDirections.toSearchFragment(query, autoPlay)
|
||||||
bundle.putString(Constants.INTENT_QUERY, query)
|
findNavController(R.id.nav_host_fragment).navigate(action)
|
||||||
bundle.putBoolean(Constants.INTENT_AUTOPLAY, autoPlay)
|
|
||||||
findNavController(R.id.nav_host_fragment).navigate(R.id.searchFragment, bundle)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ class FolderSelectorBinder(context: Context) :
|
|||||||
menuItem.isChecked = true
|
menuItem.isChecked = true
|
||||||
folderName.text = musicFolderName
|
folderName.text = musicFolderName
|
||||||
|
|
||||||
RxBus.musicFolderChangedEventPublisher.onNext(selectedFolderId)
|
RxBus.musicFolderChangedEventPublisher.onNext(RxBus.Folder(selectedFolderId))
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ import android.content.Context
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.PopupMenu
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import com.drakeet.multitype.ItemViewBinder
|
import com.drakeet.multitype.ItemViewBinder
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@ -13,6 +15,7 @@ import org.moire.ultrasonic.R
|
|||||||
import org.moire.ultrasonic.domain.Identifiable
|
import org.moire.ultrasonic.domain.Identifiable
|
||||||
import org.moire.ultrasonic.domain.Track
|
import org.moire.ultrasonic.domain.Track
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
class TrackViewBinder(
|
class TrackViewBinder(
|
||||||
val onItemClick: (Track, Int) -> Unit,
|
val onItemClick: (Track, Int) -> Unit,
|
||||||
val onContextMenuClick: ((MenuItem, Track) -> Boolean)? = null,
|
val onContextMenuClick: ((MenuItem, Track) -> Boolean)? = null,
|
||||||
@ -20,13 +23,18 @@ class TrackViewBinder(
|
|||||||
val draggable: Boolean,
|
val draggable: Boolean,
|
||||||
context: Context,
|
context: Context,
|
||||||
val lifecycleOwner: LifecycleOwner,
|
val lifecycleOwner: LifecycleOwner,
|
||||||
|
val createContextMenu: (View, Track) -> PopupMenu = { view, _ ->
|
||||||
|
Utils.createPopupMenu(
|
||||||
|
view,
|
||||||
|
R.menu.context_menu_track
|
||||||
|
)
|
||||||
|
}
|
||||||
) : ItemViewBinder<Identifiable, TrackViewHolder>(), KoinComponent {
|
) : ItemViewBinder<Identifiable, TrackViewHolder>(), KoinComponent {
|
||||||
|
|
||||||
var startDrag: ((TrackViewHolder) -> Unit)? = null
|
var startDrag: ((TrackViewHolder) -> Unit)? = null
|
||||||
|
|
||||||
// Set our layout files
|
// Set our layout files
|
||||||
val layout = R.layout.list_item_track
|
val layout = R.layout.list_item_track
|
||||||
private val contextMenuLayout = R.menu.context_menu_track
|
|
||||||
|
|
||||||
private val imageHelper: Utils.ImageHelper = Utils.ImageHelper(context)
|
private val imageHelper: Utils.ImageHelper = Utils.ImageHelper(context)
|
||||||
|
|
||||||
@ -62,7 +70,7 @@ class TrackViewBinder(
|
|||||||
|
|
||||||
holder.itemView.setOnLongClickListener {
|
holder.itemView.setOnLongClickListener {
|
||||||
if (onContextMenuClick != null) {
|
if (onContextMenuClick != null) {
|
||||||
val popup = Utils.createPopupMenu(holder.itemView, contextMenuLayout)
|
val popup = createContextMenu(holder.itemView, track)
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener { menuItem ->
|
popup.setOnMenuItemClickListener { menuItem ->
|
||||||
onContextMenuClick.invoke(menuItem, track)
|
onContextMenuClick.invoke(menuItem, track)
|
||||||
|
@ -16,6 +16,7 @@ import android.widget.ImageView
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.skydoves.colorpickerview.ColorPickerDialog
|
import com.skydoves.colorpickerview.ColorPickerDialog
|
||||||
@ -56,9 +57,6 @@ private const val DIALOG_PADDING = 12
|
|||||||
* Displays a form where server settings can be created / edited
|
* Displays a form where server settings can be created / edited
|
||||||
*/
|
*/
|
||||||
class EditServerFragment : Fragment(), OnBackPressedHandler {
|
class EditServerFragment : Fragment(), OnBackPressedHandler {
|
||||||
companion object {
|
|
||||||
const val EDIT_SERVER_INTENT_INDEX = "index"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val serverSettingsModel: ServerSettingsModel by viewModel()
|
private val serverSettingsModel: ServerSettingsModel by viewModel()
|
||||||
private val activeServerProvider: ActiveServerProvider by inject()
|
private val activeServerProvider: ActiveServerProvider by inject()
|
||||||
@ -79,6 +77,8 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
|
|||||||
private var currentColor: Int = 0
|
private var currentColor: Int = 0
|
||||||
private var selectedColor: Int? = null
|
private var selectedColor: Int? = null
|
||||||
|
|
||||||
|
private val navArgs by navArgs<EditServerFragmentArgs>()
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
Util.applyTheme(this.context)
|
Util.applyTheme(this.context)
|
||||||
@ -107,15 +107,10 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
|
|||||||
saveButton = view.findViewById(R.id.edit_save)
|
saveButton = view.findViewById(R.id.edit_save)
|
||||||
testButton = view.findViewById(R.id.edit_test)
|
testButton = view.findViewById(R.id.edit_test)
|
||||||
|
|
||||||
val index = arguments?.getInt(
|
if (navArgs.index != -1) {
|
||||||
EDIT_SERVER_INTENT_INDEX,
|
|
||||||
-1
|
|
||||||
) ?: -1
|
|
||||||
|
|
||||||
if (index != -1) {
|
|
||||||
// Editing an existing server
|
// Editing an existing server
|
||||||
FragmentTitle.setTitle(this, R.string.server_editor_label)
|
FragmentTitle.setTitle(this, R.string.server_editor_label)
|
||||||
val serverSetting = serverSettingsModel.getServerSetting(index)
|
val serverSetting = serverSettingsModel.getServerSetting(navArgs.index)
|
||||||
serverSetting.observe(
|
serverSetting.observe(
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) { t ->
|
) { t ->
|
||||||
|
@ -64,7 +64,7 @@ abstract class EntryListFragment<T : GenericEntry> : MultiListFragment<T>() {
|
|||||||
RxBus.musicFolderChangedEventObservable.subscribe {
|
RxBus.musicFolderChangedEventObservable.subscribe {
|
||||||
if (!listModel.isOffline()) {
|
if (!listModel.isOffline()) {
|
||||||
val currentSetting = listModel.activeServer
|
val currentSetting = listModel.activeServer
|
||||||
currentSetting.musicFolderId = it
|
currentSetting.musicFolderId = it.id
|
||||||
serverSettingsModel.updateItem(currentSetting)
|
serverSettingsModel.updateItem(currentSetting)
|
||||||
}
|
}
|
||||||
listModel.refresh(refreshListView!!)
|
listModel.refresh(refreshListView!!)
|
||||||
|
@ -14,8 +14,6 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.view.ContextMenu
|
|
||||||
import android.view.ContextMenu.ContextMenuInfo
|
|
||||||
import android.view.GestureDetector
|
import android.view.GestureDetector
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
@ -26,10 +24,10 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
import android.widget.AdapterView.AdapterContextMenuInfo
|
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.PopupMenu
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener
|
import android.widget.SeekBar.OnSeekBarChangeListener
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
@ -71,9 +69,11 @@ import org.koin.core.component.KoinComponent
|
|||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.adapters.BaseAdapter
|
import org.moire.ultrasonic.adapters.BaseAdapter
|
||||||
import org.moire.ultrasonic.adapters.TrackViewBinder
|
import org.moire.ultrasonic.adapters.TrackViewBinder
|
||||||
|
import org.moire.ultrasonic.api.subsonic.models.AlbumListType
|
||||||
import org.moire.ultrasonic.audiofx.EqualizerController
|
import org.moire.ultrasonic.audiofx.EqualizerController
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
||||||
import org.moire.ultrasonic.domain.Identifiable
|
import org.moire.ultrasonic.domain.Identifiable
|
||||||
|
import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
import org.moire.ultrasonic.domain.Track
|
import org.moire.ultrasonic.domain.Track
|
||||||
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
@ -85,7 +85,6 @@ import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
|
|||||||
import org.moire.ultrasonic.subsonic.ShareHandler
|
import org.moire.ultrasonic.subsonic.ShareHandler
|
||||||
import org.moire.ultrasonic.util.CancellationToken
|
import org.moire.ultrasonic.util.CancellationToken
|
||||||
import org.moire.ultrasonic.util.CommunicationError
|
import org.moire.ultrasonic.util.CommunicationError
|
||||||
import org.moire.ultrasonic.util.Constants
|
|
||||||
import org.moire.ultrasonic.util.Settings
|
import org.moire.ultrasonic.util.Settings
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
import org.moire.ultrasonic.util.toTrack
|
import org.moire.ultrasonic.util.toTrack
|
||||||
@ -346,8 +345,6 @@ class PlayerFragment :
|
|||||||
|
|
||||||
initPlaylistDisplay()
|
initPlaylistDisplay()
|
||||||
|
|
||||||
registerForContextMenu(playlistView)
|
|
||||||
|
|
||||||
EqualizerController.get().observe(
|
EqualizerController.get().observe(
|
||||||
requireActivity()
|
requireActivity()
|
||||||
) { equalizerController ->
|
) { equalizerController ->
|
||||||
@ -546,55 +543,54 @@ class PlayerFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) {
|
private fun onCreateContextMenu(view: View, track: Track): PopupMenu {
|
||||||
super.onCreateContextMenu(menu, view, menuInfo)
|
val popup = PopupMenu(view.context, view)
|
||||||
if (view === playlistView) {
|
val inflater: MenuInflater = popup.menuInflater
|
||||||
val info = menuInfo as AdapterContextMenuInfo?
|
inflater.inflate(R.menu.nowplaying_context, popup.menu)
|
||||||
val track = viewAdapter.getCurrentList()[info!!.position] as Track
|
|
||||||
val menuInflater = requireActivity().menuInflater
|
|
||||||
menuInflater.inflate(R.menu.nowplaying_context, menu)
|
|
||||||
|
|
||||||
if (track.parent == null) {
|
if (track.parent == null) {
|
||||||
val menuItem = menu.findItem(R.id.menu_show_album)
|
val menuItem = popup.menu.findItem(R.id.menu_show_album)
|
||||||
if (menuItem != null) {
|
if (menuItem != null) {
|
||||||
menuItem.isVisible = false
|
menuItem.isVisible = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOffline() || !Settings.shouldUseId3Tags) {
|
if (isOffline() || !Settings.shouldUseId3Tags) {
|
||||||
menu.findItem(R.id.menu_show_artist)?.isVisible = false
|
popup.menu.findItem(R.id.menu_show_artist)?.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOffline()) {
|
popup.menu.findItem(R.id.menu_lyrics)?.isVisible = !isOffline()
|
||||||
menu.findItem(R.id.menu_lyrics)?.isVisible = false
|
popup.show()
|
||||||
}
|
return popup
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
// TODO Why is Track null?
|
return menuItemSelected(item.itemId, currentSong) || super.onOptionsItemSelected(item)
|
||||||
return menuItemSelected(item.itemId, null) || super.onOptionsItemSelected(item)
|
}
|
||||||
|
|
||||||
|
private fun onContextMenuItemSelected(
|
||||||
|
menuItem: MenuItem,
|
||||||
|
item: MusicDirectory.Child
|
||||||
|
): Boolean {
|
||||||
|
if (item !is Track) return false
|
||||||
|
return menuItemSelected(menuItem.itemId, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("ComplexMethod", "LongMethod", "ReturnCount")
|
@Suppress("ComplexMethod", "LongMethod", "ReturnCount")
|
||||||
private fun menuItemSelected(menuItemId: Int, track: Track?): Boolean {
|
private fun menuItemSelected(menuItemId: Int, track: Track?): Boolean {
|
||||||
val bundle: Bundle
|
|
||||||
|
|
||||||
when (menuItemId) {
|
when (menuItemId) {
|
||||||
R.id.menu_show_artist -> {
|
R.id.menu_show_artist -> {
|
||||||
if (track == null) return false
|
if (track == null) return false
|
||||||
|
|
||||||
if (Settings.shouldUseId3Tags) {
|
if (Settings.shouldUseId3Tags) {
|
||||||
PlayerFragmentDirections.playerToSelectAlbum(
|
val action = PlayerFragmentDirections.playerToAlbumsList(
|
||||||
|
type = AlbumListType.BY_ARTIST,
|
||||||
id = track.artistId,
|
id = track.artistId,
|
||||||
name = track.artist,
|
title = track.artist,
|
||||||
parentId = track.artistId,
|
offset = 0,
|
||||||
isArtist = true,
|
size = 1000
|
||||||
)
|
)
|
||||||
bundle = Bundle()
|
findNavController().navigate(action)
|
||||||
|
|
||||||
Navigation.findNavController(requireView())
|
|
||||||
.navigate(R.id.playerToSelectAlbum, bundle)
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -614,11 +610,9 @@ class PlayerFragment :
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.menu_lyrics -> {
|
R.id.menu_lyrics -> {
|
||||||
if (track == null) return false
|
if (track?.artist == null || track.title == null) return false
|
||||||
bundle = Bundle()
|
val action = PlayerFragmentDirections.playerToLyrics(track.artist!!, track.title!!)
|
||||||
bundle.putString(Constants.INTENT_ARTIST, track.artist)
|
Navigation.findNavController(requireView()).navigate(action)
|
||||||
bundle.putString(Constants.INTENT_TITLE, track.title)
|
|
||||||
Navigation.findNavController(requireView()).navigate(R.id.playerToLyrics, bundle)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.menu_remove -> {
|
R.id.menu_remove -> {
|
||||||
@ -672,9 +666,9 @@ class PlayerFragment :
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.menu_item_star -> {
|
R.id.menu_item_star -> {
|
||||||
if (currentSong == null) return true
|
if (track == null) return true
|
||||||
|
|
||||||
val isStarred = currentSong!!.starred
|
val isStarred = track.starred
|
||||||
|
|
||||||
mediaPlayerController.controller?.setRating(
|
mediaPlayerController.controller?.setRating(
|
||||||
HeartRating(!isStarred)
|
HeartRating(!isStarred)
|
||||||
@ -685,10 +679,10 @@ class PlayerFragment :
|
|||||||
override fun onSuccess(result: SessionResult?) {
|
override fun onSuccess(result: SessionResult?) {
|
||||||
if (isStarred) {
|
if (isStarred) {
|
||||||
starMenuItem.setIcon(hollowStar)
|
starMenuItem.setIcon(hollowStar)
|
||||||
currentSong!!.starred = false
|
track.starred = false
|
||||||
} else {
|
} else {
|
||||||
starMenuItem.setIcon(fullStar)
|
starMenuItem.setIcon(fullStar)
|
||||||
currentSong!!.starred = true
|
track.starred = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,11 +698,11 @@ class PlayerFragment :
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.menu_item_bookmark_set -> {
|
R.id.menu_item_bookmark_set -> {
|
||||||
if (currentSong == null) return true
|
if (track == null) return true
|
||||||
|
|
||||||
val songId = currentSong!!.id
|
val songId = track.id
|
||||||
val playerPosition = mediaPlayerController.playerPosition
|
val playerPosition = mediaPlayerController.playerPosition
|
||||||
currentSong!!.bookmarkPosition = playerPosition
|
track.bookmarkPosition = playerPosition
|
||||||
val bookmarkTime = Util.formatTotalDuration(playerPosition.toLong(), true)
|
val bookmarkTime = Util.formatTotalDuration(playerPosition.toLong(), true)
|
||||||
Thread {
|
Thread {
|
||||||
val musicService = getMusicService()
|
val musicService = getMusicService()
|
||||||
@ -726,10 +720,10 @@ class PlayerFragment :
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.menu_item_bookmark_delete -> {
|
R.id.menu_item_bookmark_delete -> {
|
||||||
if (currentSong == null) return true
|
if (track == null) return true
|
||||||
|
|
||||||
val bookmarkSongId = currentSong!!.id
|
val bookmarkSongId = track.id
|
||||||
currentSong!!.bookmarkPosition = 0
|
track.bookmarkPosition = 0
|
||||||
Thread {
|
Thread {
|
||||||
val musicService = getMusicService()
|
val musicService = getMusicService()
|
||||||
try {
|
try {
|
||||||
@ -758,10 +752,10 @@ class PlayerFragment :
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.menu_item_share_song -> {
|
R.id.menu_item_share_song -> {
|
||||||
if (currentSong == null) return true
|
if (track == null) return true
|
||||||
|
|
||||||
val tracks: MutableList<Track?> = ArrayList()
|
val tracks: MutableList<Track?> = ArrayList()
|
||||||
tracks.add(currentSong)
|
tracks.add(track)
|
||||||
|
|
||||||
shareHandler.createShare(
|
shareHandler.createShare(
|
||||||
this,
|
this,
|
||||||
@ -856,6 +850,8 @@ class PlayerFragment :
|
|||||||
draggable = true,
|
draggable = true,
|
||||||
context = requireContext(),
|
context = requireContext(),
|
||||||
lifecycleOwner = viewLifecycleOwner,
|
lifecycleOwner = viewLifecycleOwner,
|
||||||
|
createContextMenu = { view, track -> onCreateContextMenu(view, track) },
|
||||||
|
onContextMenuClick = { menu, id -> onContextMenuItemSelected(menu, id) },
|
||||||
).apply {
|
).apply {
|
||||||
this.startDrag = { holder ->
|
this.startDrag = { holder ->
|
||||||
dragTouchHelper.startDrag(holder)
|
dragTouchHelper.startDrag(holder)
|
||||||
|
@ -19,6 +19,7 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
@ -46,7 +47,6 @@ import org.moire.ultrasonic.subsonic.ShareHandler
|
|||||||
import org.moire.ultrasonic.subsonic.VideoPlayer.Companion.playVideo
|
import org.moire.ultrasonic.subsonic.VideoPlayer.Companion.playVideo
|
||||||
import org.moire.ultrasonic.util.CancellationToken
|
import org.moire.ultrasonic.util.CancellationToken
|
||||||
import org.moire.ultrasonic.util.CommunicationError
|
import org.moire.ultrasonic.util.CommunicationError
|
||||||
import org.moire.ultrasonic.util.Constants
|
|
||||||
import org.moire.ultrasonic.util.Settings
|
import org.moire.ultrasonic.util.Settings
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
import org.moire.ultrasonic.util.Util.toast
|
import org.moire.ultrasonic.util.Util.toast
|
||||||
@ -54,8 +54,6 @@ 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
|
||||||
*
|
|
||||||
* TODO: Move to SafeArgs
|
|
||||||
*/
|
*/
|
||||||
class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
|
class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
|
||||||
private var searchResult: SearchResult? = null
|
private var searchResult: SearchResult? = null
|
||||||
@ -69,6 +67,8 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
|
|||||||
|
|
||||||
private var cancellationToken: CancellationToken? = null
|
private var cancellationToken: CancellationToken? = null
|
||||||
|
|
||||||
|
private val navArgs by navArgs<SearchFragmentArgs>()
|
||||||
|
|
||||||
override val listModel: SearchListModel by viewModels()
|
override val listModel: SearchListModel by viewModels()
|
||||||
|
|
||||||
override val mainLayout: Int = R.layout.search
|
override val mainLayout: Int = R.layout.search
|
||||||
@ -133,14 +133,10 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
|
|||||||
MoreButtonBinder()
|
MoreButtonBinder()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fragment was started with a query (e.g. from voice search), try to execute search right away
|
// If the fragment was started with a query (e.g. from voice search),
|
||||||
val arguments = arguments
|
// try to execute search right away
|
||||||
if (arguments != null) {
|
if (navArgs.query != null) {
|
||||||
val query = arguments.getString(Constants.INTENT_QUERY)
|
return search(navArgs.query!!, navArgs.autoplay)
|
||||||
val autoPlay = arguments.getBoolean(Constants.INTENT_AUTOPLAY, false)
|
|
||||||
if (query != null) {
|
|
||||||
return search(query, autoPlay)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,10 +152,8 @@ class SearchFragment : MultiListFragment<Identifiable>(), KoinComponent {
|
|||||||
val searchableInfo = searchManager.getSearchableInfo(requireActivity().componentName)
|
val searchableInfo = searchManager.getSearchableInfo(requireActivity().componentName)
|
||||||
searchView!!.setSearchableInfo(searchableInfo)
|
searchView!!.setSearchableInfo(searchableInfo)
|
||||||
|
|
||||||
val arguments = arguments
|
val autoPlay = navArgs.autoplay
|
||||||
val autoPlay = arguments != null &&
|
val query = navArgs.query
|
||||||
arguments.getBoolean(Constants.INTENT_AUTOPLAY, false)
|
|
||||||
val query = arguments?.getString(Constants.INTENT_QUERY)
|
|
||||||
|
|
||||||
// If started with a query, enter it to the searchView
|
// If started with a query, enter it to the searchView
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
|
@ -16,7 +16,6 @@ import org.moire.ultrasonic.adapters.ServerRowAdapter
|
|||||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
import org.moire.ultrasonic.data.ActiveServerProvider
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.OFFLINE_DB_ID
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.OFFLINE_DB_ID
|
||||||
import org.moire.ultrasonic.data.ServerSetting
|
import org.moire.ultrasonic.data.ServerSetting
|
||||||
import org.moire.ultrasonic.fragment.EditServerFragment.Companion.EDIT_SERVER_INTENT_INDEX
|
|
||||||
import org.moire.ultrasonic.model.ServerSettingsModel
|
import org.moire.ultrasonic.model.ServerSettingsModel
|
||||||
import org.moire.ultrasonic.service.MediaPlayerController
|
import org.moire.ultrasonic.service.MediaPlayerController
|
||||||
import org.moire.ultrasonic.util.ErrorDialog
|
import org.moire.ultrasonic.util.ErrorDialog
|
||||||
@ -25,8 +24,6 @@ import timber.log.Timber
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the list of configured servers, they can be selected or edited
|
* Displays the list of configured servers, they can be selected or edited
|
||||||
*
|
|
||||||
* TODO: Manage mode is unused. Remove it...
|
|
||||||
*/
|
*/
|
||||||
class ServerSelectorFragment : Fragment() {
|
class ServerSelectorFragment : Fragment() {
|
||||||
|
|
||||||
@ -143,8 +140,7 @@ class ServerSelectorFragment : Fragment() {
|
|||||||
* Starts the Edit Server Fragment to edit the details of a server
|
* Starts the Edit Server Fragment to edit the details of a server
|
||||||
*/
|
*/
|
||||||
private fun editServerByIndex(index: Int) {
|
private fun editServerByIndex(index: Int) {
|
||||||
val bundle = Bundle()
|
val action = ServerSelectorFragmentDirections.toEditServer(index)
|
||||||
bundle.putInt(EDIT_SERVER_INTENT_INDEX, index)
|
findNavController().navigate(action)
|
||||||
findNavController().navigate(R.id.serverSelectorToEditServer, bundle)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* LyricsFragment.kt
|
||||||
|
* Copyright (C) 2009-2022 Ultrasonic developers
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GNU GPLv3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.moire.ultrasonic.fragment.legacy
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
import org.moire.ultrasonic.R
|
||||||
|
import org.moire.ultrasonic.domain.Lyrics
|
||||||
|
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
|
||||||
|
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
|
||||||
|
import org.moire.ultrasonic.util.BackgroundTask
|
||||||
|
import org.moire.ultrasonic.util.CancellationToken
|
||||||
|
import org.moire.ultrasonic.util.FragmentBackgroundTask
|
||||||
|
import org.moire.ultrasonic.util.Util.applyTheme
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the lyrics of a song
|
||||||
|
*
|
||||||
|
* TODO: This file has been converted from Java, but not modernized yet.
|
||||||
|
*/
|
||||||
|
class LyricsFragment : Fragment() {
|
||||||
|
private var artistView: TextView? = null
|
||||||
|
private var titleView: TextView? = null
|
||||||
|
private var textView: TextView? = null
|
||||||
|
private var swipe: SwipeRefreshLayout? = null
|
||||||
|
private var cancellationToken: CancellationToken? = null
|
||||||
|
|
||||||
|
private val navArgs by navArgs<LyricsFragmentArgs>()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
applyTheme(this.context)
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
return inflater.inflate(R.layout.lyrics, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
cancellationToken = CancellationToken()
|
||||||
|
Timber.d("Lyrics set title")
|
||||||
|
setTitle(this, R.string.download_menu_lyrics)
|
||||||
|
swipe = view.findViewById(R.id.lyrics_refresh)
|
||||||
|
swipe?.isEnabled = false
|
||||||
|
artistView = view.findViewById(R.id.lyrics_artist)
|
||||||
|
titleView = view.findViewById(R.id.lyrics_title)
|
||||||
|
textView = view.findViewById(R.id.lyrics_text)
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
cancellationToken!!.cancel()
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun load() {
|
||||||
|
val task: BackgroundTask<Lyrics> = object : FragmentBackgroundTask<Lyrics>(
|
||||||
|
activity, true, swipe, cancellationToken
|
||||||
|
) {
|
||||||
|
@Throws(Throwable::class)
|
||||||
|
override fun doInBackground(): Lyrics {
|
||||||
|
val musicService = getMusicService()
|
||||||
|
return musicService.getLyrics(navArgs.artist, navArgs.title)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun done(result: Lyrics) {
|
||||||
|
if (result.artist != null) {
|
||||||
|
artistView!!.text = result.artist
|
||||||
|
titleView!!.text = result.title
|
||||||
|
textView!!.text = result.text
|
||||||
|
} else {
|
||||||
|
artistView!!.setText(R.string.lyrics_nomatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task.execute()
|
||||||
|
}
|
||||||
|
}
|
@ -28,9 +28,6 @@ import timber.log.Timber
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for handling received events for the Media Player implementation
|
* This class is responsible for handling received events for the Media Player implementation
|
||||||
*
|
|
||||||
* TODO: Remove this class. Each component should listen to the lifecycleEvents and act on them
|
|
||||||
* independently
|
|
||||||
*/
|
*/
|
||||||
class MediaPlayerLifecycleSupport : KoinComponent {
|
class MediaPlayerLifecycleSupport : KoinComponent {
|
||||||
private val playbackStateSerializer by inject<PlaybackStateSerializer>()
|
private val playbackStateSerializer by inject<PlaybackStateSerializer>()
|
||||||
|
@ -25,9 +25,9 @@ class RxBus {
|
|||||||
val themeChangedEventObservable: Observable<Unit> =
|
val themeChangedEventObservable: Observable<Unit> =
|
||||||
themeChangedEventPublisher.observeOn(mainThread())
|
themeChangedEventPublisher.observeOn(mainThread())
|
||||||
|
|
||||||
val musicFolderChangedEventPublisher: PublishSubject<String> =
|
val musicFolderChangedEventPublisher: PublishSubject<Folder> =
|
||||||
PublishSubject.create()
|
PublishSubject.create()
|
||||||
val musicFolderChangedEventObservable: Observable<String> =
|
val musicFolderChangedEventObservable: Observable<Folder> =
|
||||||
musicFolderChangedEventPublisher.observeOn(mainThread())
|
musicFolderChangedEventPublisher.observeOn(mainThread())
|
||||||
|
|
||||||
val playerStatePublisher: PublishSubject<StateWithTrack> =
|
val playerStatePublisher: PublishSubject<StateWithTrack> =
|
||||||
@ -93,6 +93,10 @@ class RxBus {
|
|||||||
val state: DownloadStatus,
|
val state: DownloadStatus,
|
||||||
val progress: Int?
|
val progress: Int?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class Folder(
|
||||||
|
val id: String?
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
|
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
|
||||||
|
@ -15,14 +15,6 @@ object Constants {
|
|||||||
const val REST_PROTOCOL_VERSION = "1.7.0"
|
const val REST_PROTOCOL_VERSION = "1.7.0"
|
||||||
const val REST_CLIENT_ID = "Ultrasonic"
|
const val REST_CLIENT_ID = "Ultrasonic"
|
||||||
|
|
||||||
// Legacy names for intent extras, in those fragments which don't use SafeArgs yet.
|
|
||||||
const val INTENT_ARTIST = "subsonic.artist"
|
|
||||||
const val INTENT_TITLE = "subsonic.title"
|
|
||||||
const val INTENT_AUTOPLAY = "subsonic.playall"
|
|
||||||
const val INTENT_QUERY = "subsonic.query"
|
|
||||||
const val INTENT_ALBUM_LIST_TYPE = "subsonic.albumlisttype"
|
|
||||||
const val INTENT_SHOW_PLAYER = "subsonic.showplayer"
|
|
||||||
|
|
||||||
// Names for Intent Actions
|
// Names for Intent Actions
|
||||||
const val CMD_PROCESS_KEYCODE = "org.moire.ultrasonic.CMD_PROCESS_KEYCODE"
|
const val CMD_PROCESS_KEYCODE = "org.moire.ultrasonic.CMD_PROCESS_KEYCODE"
|
||||||
const val CMD_PLAY = "org.moire.ultrasonic.CMD_PLAY"
|
const val CMD_PLAY = "org.moire.ultrasonic.CMD_PLAY"
|
||||||
@ -32,6 +24,7 @@ object Constants {
|
|||||||
const val CMD_STOP = "org.moire.ultrasonic.CMD_STOP"
|
const val CMD_STOP = "org.moire.ultrasonic.CMD_STOP"
|
||||||
const val CMD_PREVIOUS = "org.moire.ultrasonic.CMD_PREVIOUS"
|
const val CMD_PREVIOUS = "org.moire.ultrasonic.CMD_PREVIOUS"
|
||||||
const val CMD_NEXT = "org.moire.ultrasonic.CMD_NEXT"
|
const val CMD_NEXT = "org.moire.ultrasonic.CMD_NEXT"
|
||||||
|
const val INTENT_SHOW_PLAYER = "org.moire.ultrasonic.SHOW_PLAYER"
|
||||||
|
|
||||||
// Legacy Preferences keys
|
// Legacy Preferences keys
|
||||||
// Warning: Don't add any new here!
|
// Warning: Don't add any new here!
|
||||||
|
@ -35,6 +35,11 @@
|
|||||||
a:icon="@drawable/ic_menu_remove_all"
|
a:icon="@drawable/ic_menu_remove_all"
|
||||||
app:showAsAction="ifRoom|withText"
|
app:showAsAction="ifRoom|withText"
|
||||||
a:title="@string/download.menu_clear_playlist"/>
|
a:title="@string/download.menu_clear_playlist"/>
|
||||||
|
<item
|
||||||
|
a:id="@+id/menu_lyrics"
|
||||||
|
a:icon="@drawable/ic_library"
|
||||||
|
app:showAsAction="ifRoom|withText"
|
||||||
|
a:title="@string/download.menu_lyrics"/>
|
||||||
<item
|
<item
|
||||||
a:id="@+id/menu_item_bookmark_set"
|
a:id="@+id/menu_item_bookmark_set"
|
||||||
a:icon="@drawable/ic_menu_bookmark"
|
a:icon="@drawable/ic_menu_bookmark"
|
||||||
|
@ -212,6 +212,15 @@
|
|||||||
<action
|
<action
|
||||||
android:id="@+id/searchToAlbumsList"
|
android:id="@+id/searchToAlbumsList"
|
||||||
app:destination="@id/albumListFragment" />
|
app:destination="@id/albumListFragment" />
|
||||||
|
<argument
|
||||||
|
android:name="query"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="true"
|
||||||
|
android:defaultValue="@null" />
|
||||||
|
<argument
|
||||||
|
android:name="autoplay"
|
||||||
|
app:argType="boolean"
|
||||||
|
android:defaultValue="false" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/playlistsFragment"
|
android:id="@+id/playlistsFragment"
|
||||||
@ -263,6 +272,9 @@
|
|||||||
<action
|
<action
|
||||||
android:id="@+id/playerToSelectAlbum"
|
android:id="@+id/playerToSelectAlbum"
|
||||||
app:destination="@id/trackCollectionFragment" />
|
app:destination="@id/trackCollectionFragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/playerToAlbumsList"
|
||||||
|
app:destination="@id/albumListFragment" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/playerToLyrics"
|
android:id="@+id/playerToLyrics"
|
||||||
app:destination="@id/lyricsFragment" />
|
app:destination="@id/lyricsFragment" />
|
||||||
@ -272,7 +284,14 @@
|
|||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/lyricsFragment"
|
android:id="@+id/lyricsFragment"
|
||||||
android:name="org.moire.ultrasonic.fragment.LyricsFragment" />
|
android:name="org.moire.ultrasonic.fragment.legacy.LyricsFragment" >
|
||||||
|
<argument
|
||||||
|
android:name="artist"
|
||||||
|
app:argType="string" />
|
||||||
|
<argument
|
||||||
|
android:name="title"
|
||||||
|
app:argType="string" />
|
||||||
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/equalizerFragment"
|
android:id="@+id/equalizerFragment"
|
||||||
android:name="org.moire.ultrasonic.fragment.EqualizerFragment" />
|
android:name="org.moire.ultrasonic.fragment.EqualizerFragment" />
|
||||||
@ -280,10 +299,18 @@
|
|||||||
android:id="@+id/serverSelectorFragment"
|
android:id="@+id/serverSelectorFragment"
|
||||||
android:name="org.moire.ultrasonic.fragment.ServerSelectorFragment" >
|
android:name="org.moire.ultrasonic.fragment.ServerSelectorFragment" >
|
||||||
<action
|
<action
|
||||||
android:id="@+id/serverSelectorToEditServer"
|
android:id="@+id/toEditServer"
|
||||||
app:destination="@id/editServerFragment" />
|
app:destination="@id/editServerFragment" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/editServerFragment"
|
android:id="@+id/editServerFragment"
|
||||||
android:name="org.moire.ultrasonic.fragment.EditServerFragment" />
|
android:name="org.moire.ultrasonic.fragment.EditServerFragment" >
|
||||||
|
<argument
|
||||||
|
android:name="index"
|
||||||
|
app:argType="integer"
|
||||||
|
android:defaultValue="-1" />
|
||||||
|
</fragment>
|
||||||
|
<action
|
||||||
|
android:id="@+id/toSearchFragment"
|
||||||
|
app:destination="@id/searchFragment" />
|
||||||
</navigation>
|
</navigation>
|
Loading…
x
Reference in New Issue
Block a user