mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-07 15:28:40 +01:00
Refactored DownloadActivity
This commit is contained in:
parent
95773c7994
commit
a395bd6feb
@ -30,10 +30,11 @@
|
||||
<activity android:name=".activity.NavigationActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/common.appname"
|
||||
android:launchMode="standard">
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.SEARCH"/>
|
||||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@ -43,59 +44,11 @@
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable"/>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.MainActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/common.appname"
|
||||
android:launchMode="standard">
|
||||
<!--<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>-->
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.SelectAlbumActivity"
|
||||
android:configChanges="orientation|keyboardHidden"/>
|
||||
<activity
|
||||
android:name=".activity.SearchActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/search.label"
|
||||
android:launchMode="singleTask"/>
|
||||
<activity
|
||||
android:name=".activity.DownloadActivity"
|
||||
android:configChanges="keyboardHidden"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="true" />
|
||||
<activity
|
||||
android:name=".activity.LyricsActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:launchMode="singleTask"/>
|
||||
<activity
|
||||
android:name=".activity.EqualizerActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/equalizer.label"
|
||||
android:launchMode="singleTask"/>
|
||||
<activity
|
||||
android:name=".activity.VoiceQueryReceiverActivity"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- <activity
|
||||
android:name=".activity.QueryReceiverActivity"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable"/>
|
||||
</activity>
|
||||
-->
|
||||
<activity
|
||||
android:name=".activity.ServerSelectorActivity"
|
||||
android:label="@string/server_selector.label" />
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,89 +0,0 @@
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
package org.moire.ultrasonic.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
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.Constants;
|
||||
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
||||
|
||||
/**
|
||||
* Displays song lyrics.
|
||||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public final class LyricsActivity extends SubsonicTabActivity
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle)
|
||||
{
|
||||
super.onCreate(bundle);
|
||||
setContentView(R.layout.lyrics);
|
||||
|
||||
View nowPlayingMenuItem = findViewById(R.id.menu_now_playing);
|
||||
menuDrawer.setActiveView(nowPlayingMenuItem);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
private void load()
|
||||
{
|
||||
BackgroundTask<Lyrics> task = new TabActivityBackgroundTask<Lyrics>(this, true)
|
||||
{
|
||||
@Override
|
||||
protected Lyrics doInBackground() throws Throwable
|
||||
{
|
||||
String artist = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ARTIST);
|
||||
String title = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_TITLE);
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(LyricsActivity.this);
|
||||
return musicService.getLyrics(artist, title, LyricsActivity.this, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(Lyrics result)
|
||||
{
|
||||
TextView artistView = (TextView) findViewById(R.id.lyrics_artist);
|
||||
TextView titleView = (TextView) findViewById(R.id.lyrics_title);
|
||||
TextView textView = (TextView) findViewById(R.id.lyrics_text);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
package org.moire.ultrasonic.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider;
|
||||
import org.moire.ultrasonic.data.ServerSetting;
|
||||
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.FileUtil;
|
||||
import org.moire.ultrasonic.util.MergeAdapter;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.koin.android.viewmodel.compat.ViewModelCompat.viewModel;
|
||||
import static org.koin.java.KoinJavaComponent.inject;
|
||||
|
||||
public class MainActivity extends SubsonicTabActivity
|
||||
{
|
||||
private static boolean infoDialogDisplayed;
|
||||
private static boolean shouldUseId3;
|
||||
private static String lastActiveServerProperties;
|
||||
|
||||
private Lazy<MediaPlayerLifecycleSupport> lifecycleSupport = inject(MediaPlayerLifecycleSupport.class);
|
||||
private Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class);
|
||||
private Lazy<ServerSettingsModel> serverSettingsModel = viewModel(this, ServerSettingsModel.class);
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.main);
|
||||
|
||||
final View homeMenuItem = findViewById(R.id.menu_home);
|
||||
menuDrawer.setActiveView(homeMenuItem);
|
||||
|
||||
setActionBarTitle(R.string.common_appname);
|
||||
setTitle(R.string.common_appname);
|
||||
|
||||
// Remember the current theme.
|
||||
theme = Util.getTheme(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu)
|
||||
{
|
||||
final MenuInflater menuInflater = getMenuInflater();
|
||||
menuInflater.inflate(R.menu.main, menu);
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item)
|
||||
{
|
||||
switch (item.getItemId())
|
||||
{
|
||||
case android.R.id.home:
|
||||
menuDrawer.toggleMenu();
|
||||
return true;
|
||||
case R.id.main_shuffle:
|
||||
final Intent intent1 = new Intent(this, DownloadActivity.class);
|
||||
intent1.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
|
||||
startActivityForResultWithoutTransition(this, intent1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
package org.moire.ultrasonic.activity;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchRecentSuggestions;
|
||||
|
||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
/**
|
||||
* Receives search queries and forwards to the SelectAlbumActivity.
|
||||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class QueryReceiverActivity extends ResultActivity
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String query = getIntent().getStringExtra(SearchManager.QUERY);
|
||||
|
||||
if (query != null)
|
||||
{
|
||||
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE);
|
||||
suggestions.saveRecentQuery(query, null);
|
||||
|
||||
Intent intent = new Intent(QueryReceiverActivity.this, SearchActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
|
||||
startActivityForResultWithoutTransition(QueryReceiverActivity.this, intent);
|
||||
}
|
||||
finish();
|
||||
Util.disablePendingTransition(this);
|
||||
}
|
||||
}
|
@ -1,554 +0,0 @@
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
package org.moire.ultrasonic.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider;
|
||||
import org.moire.ultrasonic.domain.Artist;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
import org.moire.ultrasonic.domain.SearchCriteria;
|
||||
import org.moire.ultrasonic.domain.SearchResult;
|
||||
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||
import org.moire.ultrasonic.service.MusicService;
|
||||
import org.moire.ultrasonic.service.MusicServiceFactory;
|
||||
import org.moire.ultrasonic.subsonic.VideoPlayer;
|
||||
import org.moire.ultrasonic.util.BackgroundTask;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.MergeAdapter;
|
||||
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
import org.moire.ultrasonic.view.ArtistAdapter;
|
||||
import org.moire.ultrasonic.view.EntryAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import kotlin.Lazy;
|
||||
|
||||
import static org.koin.java.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* Performs searches and displays the matching artists, albums and songs.
|
||||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class SearchActivity extends SubsonicTabActivity
|
||||
{
|
||||
|
||||
private static int DEFAULT_ARTISTS;
|
||||
private static int DEFAULT_ALBUMS;
|
||||
private static int DEFAULT_SONGS;
|
||||
|
||||
private ListView list;
|
||||
|
||||
private View artistsHeading;
|
||||
private View albumsHeading;
|
||||
private View songsHeading;
|
||||
private TextView searchButton;
|
||||
private View moreArtistsButton;
|
||||
private View moreAlbumsButton;
|
||||
private View moreSongsButton;
|
||||
private SearchResult searchResult;
|
||||
private MergeAdapter mergeAdapter;
|
||||
private ArtistAdapter artistAdapter;
|
||||
private ListAdapter moreArtistsAdapter;
|
||||
private EntryAdapter albumAdapter;
|
||||
private ListAdapter moreAlbumsAdapter;
|
||||
private ListAdapter moreSongsAdapter;
|
||||
private EntryAdapter songAdapter;
|
||||
|
||||
private final Lazy<VideoPlayer> videoPlayer = inject(VideoPlayer.class);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.search);
|
||||
|
||||
setActionBarTitle(R.string.common_appname);
|
||||
setActionBarSubtitle(R.string.search_title);
|
||||
|
||||
View searchMenuItem = findViewById(R.id.menu_search);
|
||||
menuDrawer.setActiveView(searchMenuItem);
|
||||
|
||||
DEFAULT_ARTISTS = Util.getDefaultArtists(this);
|
||||
DEFAULT_ALBUMS = Util.getDefaultAlbums(this);
|
||||
DEFAULT_SONGS = Util.getDefaultSongs(this);
|
||||
|
||||
View buttons = LayoutInflater.from(this).inflate(R.layout.search_buttons, null);
|
||||
|
||||
if (buttons != null)
|
||||
{
|
||||
artistsHeading = buttons.findViewById(R.id.search_artists);
|
||||
albumsHeading = buttons.findViewById(R.id.search_albums);
|
||||
songsHeading = buttons.findViewById(R.id.search_songs);
|
||||
searchButton = (TextView) buttons.findViewById(R.id.search_search);
|
||||
moreArtistsButton = buttons.findViewById(R.id.search_more_artists);
|
||||
moreAlbumsButton = buttons.findViewById(R.id.search_more_albums);
|
||||
moreSongsButton = buttons.findViewById(R.id.search_more_songs);
|
||||
}
|
||||
|
||||
list = (ListView) findViewById(R.id.search_list);
|
||||
|
||||
list.setOnItemClickListener(new AdapterView.OnItemClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
|
||||
{
|
||||
if (view == searchButton)
|
||||
{
|
||||
onSearchRequested();
|
||||
}
|
||||
else if (view == moreArtistsButton)
|
||||
{
|
||||
expandArtists();
|
||||
}
|
||||
else if (view == moreAlbumsButton)
|
||||
{
|
||||
expandAlbums();
|
||||
}
|
||||
else if (view == moreSongsButton)
|
||||
{
|
||||
expandSongs();
|
||||
}
|
||||
else
|
||||
{
|
||||
Object item = parent.getItemAtPosition(position);
|
||||
if (item instanceof Artist)
|
||||
{
|
||||
onArtistSelected((Artist) item);
|
||||
}
|
||||
else if (item instanceof MusicDirectory.Entry)
|
||||
{
|
||||
MusicDirectory.Entry entry = (MusicDirectory.Entry) item;
|
||||
if (entry.isDirectory())
|
||||
{
|
||||
onAlbumSelected(entry, false);
|
||||
}
|
||||
else if (entry.isVideo())
|
||||
{
|
||||
onVideoSelected(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
onSongSelected(entry, false, true, true, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
registerForContextMenu(list);
|
||||
|
||||
onNewIntent(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent)
|
||||
{
|
||||
super.onNewIntent(intent);
|
||||
String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
|
||||
boolean autoPlay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
|
||||
boolean requestSearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false);
|
||||
|
||||
if (query != null)
|
||||
{
|
||||
mergeAdapter = new MergeAdapter();
|
||||
list.setAdapter(mergeAdapter);
|
||||
search(query, autoPlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
populateList();
|
||||
if (requestSearch) onSearchRequested();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo)
|
||||
{
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
Object selectedItem = list.getItemAtPosition(info.position);
|
||||
|
||||
boolean isArtist = selectedItem instanceof Artist;
|
||||
boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory();
|
||||
|
||||
if (!isArtist && !isAlbum)
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.select_song_context, menu);
|
||||
}
|
||||
else
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.select_album_context, menu);
|
||||
}
|
||||
|
||||
MenuItem shareButton = menu.findItem(R.id.menu_item_share);
|
||||
MenuItem downloadMenuItem = menu.findItem(R.id.album_menu_download);
|
||||
|
||||
if (downloadMenuItem != null)
|
||||
{
|
||||
downloadMenuItem.setVisible(!ActiveServerProvider.Companion.isOffline(this));
|
||||
}
|
||||
|
||||
if (ActiveServerProvider.Companion.isOffline(this) || isArtist)
|
||||
{
|
||||
if (shareButton != null)
|
||||
{
|
||||
shareButton.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem)
|
||||
{
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Object selectedItem = list.getItemAtPosition(info.position);
|
||||
|
||||
Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null;
|
||||
Entry entry = selectedItem instanceof Entry ? (Entry) selectedItem : null;
|
||||
|
||||
String entryId = null;
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
entryId = entry.getId();
|
||||
}
|
||||
|
||||
String id = artist != null ? artist.getId() : entryId;
|
||||
|
||||
if (id == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
List<Entry> songs = new ArrayList<Entry>(1);
|
||||
|
||||
switch (menuItem.getItemId())
|
||||
{
|
||||
case R.id.album_menu_play_now:
|
||||
downloadRecursively(id, false, false, true, false, false, false, false, false);
|
||||
break;
|
||||
case R.id.album_menu_play_next:
|
||||
downloadRecursively(id, false, true, false, true, false, true, false, false);
|
||||
break;
|
||||
case R.id.album_menu_play_last:
|
||||
downloadRecursively(id, false, true, false, false, false, false, false, false);
|
||||
break;
|
||||
case R.id.album_menu_pin:
|
||||
downloadRecursively(id, true, true, false, false, false, false, false, false);
|
||||
break;
|
||||
case R.id.album_menu_unpin:
|
||||
downloadRecursively(id, false, false, false, false, false, false, true, false);
|
||||
break;
|
||||
case R.id.album_menu_download:
|
||||
downloadRecursively(id, false, false, false, false, true, false, false, false);
|
||||
break;
|
||||
case R.id.song_menu_play_now:
|
||||
if (entry != null)
|
||||
{
|
||||
songs = new ArrayList<MusicDirectory.Entry>(1);
|
||||
songs.add(entry);
|
||||
download(false, false, true, false, false, songs);
|
||||
}
|
||||
break;
|
||||
case R.id.song_menu_play_next:
|
||||
if (entry != null)
|
||||
{
|
||||
songs = new ArrayList<MusicDirectory.Entry>(1);
|
||||
songs.add(entry);
|
||||
download(true, false, false, true, false, songs);
|
||||
}
|
||||
break;
|
||||
case R.id.song_menu_play_last:
|
||||
if (entry != null)
|
||||
{
|
||||
songs = new ArrayList<MusicDirectory.Entry>(1);
|
||||
songs.add(entry);
|
||||
download(true, false, false, false, false, songs);
|
||||
}
|
||||
break;
|
||||
case R.id.song_menu_pin:
|
||||
if (entry != null)
|
||||
{
|
||||
songs.add(entry);
|
||||
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size(), songs.size()));
|
||||
downloadBackground(true, songs);
|
||||
}
|
||||
break;
|
||||
case R.id.song_menu_download:
|
||||
if (entry != null)
|
||||
{
|
||||
songs.add(entry);
|
||||
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_downloaded, songs.size(), songs.size()));
|
||||
downloadBackground(false, songs);
|
||||
}
|
||||
break;
|
||||
case R.id.song_menu_unpin:
|
||||
if (entry != null)
|
||||
{
|
||||
songs.add(entry);
|
||||
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_unpinned, songs.size(), songs.size()));
|
||||
getMediaPlayerController().unpin(songs);
|
||||
}
|
||||
break;
|
||||
case R.id.menu_item_share:
|
||||
if (entry != null)
|
||||
{
|
||||
songs = new ArrayList<MusicDirectory.Entry>(1);
|
||||
songs.add(entry);
|
||||
createShare(songs);
|
||||
}
|
||||
default:
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs)
|
||||
{
|
||||
if (getMediaPlayerController() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable onValid = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
warnIfNetworkOrStorageUnavailable();
|
||||
getMediaPlayerController().downloadBackground(songs, save);
|
||||
}
|
||||
};
|
||||
|
||||
checkLicenseAndTrialPeriod(onValid);
|
||||
}
|
||||
|
||||
private void search(final String query, final boolean autoplay)
|
||||
{
|
||||
final int maxArtists = Util.getMaxArtists(this);
|
||||
final int maxAlbums = Util.getMaxAlbums(this);
|
||||
final int maxSongs = Util.getMaxSongs(this);
|
||||
|
||||
BackgroundTask<SearchResult> task = new TabActivityBackgroundTask<SearchResult>(this, true)
|
||||
{
|
||||
@Override
|
||||
protected SearchResult doInBackground() throws Throwable
|
||||
{
|
||||
SearchCriteria criteria = new SearchCriteria(query, maxArtists, maxAlbums, maxSongs);
|
||||
MusicService service = MusicServiceFactory.getMusicService(SearchActivity.this);
|
||||
licenseValid = service.isLicenseValid(SearchActivity.this, this);
|
||||
return service.search(criteria, SearchActivity.this, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(SearchResult result)
|
||||
{
|
||||
searchResult = result;
|
||||
|
||||
populateList();
|
||||
|
||||
if (autoplay)
|
||||
{
|
||||
autoplay();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
task.execute();
|
||||
}
|
||||
|
||||
private void populateList()
|
||||
{
|
||||
mergeAdapter = new MergeAdapter();
|
||||
mergeAdapter.addView(searchButton, true);
|
||||
|
||||
if (searchResult != null)
|
||||
{
|
||||
List<Artist> artists = searchResult.getArtists();
|
||||
if (!artists.isEmpty())
|
||||
{
|
||||
mergeAdapter.addView(artistsHeading);
|
||||
List<Artist> displayedArtists = new ArrayList<Artist>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size())));
|
||||
artistAdapter = new ArtistAdapter(this, displayedArtists);
|
||||
mergeAdapter.addAdapter(artistAdapter);
|
||||
if (artists.size() > DEFAULT_ARTISTS)
|
||||
{
|
||||
moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true);
|
||||
}
|
||||
}
|
||||
|
||||
List<MusicDirectory.Entry> albums = searchResult.getAlbums();
|
||||
if (!albums.isEmpty())
|
||||
{
|
||||
mergeAdapter.addView(albumsHeading);
|
||||
List<MusicDirectory.Entry> displayedAlbums = new ArrayList<MusicDirectory.Entry>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size())));
|
||||
albumAdapter = new EntryAdapter(this, imageLoader.getValue().getImageLoader(), displayedAlbums, false);
|
||||
mergeAdapter.addAdapter(albumAdapter);
|
||||
if (albums.size() > DEFAULT_ALBUMS)
|
||||
{
|
||||
moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true);
|
||||
}
|
||||
}
|
||||
|
||||
List<MusicDirectory.Entry> songs = searchResult.getSongs();
|
||||
if (!songs.isEmpty())
|
||||
{
|
||||
mergeAdapter.addView(songsHeading);
|
||||
List<MusicDirectory.Entry> displayedSongs = new ArrayList<MusicDirectory.Entry>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size())));
|
||||
songAdapter = new EntryAdapter(this, imageLoader.getValue().getImageLoader(), displayedSongs, false);
|
||||
mergeAdapter.addAdapter(songAdapter);
|
||||
if (songs.size() > DEFAULT_SONGS)
|
||||
{
|
||||
moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true);
|
||||
}
|
||||
}
|
||||
|
||||
boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty();
|
||||
searchButton.setText(empty ? R.string.search_no_match : R.string.search_search);
|
||||
}
|
||||
|
||||
list.setAdapter(mergeAdapter);
|
||||
}
|
||||
|
||||
private void expandArtists()
|
||||
{
|
||||
artistAdapter.clear();
|
||||
|
||||
for (Artist artist : searchResult.getArtists())
|
||||
{
|
||||
artistAdapter.add(artist);
|
||||
}
|
||||
|
||||
artistAdapter.notifyDataSetChanged();
|
||||
mergeAdapter.removeAdapter(moreArtistsAdapter);
|
||||
mergeAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void expandAlbums()
|
||||
{
|
||||
albumAdapter.clear();
|
||||
|
||||
for (MusicDirectory.Entry album : searchResult.getAlbums())
|
||||
{
|
||||
albumAdapter.add(album);
|
||||
}
|
||||
|
||||
albumAdapter.notifyDataSetChanged();
|
||||
mergeAdapter.removeAdapter(moreAlbumsAdapter);
|
||||
mergeAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void expandSongs()
|
||||
{
|
||||
songAdapter.clear();
|
||||
|
||||
for (MusicDirectory.Entry song : searchResult.getSongs())
|
||||
{
|
||||
songAdapter.add(song);
|
||||
}
|
||||
|
||||
songAdapter.notifyDataSetChanged();
|
||||
mergeAdapter.removeAdapter(moreSongsAdapter);
|
||||
mergeAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void onArtistSelected(Artist artist)
|
||||
{
|
||||
Intent intent = new Intent(this, SelectAlbumActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
|
||||
startActivityForResultWithoutTransition(this, intent);
|
||||
}
|
||||
|
||||
private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay)
|
||||
{
|
||||
Intent intent = new Intent(SearchActivity.this, SelectAlbumActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, album.getId());
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle());
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, album.isDirectory());
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay);
|
||||
startActivityForResultWithoutTransition(SearchActivity.this, intent);
|
||||
}
|
||||
|
||||
private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext)
|
||||
{
|
||||
MediaPlayerController mediaPlayerController = getMediaPlayerController();
|
||||
if (mediaPlayerController != null)
|
||||
{
|
||||
if (!append && !playNext)
|
||||
{
|
||||
mediaPlayerController.clear();
|
||||
}
|
||||
|
||||
mediaPlayerController.download(Collections.singletonList(song), save, false, playNext, false, false);
|
||||
|
||||
if (autoplay)
|
||||
{
|
||||
mediaPlayerController.play(mediaPlayerController.getPlaylistSize() - 1);
|
||||
}
|
||||
|
||||
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
private void onVideoSelected(MusicDirectory.Entry entry)
|
||||
{
|
||||
videoPlayer.getValue().playVideo(entry);
|
||||
}
|
||||
|
||||
private void autoplay()
|
||||
{
|
||||
if (!searchResult.getSongs().isEmpty())
|
||||
{
|
||||
onSongSelected(searchResult.getSongs().get(0), false, false, true, false);
|
||||
}
|
||||
else if (!searchResult.getAlbums().isEmpty())
|
||||
{
|
||||
onAlbumSelected(searchResult.getAlbums().get(0), true);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
package org.moire.ultrasonic.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.Share;
|
||||
import org.moire.ultrasonic.service.DownloadFile;
|
||||
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||
import org.moire.ultrasonic.service.MusicService;
|
||||
import org.moire.ultrasonic.service.MusicServiceFactory;
|
||||
import org.moire.ultrasonic.util.AlbumHeader;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator;
|
||||
import org.moire.ultrasonic.util.Pair;
|
||||
import org.moire.ultrasonic.util.TabActivityBackgroundTask;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
import org.moire.ultrasonic.view.AlbumView;
|
||||
import org.moire.ultrasonic.view.EntryAdapter;
|
||||
import org.moire.ultrasonic.view.SongView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class SelectAlbumActivity extends SubsonicTabActivity
|
||||
{
|
||||
|
||||
public static final String allSongsId = "-1";
|
||||
private SwipeRefreshLayout refreshAlbumListView;
|
||||
private ListView albumListView;
|
||||
private View header;
|
||||
private View albumButtons;
|
||||
private View emptyView;
|
||||
private ImageView selectButton;
|
||||
private ImageView playNowButton;
|
||||
private ImageView playNextButton;
|
||||
private ImageView playLastButton;
|
||||
private ImageView pinButton;
|
||||
private ImageView unpinButton;
|
||||
private ImageView downloadButton;
|
||||
private ImageView deleteButton;
|
||||
private ImageView moreButton;
|
||||
private boolean playAllButtonVisible;
|
||||
private boolean shareButtonVisible;
|
||||
private MenuItem playAllButton;
|
||||
private MenuItem shareButton;
|
||||
private boolean showHeader = true;
|
||||
private Random random = new java.security.SecureRandom();
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.select_album);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu)
|
||||
{
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
playAllButton = menu.findItem(R.id.select_album_play_all);
|
||||
|
||||
if (playAllButton != null)
|
||||
{
|
||||
playAllButton.setVisible(playAllButtonVisible);
|
||||
}
|
||||
|
||||
shareButton = menu.findItem(R.id.menu_item_share);
|
||||
|
||||
if (shareButton != null)
|
||||
{
|
||||
shareButton.setVisible(shareButtonVisible);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.select_album, menu);
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
switch (item.getItemId())
|
||||
{
|
||||
case android.R.id.home:
|
||||
menuDrawer.toggleMenu();
|
||||
return true;
|
||||
case R.id.main_shuffle:
|
||||
Intent intent1 = new Intent(this, DownloadActivity.class);
|
||||
intent1.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
|
||||
startActivityForResultWithoutTransition(this, intent1);
|
||||
return true;
|
||||
case R.id.select_album_play_all:
|
||||
// TODO
|
||||
//playAll();
|
||||
return true;
|
||||
case R.id.menu_item_share:
|
||||
// TODO
|
||||
//createShare(getSelectedSongs(albumListView));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -48,6 +48,7 @@ import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.domain.Share;
|
||||
import org.moire.ultrasonic.featureflags.Feature;
|
||||
import org.moire.ultrasonic.featureflags.FeatureStorage;
|
||||
import org.moire.ultrasonic.fragment.SelectAlbumFragment;
|
||||
import org.moire.ultrasonic.service.*;
|
||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider;
|
||||
import org.moire.ultrasonic.subsonic.SubsonicImageLoaderProxy;
|
||||
@ -344,7 +345,8 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
}
|
||||
});
|
||||
|
||||
final Intent intent = new Intent(context, SelectAlbumActivity.class);
|
||||
// TODO: Refactor to use navigation
|
||||
final Intent intent = new Intent(context, SelectAlbumFragment.class);// SelectAlbumActivity.class);
|
||||
|
||||
if (Util.getShouldUseId3Tags(context))
|
||||
{
|
||||
@ -595,51 +597,6 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
task.execute();
|
||||
}
|
||||
|
||||
public void setTextViewTextOnUiThread(final RemoteViews view, final int id, final CharSequence text)
|
||||
{
|
||||
this.runOnUiThread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.setTextViewText(id, text);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setImageViewBitmapOnUiThread(final RemoteViews view, final int id, final Bitmap bitmap)
|
||||
{
|
||||
this.runOnUiThread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.setImageViewBitmap(id, bitmap);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setImageViewResourceOnUiThread(final RemoteViews view, final int id, final int resource)
|
||||
{
|
||||
this.runOnUiThread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (view != null)
|
||||
{
|
||||
view.setImageViewResource(id, resource);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setOnTouchListenerOnUiThread(final View view, final OnTouchListener listener)
|
||||
{
|
||||
this.runOnUiThread(new Runnable()
|
||||
@ -720,29 +677,6 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
return instance;
|
||||
}
|
||||
|
||||
public boolean getIsDestroyed()
|
||||
{
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
public void setProgressVisible(boolean visible)
|
||||
{
|
||||
View view = findViewById(R.id.tab_progress);
|
||||
if (view != null)
|
||||
{
|
||||
view.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateProgress(CharSequence message)
|
||||
{
|
||||
TextView view = (TextView) findViewById(R.id.tab_progress_message);
|
||||
if (view != null)
|
||||
{
|
||||
view.setText(message);
|
||||
}
|
||||
}
|
||||
|
||||
public MediaPlayerController getMediaPlayerController()
|
||||
{
|
||||
return mediaPlayerControllerLazy.getValue();
|
||||
@ -760,292 +694,6 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
}
|
||||
}
|
||||
|
||||
void download(final boolean append, final boolean save, final boolean autoPlay, final boolean playNext, final boolean shuffle, final List<Entry> songs)
|
||||
{
|
||||
if (getMediaPlayerController() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Runnable onValid = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (!append && !playNext)
|
||||
{
|
||||
getMediaPlayerController().clear();
|
||||
}
|
||||
|
||||
warnIfNetworkOrStorageUnavailable();
|
||||
getMediaPlayerController().download(songs, save, autoPlay, playNext, shuffle, false);
|
||||
String playlistName = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
|
||||
|
||||
if (playlistName != null)
|
||||
{
|
||||
getMediaPlayerController().setSuggestedPlaylistName(playlistName);
|
||||
}
|
||||
|
||||
if (autoPlay)
|
||||
{
|
||||
if (Util.getShouldTransitionOnPlaybackPreference(SubsonicTabActivity.this))
|
||||
{
|
||||
startActivityForResultWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
|
||||
}
|
||||
}
|
||||
else if (save)
|
||||
{
|
||||
Util.toast(SubsonicTabActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size(), songs.size()));
|
||||
}
|
||||
else if (playNext)
|
||||
{
|
||||
Util.toast(SubsonicTabActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_play_next, songs.size(), songs.size()));
|
||||
}
|
||||
else if (append)
|
||||
{
|
||||
Util.toast(SubsonicTabActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
checkLicenseAndTrialPeriod(onValid);
|
||||
}
|
||||
|
||||
protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background, final boolean playNext, final boolean unpin, final boolean isArtist)
|
||||
{
|
||||
downloadRecursively(id, "", false, true, save, append, autoplay, shuffle, background, playNext, unpin, isArtist);
|
||||
}
|
||||
|
||||
protected void downloadShare(final String id, final String name, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background, final boolean playNext, final boolean unpin)
|
||||
{
|
||||
downloadRecursively(id, name, true, false, save, append, autoplay, shuffle, background, playNext, unpin, false);
|
||||
}
|
||||
|
||||
protected void downloadPlaylist(final String id, final String name, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background, final boolean playNext, final boolean unpin)
|
||||
{
|
||||
downloadRecursively(id, name, false, false, save, append, autoplay, shuffle, background, playNext, unpin, false);
|
||||
}
|
||||
|
||||
protected void downloadRecursively(final String id, final String name, final boolean isShare, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background, final boolean playNext, final boolean unpin, final boolean isArtist)
|
||||
{
|
||||
ModalBackgroundTask<List<Entry>> task = new ModalBackgroundTask<List<Entry>>(this, false)
|
||||
{
|
||||
private static final int MAX_SONGS = 500;
|
||||
|
||||
@Override
|
||||
protected List<Entry> doInBackground() throws Throwable
|
||||
{
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
|
||||
List<Entry> songs = new LinkedList<Entry>();
|
||||
MusicDirectory root;
|
||||
|
||||
if (!ActiveServerProvider.Companion.isOffline(SubsonicTabActivity.this) && isArtist && Util.getShouldUseId3Tags(SubsonicTabActivity.this))
|
||||
{
|
||||
getSongsForArtist(id, songs);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDirectory)
|
||||
{
|
||||
root = !ActiveServerProvider.Companion.isOffline(SubsonicTabActivity.this) && Util.getShouldUseId3Tags(SubsonicTabActivity.this) ? musicService.getAlbum(id, name, false, SubsonicTabActivity.this, this) : musicService.getMusicDirectory(id, name, false, SubsonicTabActivity.this, this);
|
||||
}
|
||||
else if (isShare)
|
||||
{
|
||||
root = new MusicDirectory();
|
||||
|
||||
List<Share> shares = musicService.getShares(true, SubsonicTabActivity.this, this);
|
||||
|
||||
for (Share share : shares)
|
||||
{
|
||||
if (share.getId().equals(id))
|
||||
{
|
||||
for (Entry entry : share.getEntries())
|
||||
{
|
||||
root.addChild(entry);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
root = musicService.getPlaylist(id, name, SubsonicTabActivity.this, this);
|
||||
}
|
||||
|
||||
getSongsRecursively(root, songs);
|
||||
}
|
||||
|
||||
return songs;
|
||||
}
|
||||
|
||||
private void getSongsRecursively(MusicDirectory parent, List<Entry> songs) throws Exception
|
||||
{
|
||||
if (songs.size() > MAX_SONGS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (Entry song : parent.getChildren(false, true))
|
||||
{
|
||||
if (!song.isVideo())
|
||||
{
|
||||
songs.add(song);
|
||||
}
|
||||
}
|
||||
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
|
||||
|
||||
for (Entry dir : parent.getChildren(true, false))
|
||||
{
|
||||
MusicDirectory root;
|
||||
|
||||
root = !ActiveServerProvider.Companion.isOffline(SubsonicTabActivity.this) && Util.getShouldUseId3Tags(SubsonicTabActivity.this) ? musicService.getAlbum(dir.getId(), dir.getTitle(), false, SubsonicTabActivity.this, this) : musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, SubsonicTabActivity.this, this);
|
||||
|
||||
getSongsRecursively(root, songs);
|
||||
}
|
||||
}
|
||||
|
||||
private void getSongsForArtist(String id, Collection<Entry> songs) throws Exception
|
||||
{
|
||||
if (songs.size() > MAX_SONGS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this);
|
||||
MusicDirectory artist = musicService.getArtist(id, "", false, SubsonicTabActivity.this, this);
|
||||
|
||||
for (Entry album : artist.getChildren())
|
||||
{
|
||||
MusicDirectory albumDirectory = musicService.getAlbum(album.getId(), "", false, SubsonicTabActivity.this, this);
|
||||
|
||||
for (Entry song : albumDirectory.getChildren())
|
||||
{
|
||||
if (!song.isVideo())
|
||||
{
|
||||
songs.add(song);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(List<Entry> songs)
|
||||
{
|
||||
if (Util.getShouldSortByDisc(SubsonicTabActivity.this))
|
||||
{
|
||||
Collections.sort(songs, new EntryByDiscAndTrackComparator());
|
||||
}
|
||||
|
||||
MediaPlayerController mediaPlayerController = getMediaPlayerController();
|
||||
if (!songs.isEmpty() && mediaPlayerController != null)
|
||||
{
|
||||
if (!append && !playNext && !unpin && !background)
|
||||
{
|
||||
mediaPlayerController.clear();
|
||||
}
|
||||
warnIfNetworkOrStorageUnavailable();
|
||||
if (!background)
|
||||
{
|
||||
if (unpin)
|
||||
{
|
||||
mediaPlayerController.unpin(songs);
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaPlayerController.download(songs, save, autoplay, playNext, shuffle, false);
|
||||
if (!append && Util.getShouldTransitionOnPlaybackPreference(SubsonicTabActivity.this))
|
||||
{
|
||||
startActivityForResultWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unpin)
|
||||
{
|
||||
mediaPlayerController.unpin(songs);
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaPlayerController.downloadBackground(songs, save);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
task.execute();
|
||||
}
|
||||
|
||||
protected void checkLicenseAndTrialPeriod(Runnable onValid)
|
||||
{
|
||||
if (licenseValid)
|
||||
{
|
||||
onValid.run();
|
||||
return;
|
||||
}
|
||||
|
||||
int trialDaysLeft = Util.getRemainingTrialDays(this);
|
||||
Timber.i("%s trial days left.", trialDaysLeft);
|
||||
|
||||
if (trialDaysLeft == 0)
|
||||
{
|
||||
showDonationDialog(trialDaysLeft, null);
|
||||
}
|
||||
else if (trialDaysLeft < Constants.FREE_TRIAL_DAYS / 2)
|
||||
{
|
||||
showDonationDialog(trialDaysLeft, onValid);
|
||||
}
|
||||
else
|
||||
{
|
||||
Util.toast(this, getResources().getString(R.string.select_album_not_licensed, trialDaysLeft));
|
||||
onValid.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void showDonationDialog(int trialDaysLeft, final Runnable onValid)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setIcon(android.R.drawable.ic_dialog_info);
|
||||
|
||||
if (trialDaysLeft == 0)
|
||||
{
|
||||
builder.setTitle(R.string.select_album_donate_dialog_0_trial_days_left);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.setTitle(getResources().getQuantityString(R.plurals.select_album_donate_dialog_n_trial_days_left, trialDaysLeft, trialDaysLeft));
|
||||
}
|
||||
|
||||
builder.setMessage(R.string.select_album_donate_dialog_message);
|
||||
|
||||
builder.setPositiveButton(R.string.select_album_donate_dialog_now, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i)
|
||||
{
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.DONATION_URL)));
|
||||
}
|
||||
});
|
||||
|
||||
builder.setNegativeButton(R.string.select_album_donate_dialog_later, new DialogInterface.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i)
|
||||
{
|
||||
dialogInterface.dismiss();
|
||||
if (onValid != null)
|
||||
{
|
||||
onValid.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
protected void setActionBarDisplayHomeAsUp(boolean enabled)
|
||||
{
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
@ -1056,39 +704,6 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
}
|
||||
}
|
||||
|
||||
protected void setActionBarTitle(CharSequence title)
|
||||
{
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
|
||||
if (actionBar != null)
|
||||
{
|
||||
actionBar.setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setActionBarTitle(int id)
|
||||
{
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
|
||||
if (actionBar != null)
|
||||
{
|
||||
actionBar.setTitle(id);
|
||||
}
|
||||
}
|
||||
|
||||
protected CharSequence getActionBarTitle()
|
||||
{
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
CharSequence title = null;
|
||||
|
||||
if (actionBar != null)
|
||||
{
|
||||
title = actionBar.getTitle();
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
protected void setActionBarSubtitle(CharSequence title)
|
||||
{
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
@ -1109,19 +724,6 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
}
|
||||
}
|
||||
|
||||
protected CharSequence getActionBarSubtitle()
|
||||
{
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
CharSequence subtitle = null;
|
||||
|
||||
if (actionBar != null)
|
||||
{
|
||||
subtitle = actionBar.getSubtitle();
|
||||
}
|
||||
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
private void setUncaughtExceptionHandler()
|
||||
{
|
||||
Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
@ -1272,7 +874,8 @@ public class SubsonicTabActivity extends ResultActivity
|
||||
}
|
||||
}
|
||||
|
||||
SubsonicTabActivity.this.startActivityForResultWithoutTransition(activity, DownloadActivity.class);
|
||||
// TODO: Refactor this to Navigation. It should automatically go to the PlayerFragment.
|
||||
//SubsonicTabActivity.this.startActivityForResultWithoutTransition(activity, DownloadActivity.class);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
package org.moire.ultrasonic.activity;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchRecentSuggestions;
|
||||
|
||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
/**
|
||||
* Receives voice search queries and forwards to the SearchActivity.
|
||||
* <p/>
|
||||
* http://android-developers.blogspot.com/2010/09/supporting-new-music-voice-action.html
|
||||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class VoiceQueryReceiverActivity extends ResultActivity
|
||||
{
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
String query = getIntent().getStringExtra(SearchManager.QUERY);
|
||||
|
||||
if (query != null)
|
||||
{
|
||||
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE);
|
||||
suggestions.saveRecentQuery(query, null);
|
||||
|
||||
Intent intent = new Intent(VoiceQueryReceiverActivity.this, SearchActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
|
||||
startActivityForResultWithoutTransition(VoiceQueryReceiverActivity.this, intent);
|
||||
}
|
||||
finish();
|
||||
Util.disablePendingTransition(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
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.TabActivityBackgroundTask;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
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 TabActivityBackgroundTask<Lyrics>(getActivity(), true, swipe, cancellationToken)
|
||||
{
|
||||
@Override
|
||||
protected Lyrics doInBackground() throws Throwable
|
||||
{
|
||||
String artist = getArguments().getString(Constants.INTENT_EXTRA_NAME_ARTIST);
|
||||
String title = getArguments().getString(Constants.INTENT_EXTRA_NAME_TITLE);
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(getContext());
|
||||
return musicService.getLyrics(artist, title, getContext(), this);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -177,6 +177,22 @@ public class SearchFragment extends Fragment {
|
||||
|
||||
registerForContextMenu(list);
|
||||
|
||||
// Fragment was started with a query, try to execute search right away
|
||||
Bundle arguments = getArguments();
|
||||
if (arguments != null) {
|
||||
String query = arguments.getString(Constants.INTENT_EXTRA_NAME_QUERY);
|
||||
boolean autoPlay = arguments.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
|
||||
|
||||
if (query != null)
|
||||
{
|
||||
mergeAdapter = new MergeAdapter();
|
||||
list.setAdapter(mergeAdapter);
|
||||
search(query, autoPlay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fragment was started from the Menu, create empty list
|
||||
populateList();
|
||||
}
|
||||
|
||||
@ -221,6 +237,7 @@ public class SearchFragment extends Fragment {
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) { return true; }
|
||||
});
|
||||
|
||||
searchView.setIconifiedByDefault(false);
|
||||
searchItem.expandActionView();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
@ -411,7 +412,7 @@ public class SelectAlbumFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu)
|
||||
public void onPrepareOptionsMenu(@NotNull Menu menu)
|
||||
{
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
playAllButton = menu.findItem(R.id.select_album_play_all);
|
||||
|
@ -86,8 +86,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
private SharedPreferences settings;
|
||||
|
||||
private Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
private Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
||||
private final Lazy<MediaPlayerController> mediaPlayerControllerLazy = inject(MediaPlayerController.class);
|
||||
private final Lazy<ImageLoaderProvider> imageLoader = inject(ImageLoaderProvider.class);
|
||||
private final Lazy<PermissionUtil> permissionUtil = inject(PermissionUtil.class);
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@ -517,7 +518,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
File dir = new File(path);
|
||||
|
||||
if (!FileUtil.ensureDirectoryExistsAndIsReadWritable(dir)) {
|
||||
PermissionUtil.handlePermissionFailed(getActivity(), new PermissionUtil.PermissionRequestFinishedCallback() {
|
||||
permissionUtil.getValue().handlePermissionFailed(new PermissionUtil.PermissionRequestFinishedCallback() {
|
||||
@Override
|
||||
public void onPermissionRequestFinished(boolean hasPermission) {
|
||||
String currentPath = settings.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION,
|
||||
|
@ -14,8 +14,7 @@ import android.view.KeyEvent;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.activity.DownloadActivity;
|
||||
import org.moire.ultrasonic.activity.MainActivity;
|
||||
import org.moire.ultrasonic.activity.NavigationActivity;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver;
|
||||
import org.moire.ultrasonic.service.MediaPlayerController;
|
||||
@ -181,15 +180,11 @@ public class UltrasonicAppWidgetProvider extends AppWidgetProvider
|
||||
|
||||
/**
|
||||
* Link up various button actions using {@link PendingIntent}.
|
||||
*
|
||||
* @param playerActive True if player is active in background, which means
|
||||
* widget click will launch {@link DownloadActivity},
|
||||
* otherwise we launch {@link MainActivity}.
|
||||
*/
|
||||
private static void linkButtons(Context context, RemoteViews views, boolean playerActive)
|
||||
{
|
||||
|
||||
Intent intent = new Intent(context, playerActive ? DownloadActivity.class : MainActivity.class);
|
||||
// TODO: If playerActive = true, display the PlayerFragment automatically
|
||||
Intent intent = new Intent(context, playerActive ? NavigationActivity.class : NavigationActivity.class);
|
||||
intent.setAction("android.intent.action.MAIN");
|
||||
intent.addCategory("android.intent.category.LAUNCHER");
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
@ -198,21 +193,18 @@ public class UltrasonicAppWidgetProvider extends AppWidgetProvider
|
||||
|
||||
// Emulate media button clicks.
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
//intent.setPackage(context.getPackageName());
|
||||
intent.setComponent(new ComponentName(context, MediaButtonIntentReceiver.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 11, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
|
||||
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
//intent.setPackage(context.getPackageName());
|
||||
intent.setComponent(new ComponentName(context, MediaButtonIntentReceiver.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT));
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 12, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
|
||||
|
||||
intent = new Intent(Constants.CMD_PROCESS_KEYCODE);
|
||||
//intent.setPackage(context.getPackageName());
|
||||
intent.setComponent(new ComponentName(context, MediaButtonIntentReceiver.class));
|
||||
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
|
||||
pendingIntent = PendingIntent.getBroadcast(context, 13, intent, 0);
|
||||
|
@ -19,12 +19,12 @@ import timber.log.Timber;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.moire.ultrasonic.activity.DownloadActivity;
|
||||
import org.moire.ultrasonic.audiofx.EqualizerController;
|
||||
import org.moire.ultrasonic.audiofx.VisualizerController;
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.fragment.PlayerFragment;
|
||||
import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver;
|
||||
import org.moire.ultrasonic.util.CancellableTask;
|
||||
import org.moire.ultrasonic.util.Constants;
|
||||
@ -598,7 +598,7 @@ public class LocalMediaPlayer
|
||||
@Override
|
||||
public void onBufferingUpdate(MediaPlayer mp, int percent)
|
||||
{
|
||||
SeekBar progressBar = DownloadActivity.getProgressBar();
|
||||
SeekBar progressBar = PlayerFragment.getProgressBar();
|
||||
MusicDirectory.Entry song = downloadFile.getSong();
|
||||
|
||||
if (percent == 100)
|
||||
@ -627,12 +627,12 @@ public class LocalMediaPlayer
|
||||
|
||||
setPlayerState(PREPARED);
|
||||
|
||||
SeekBar progressBar = DownloadActivity.getProgressBar();
|
||||
SeekBar progressBar = PlayerFragment.getProgressBar();
|
||||
|
||||
if (progressBar != null && downloadFile.isWorkDone())
|
||||
{
|
||||
// Populate seek bar secondary progress if we have a complete file for consistency
|
||||
DownloadActivity.getProgressBar().setSecondaryProgress(100 * progressBar.getMax());
|
||||
PlayerFragment.getProgressBar().setSecondaryProgress(100 * progressBar.getMax());
|
||||
}
|
||||
|
||||
synchronized (LocalMediaPlayer.this)
|
||||
|
@ -20,7 +20,7 @@ import androidx.core.app.NotificationManagerCompat;
|
||||
|
||||
import org.koin.java.KoinJavaComponent;
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.activity.DownloadActivity;
|
||||
import org.moire.ultrasonic.activity.NavigationActivity;
|
||||
import org.moire.ultrasonic.activity.SubsonicTabActivity;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
@ -650,7 +650,8 @@ public class MediaPlayerService extends Service
|
||||
|
||||
notificationBuilder.setContent(contentView);
|
||||
|
||||
Intent notificationIntent = new Intent(this, DownloadActivity.class);
|
||||
// TODO: Navigate automatically to PlayerFragment
|
||||
Intent notificationIntent = new Intent(this, NavigationActivity.class);
|
||||
notificationBuilder.setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, 0));
|
||||
|
||||
if (playerState == PlayerState.PAUSED || playerState == PlayerState.IDLE) {
|
||||
|
@ -60,7 +60,8 @@ public class FileUtil
|
||||
private static final List<String> PLAYLIST_FILE_EXTENSIONS = Collections.singletonList("m3u");
|
||||
private static final Pattern TITLE_WITH_TRACK = Pattern.compile("^\\d\\d-.*");
|
||||
|
||||
private static Lazy<ImageLoaderProvider> imageLoaderProvider = inject(ImageLoaderProvider.class);
|
||||
private static final Lazy<ImageLoaderProvider> imageLoaderProvider = inject(ImageLoaderProvider.class);
|
||||
private static final Lazy<PermissionUtil> permissionUtil = inject(PermissionUtil.class);
|
||||
|
||||
public static File getSongFile(Context context, MusicDirectory.Entry song)
|
||||
{
|
||||
@ -396,7 +397,7 @@ public class FileUtil
|
||||
File dir = new File(path);
|
||||
|
||||
boolean hasAccess = ensureDirectoryExistsAndIsReadWritable(dir);
|
||||
if (hasAccess == false) PermissionUtil.handlePermissionFailed(context, null);
|
||||
if (!hasAccess) permissionUtil.getValue().handlePermissionFailed(null);
|
||||
|
||||
return hasAccess ? dir : defaultMusicDirectory;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import com.karumi.dexter.listener.PermissionRequestErrorListener;
|
||||
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.activity.MainActivity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -32,6 +31,13 @@ import static androidx.core.content.PermissionChecker.PERMISSION_DENIED;
|
||||
* Contains static functions for Permission handling
|
||||
*/
|
||||
public class PermissionUtil {
|
||||
|
||||
private final Context context;
|
||||
|
||||
public PermissionUtil(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public interface PermissionRequestFinishedCallback {
|
||||
void onPermissionRequestFinished(boolean hasPermission);
|
||||
}
|
||||
@ -42,31 +48,27 @@ public class PermissionUtil {
|
||||
* It will check if the failure is because the necessary permissions aren't available,
|
||||
* and it will request them, if necessary.
|
||||
*
|
||||
* @param context context for the operation
|
||||
* @param callback callback function to execute after the permission request is finished
|
||||
*/
|
||||
public static void handlePermissionFailed(final Context context, final PermissionRequestFinishedCallback callback) {
|
||||
|
||||
public void handlePermissionFailed(final PermissionRequestFinishedCallback callback) {
|
||||
// TODO: Test with ApplicationContext
|
||||
String currentCachePath = Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory(context).getPath());
|
||||
String defaultCachePath = FileUtil.getDefaultMusicDirectory(context).getPath();
|
||||
|
||||
// Ultrasonic can do nothing about this error when the Music Directory is already set to the default.
|
||||
if (currentCachePath.compareTo(defaultCachePath) == 0) return;
|
||||
|
||||
// We must get the context of the Main Activity for the dialogs, as this function may be called from a background thread where displaying dialogs is not available
|
||||
final Context mainContext = MainActivity.getInstance();
|
||||
|
||||
if ((PermissionChecker.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED) ||
|
||||
(PermissionChecker.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_DENIED)) {
|
||||
// While we request permission, the Music Directory is temporarily reset to its default location
|
||||
setCacheLocation(context, FileUtil.getDefaultMusicDirectory(context).getPath());
|
||||
requestFailedPermission(mainContext, currentCachePath, callback);
|
||||
requestFailedPermission(context, currentCachePath, callback);
|
||||
} else {
|
||||
setCacheLocation(context, FileUtil.getDefaultMusicDirectory(context).getPath());
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showWarning(mainContext, context.getString(R.string.permissions_message_box_title), context.getString(R.string.permissions_access_error), null);
|
||||
showWarning(context, context.getString(R.string.permissions_message_box_title), context.getString(R.string.permissions_access_error), null);
|
||||
}
|
||||
});
|
||||
callback.onPermissionRequestFinished(false);
|
||||
|
@ -51,8 +51,7 @@ import android.widget.Toast;
|
||||
import androidx.annotation.ColorInt;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.activity.DownloadActivity;
|
||||
import org.moire.ultrasonic.activity.MainActivity;
|
||||
import org.moire.ultrasonic.activity.NavigationActivity;
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider;
|
||||
import org.moire.ultrasonic.domain.*;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
@ -1020,8 +1019,8 @@ public class Util
|
||||
|
||||
public static void linkButtons(Context context, RemoteViews views, boolean playerActive)
|
||||
{
|
||||
|
||||
Intent intent = new Intent(context, playerActive ? DownloadActivity.class : MainActivity.class);
|
||||
// TODO: Navigate automatically to PlayerFragment if playerActive = true
|
||||
Intent intent = new Intent(context, playerActive ? NavigationActivity.class : NavigationActivity.class);
|
||||
intent.setAction("android.intent.action.MAIN");
|
||||
intent.addCategory("android.intent.category.LAUNCHER");
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
@ -1,9 +1,13 @@
|
||||
package org.moire.ultrasonic.activity
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.SearchManager
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import android.provider.MediaStore
|
||||
import android.provider.SearchRecentSuggestions
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@ -21,6 +25,7 @@ import com.google.android.material.navigation.NavigationView
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.android.viewmodel.ext.android.viewModel
|
||||
import org.moire.ultrasonic.R
|
||||
import org.moire.ultrasonic.provider.SearchSuggestionProvider
|
||||
import org.moire.ultrasonic.service.MediaPlayerController
|
||||
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport
|
||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||
@ -59,7 +64,7 @@ class NavigationActivity : AppCompatActivity() {
|
||||
setOf(R.id.mainFragment, R.id.selectArtistFragment, R.id.searchFragment,
|
||||
R.id.playlistsFragment, R.id.sharesFragment, R.id.bookmarksFragment,
|
||||
R.id.chatFragment, R.id.podcastFragment, R.id.settingsFragment,
|
||||
R.id.aboutFragment),
|
||||
R.id.aboutFragment, R.id.playerFragment),
|
||||
drawerLayout)
|
||||
|
||||
setupActionBar(navController, appBarConfiguration)
|
||||
@ -127,6 +132,25 @@ class NavigationActivity : AppCompatActivity() {
|
||||
return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration)
|
||||
}
|
||||
|
||||
// TODO: Test if this works with external Intents
|
||||
// android.intent.action.SEARCH and android.media.action.MEDIA_PLAY_FROM_SEARCH calls here
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
val query = intent?.getStringExtra(SearchManager.QUERY)
|
||||
|
||||
if (query != null) {
|
||||
val autoPlay = intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
|
||||
val suggestions = SearchRecentSuggestions(this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE)
|
||||
suggestions.saveRecentQuery(query, null)
|
||||
|
||||
val bundle = Bundle()
|
||||
bundle.putString(Constants.INTENT_EXTRA_NAME_QUERY, query)
|
||||
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoPlay)
|
||||
findNavController(R.id.nav_host_fragment).navigate(R.id.searchFragment, bundle)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadSettings() {
|
||||
PreferenceManager.setDefaultValues(this, R.xml.settings, false)
|
||||
val preferences = Util.getPreferences(this)
|
||||
|
@ -6,6 +6,7 @@ import org.koin.core.context.startKoin
|
||||
import org.koin.core.logger.Level
|
||||
import org.moire.ultrasonic.BuildConfig
|
||||
import org.moire.ultrasonic.di.appPermanentStorage
|
||||
import org.moire.ultrasonic.di.applicationModule
|
||||
import org.moire.ultrasonic.di.baseNetworkModule
|
||||
import org.moire.ultrasonic.di.directoriesModule
|
||||
import org.moire.ultrasonic.di.featureFlagsModule
|
||||
@ -35,6 +36,7 @@ class UApp : MultiDexApplication() {
|
||||
androidContext(this@UApp)
|
||||
// declare modules to use
|
||||
modules(
|
||||
applicationModule,
|
||||
directoriesModule,
|
||||
appPermanentStorage,
|
||||
baseNetworkModule,
|
||||
|
@ -31,8 +31,4 @@ val appPermanentStorage = module {
|
||||
single { get<AppDatabase>().serverSettingDao() }
|
||||
|
||||
viewModel { ServerSettingsModel(get(), get(), androidContext()) }
|
||||
|
||||
single { ActiveServerProvider(get(), androidContext()) }
|
||||
|
||||
single { ImageLoaderProvider(androidContext()) }
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package org.moire.ultrasonic.di
|
||||
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
import org.moire.ultrasonic.cache.AndroidDirectories
|
||||
import org.moire.ultrasonic.cache.Directories
|
||||
import org.moire.ultrasonic.data.ActiveServerProvider
|
||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||
import org.moire.ultrasonic.util.PermissionUtil
|
||||
|
||||
val applicationModule = module {
|
||||
single { ActiveServerProvider(get(), androidContext()) }
|
||||
single { ImageLoaderProvider(androidContext()) }
|
||||
single { PermissionUtil(androidContext()) }
|
||||
}
|
@ -33,9 +33,8 @@ class DownloadHandler(
|
||||
}
|
||||
if (autoPlay) {
|
||||
if (Util.getShouldTransitionOnPlaybackPreference(fragment.activity)) {
|
||||
fragment.findNavController().popBackStack(R.id.downloadFragment, true)
|
||||
fragment.findNavController().navigate(R.id.downloadFragment)
|
||||
//startActivityForResultWithoutTransition(this@SubsonicTabActivity, DownloadActivity::class.java)
|
||||
fragment.findNavController().popBackStack(R.id.playerFragment, true)
|
||||
fragment.findNavController().navigate(R.id.playerFragment)
|
||||
}
|
||||
} else if (save) {
|
||||
Util.toast(fragment.context, fragment.resources.getQuantityString(R.plurals.select_album_n_songs_pinned, songs.size, songs.size))
|
||||
@ -190,9 +189,8 @@ class DownloadHandler(
|
||||
} else {
|
||||
mediaPlayerController.download(songs, save, autoPlay, playNext, shuffle, false)
|
||||
if (!append && Util.getShouldTransitionOnPlaybackPreference(activity)) {
|
||||
fragment.findNavController().popBackStack(R.id.downloadFragment, true)
|
||||
fragment.findNavController().navigate(R.id.downloadFragment)
|
||||
//startActivityForResultWithoutTransition(activity, DownloadActivity::class.java)
|
||||
fragment.findNavController().popBackStack(R.id.playerFragment, true)
|
||||
fragment.findNavController().navigate(R.id.playerFragment)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -32,7 +32,7 @@ class ShareHandler(val context: Context) {
|
||||
private var saveAsDefaultsCheckBox: CheckBox? = null
|
||||
private val pattern = Pattern.compile(":")
|
||||
|
||||
fun createShare(fragment: Fragment, entries: List<MusicDirectory.Entry?>?, swipe: SwipeRefreshLayout, cancellationToken: CancellationToken) {
|
||||
fun createShare(fragment: Fragment, entries: List<MusicDirectory.Entry?>?, swipe: SwipeRefreshLayout?, cancellationToken: CancellationToken) {
|
||||
val askForDetails = Util.getShouldAskForShareDetails(context)
|
||||
val shareDetails = ShareDetails()
|
||||
shareDetails.Entries = entries
|
||||
@ -45,7 +45,7 @@ class ShareHandler(val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun share(fragment: Fragment, shareDetails: ShareDetails, swipe: SwipeRefreshLayout, cancellationToken: CancellationToken) {
|
||||
fun share(fragment: Fragment, shareDetails: ShareDetails, swipe: SwipeRefreshLayout?, cancellationToken: CancellationToken) {
|
||||
val task: BackgroundTask<Share> = object : TabActivityBackgroundTask<Share>(fragment.requireActivity(), true, swipe, cancellationToken) {
|
||||
@Throws(Throwable::class)
|
||||
override fun doInBackground(): Share {
|
||||
@ -76,7 +76,7 @@ class ShareHandler(val context: Context) {
|
||||
task.execute()
|
||||
}
|
||||
|
||||
private fun showDialog(fragment: Fragment, shareDetails: ShareDetails, swipe: SwipeRefreshLayout, cancellationToken: CancellationToken) {
|
||||
private fun showDialog(fragment: Fragment, shareDetails: ShareDetails, swipe: SwipeRefreshLayout?, cancellationToken: CancellationToken) {
|
||||
val layout = LayoutInflater.from(fragment.context).inflate(R.layout.share_details, null)
|
||||
|
||||
if (layout != null) {
|
||||
|
@ -4,53 +4,61 @@
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent">
|
||||
|
||||
<include layout="@layout/tab_progress"/>
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
a:id="@+id/lyrics_refresh"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="0dp"
|
||||
a:layout_weight="1.0">
|
||||
|
||||
<ScrollView
|
||||
a:id="@+id/lyrics_scrollview"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="0dip"
|
||||
a:layout_weight="1.0">
|
||||
|
||||
<LinearLayout
|
||||
a:orientation="vertical"
|
||||
<androidx.core.widget.NestedScrollView
|
||||
a:id="@+id/lyrics_scrollview"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent">
|
||||
<TextView
|
||||
a:id="@+id/lyrics_artist"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="center_horizontal"
|
||||
a:layout_height="wrap_content"
|
||||
a:scrollbars="vertical"
|
||||
a:layout_weight="1.0">
|
||||
|
||||
<LinearLayout
|
||||
a:orientation="vertical"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:paddingLeft="10dip"
|
||||
a:paddingRight="10dip"
|
||||
a:paddingTop="10dip"
|
||||
a:paddingBottom="4dip"
|
||||
/>
|
||||
a:paddingVertical="32dip">
|
||||
<TextView
|
||||
a:id="@+id/lyrics_artist"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="center_horizontal"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:paddingLeft="10dip"
|
||||
a:paddingRight="10dip"
|
||||
a:paddingTop="10dip"
|
||||
a:paddingBottom="4dip"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
a:id="@+id/lyrics_title"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="center_horizontal"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:paddingLeft="10dip"
|
||||
a:paddingRight="10dip"
|
||||
/>
|
||||
<TextView
|
||||
a:id="@+id/lyrics_title"
|
||||
a:textAppearance="?android:attr/textAppearanceMedium"
|
||||
a:gravity="center_horizontal"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:paddingLeft="10dip"
|
||||
a:paddingRight="10dip"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
a:id="@+id/lyrics_text"
|
||||
a:textAppearance="?android:attr/textAppearanceSmall"
|
||||
a:gravity="center_horizontal"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:paddingLeft="10dip"
|
||||
a:paddingRight="10dip"
|
||||
/>
|
||||
<TextView
|
||||
a:id="@+id/lyrics_text"
|
||||
a:textAppearance="?android:attr/textAppearanceSmall"
|
||||
a:gravity="center_horizontal"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:paddingTop="32dip"
|
||||
a:paddingLeft="10dip"
|
||||
a:paddingRight="10dip"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<include layout="@layout/now_playing"/>
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
a:icon="?attr/chat"
|
||||
a:title="@string/button_bar.chat" />
|
||||
<item
|
||||
a:id="@+id/menu_now_playing"
|
||||
a:id="@+id/playerFragment"
|
||||
a:checkable="true"
|
||||
a:icon="?attr/media_play"
|
||||
a:title="@string/button_bar.now_playing" />
|
||||
|
@ -22,64 +22,64 @@
|
||||
android:id="@+id/selectArtistToSelectAlbum"
|
||||
app:destination="@id/selectAlbumFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/downloadFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.DownloadFragment" />
|
||||
<fragment
|
||||
android:id="@+id/selectAlbumFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.SelectAlbumFragment"
|
||||
android:label="SelectAlbumFragment" >
|
||||
android:name="org.moire.ultrasonic.fragment.SelectAlbumFragment" >
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/searchFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.SearchFragment"
|
||||
android:label="SearchFragment" >
|
||||
android:name="org.moire.ultrasonic.fragment.SearchFragment" >
|
||||
<action
|
||||
android:id="@+id/searchToSelectAlbum"
|
||||
app:destination="@id/selectAlbumFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/playlistsFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.PlaylistsFragment"
|
||||
android:label="PlaylistsFragment" >
|
||||
android:name="org.moire.ultrasonic.fragment.PlaylistsFragment" >
|
||||
<action
|
||||
android:id="@+id/playlistsToSelectAlbum"
|
||||
app:destination="@id/selectAlbumFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/sharesFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.SharesFragment"
|
||||
android:label="SharesFragment" >
|
||||
android:name="org.moire.ultrasonic.fragment.SharesFragment" >
|
||||
<action
|
||||
android:id="@+id/sharesToSelectAlbum"
|
||||
app:destination="@id/selectAlbumFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/bookmarksFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.BookmarksFragment"
|
||||
android:label="BookmarksFragment" />
|
||||
android:name="org.moire.ultrasonic.fragment.BookmarksFragment" />
|
||||
<fragment
|
||||
android:id="@+id/chatFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.ChatFragment"
|
||||
android:label="ChatFragment" />
|
||||
android:name="org.moire.ultrasonic.fragment.ChatFragment" />
|
||||
<fragment
|
||||
android:id="@+id/podcastFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.PodcastFragment"
|
||||
android:label="PodcastFragment" >
|
||||
android:name="org.moire.ultrasonic.fragment.PodcastFragment" >
|
||||
<action
|
||||
android:id="@+id/podcastToSelectAlbum"
|
||||
app:destination="@id/selectAlbumFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/settingsFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.SettingsFragment"
|
||||
android:label="SettingsFragment" />
|
||||
android:name="org.moire.ultrasonic.fragment.SettingsFragment" />
|
||||
<fragment
|
||||
android:id="@+id/aboutFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.AboutFragment"
|
||||
android:label="AboutFragment" />
|
||||
android:name="org.moire.ultrasonic.fragment.AboutFragment" />
|
||||
<fragment
|
||||
android:id="@+id/selectGenreFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.SelectGenreFragment"
|
||||
android:label="SelectGenreFragment" />
|
||||
android:name="org.moire.ultrasonic.fragment.SelectGenreFragment" />
|
||||
<fragment
|
||||
android:id="@+id/playerFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.PlayerFragment" >
|
||||
<action
|
||||
android:id="@+id/playerToSelectAlbum"
|
||||
app:destination="@id/selectAlbumFragment" />
|
||||
<action
|
||||
android:id="@+id/playerToLyrics"
|
||||
app:destination="@id/lyricsFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/lyricsFragment"
|
||||
android:name="org.moire.ultrasonic.fragment.LyricsFragment" />
|
||||
</navigation>
|
Loading…
x
Reference in New Issue
Block a user