-Added UI for creating playlist.

-Added UI for appending item to playlists.
-Added mini variant of playlist info item.
This commit is contained in:
John Zhen Mo 2018-01-16 11:48:52 -08:00
parent f7c2344fda
commit 689a138e17
17 changed files with 508 additions and 78 deletions

View file

@ -14,6 +14,8 @@ import java.util.List;
import io.reactivex.Completable;
import io.reactivex.Maybe;
import io.reactivex.Scheduler;
import io.reactivex.schedulers.Schedulers;
public class LocalPlaylistManager {
@ -46,7 +48,7 @@ public class LocalPlaylistManager {
}
return playlistStreamTable.insertAll(joinEntities);
}));
})).subscribeOn(Schedulers.io());
}
public Maybe<Long> appendToPlaylist(final long playlistId, final StreamEntity stream) {
@ -57,7 +59,7 @@ public class LocalPlaylistManager {
return Maybe.zip(streamIdFuture, joinIndexFuture, (streamId, currentMaxJoinIndex) ->
playlistStreamTable.insert(new PlaylistStreamEntity(playlistId,
streamId, currentMaxJoinIndex + 1))
);
).subscribeOn(Schedulers.io());
}
public Completable updateJoin(final long playlistId, final List<Long> streamIds) {
@ -73,6 +75,8 @@ public class LocalPlaylistManager {
}
public Maybe<List<PlaylistMetadataEntry>> getPlaylists() {
return playlistStreamTable.getPlaylistMetadata().firstElement();
return playlistStreamTable.getPlaylistMetadata()
.firstElement()
.subscribeOn(Schedulers.io());
}
}

View file

@ -0,0 +1,147 @@
package org.schabi.newpipe.fragments.playlist;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.info_list.stored.LocalPlaylistInfoItem;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
public class PlaylistAppendDialog extends DialogFragment {
private static final String TAG = PlaylistAppendDialog.class.getCanonicalName();
private static final String INFO_KEY = "info_key";
private StreamInfo streamInfo;
private View newPlaylistButton;
private RecyclerView playlistRecyclerView;
private InfoListAdapter playlistAdapter;
public static PlaylistAppendDialog newInstance(final StreamInfo info) {
PlaylistAppendDialog dialog = new PlaylistAppendDialog();
dialog.setInfo(info);
return dialog;
}
private void setInfo(StreamInfo info) {
this.streamInfo = info;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
playlistAdapter = new InfoListAdapter(getActivity());
playlistAdapter.useMiniItemVariants(true);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
Serializable serial = savedInstanceState.getSerializable(INFO_KEY);
if (serial instanceof StreamInfo) streamInfo = (StreamInfo) serial;
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.dialog_playlists, container);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
newPlaylistButton = view.findViewById(R.id.newPlaylist);
playlistRecyclerView = view.findViewById(R.id.playlist_list);
playlistRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
playlistRecyclerView.setAdapter(playlistAdapter);
final LocalPlaylistManager playlistManager =
new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext()));
newPlaylistButton.setOnClickListener(ignored -> openCreatePlaylistDialog());
playlistAdapter.setOnPlaylistSelectedListener(new InfoItemBuilder.OnInfoItemSelectedListener<PlaylistInfoItem>() {
@Override
public void selected(PlaylistInfoItem selectedItem) {
if (!(selectedItem instanceof LocalPlaylistInfoItem)) return;
final long playlistId = ((LocalPlaylistInfoItem) selectedItem).getPlaylistId();
final Toast successToast =
Toast.makeText(getContext(), "Added", Toast.LENGTH_SHORT);
playlistManager.appendToPlaylist(playlistId, new StreamEntity(streamInfo))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(ignored -> successToast.show());
getDialog().dismiss();
}
@Override
public void held(PlaylistInfoItem selectedItem) {}
});
playlistManager.getPlaylists()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(metadataEntries -> {
if (metadataEntries.isEmpty()) {
openCreatePlaylistDialog();
}
List<InfoItem> playlistInfoItems = new ArrayList<>(metadataEntries.size());
for (final PlaylistMetadataEntry metadataEntry : metadataEntries) {
playlistInfoItems.add(metadataEntry.toStoredPlaylistInfoItem());
}
playlistAdapter.clearStreamItemList();
playlistAdapter.addInfoItemList(playlistInfoItems);
playlistRecyclerView.setVisibility(View.VISIBLE);
getDialog().setCanceledOnTouchOutside(true);
});
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(INFO_KEY, streamInfo);
}
/*//////////////////////////////////////////////////////////////////////////
// Helper
//////////////////////////////////////////////////////////////////////////*/
public void openCreatePlaylistDialog() {
if (streamInfo == null || getFragmentManager() == null) return;
getDialog().dismiss();
PlaylistCreationDialog.newInstance(streamInfo).show(getFragmentManager(), TAG);
}
}

View file

@ -0,0 +1,91 @@
package org.schabi.newpipe.fragments.playlist;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import java.util.Collections;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
public class PlaylistCreationDialog extends DialogFragment {
private static final String TAG = PlaylistCreationDialog.class.getCanonicalName();
private static final boolean DEBUG = MainActivity.DEBUG;
private static final String INFO_KEY = "info_key";
private StreamInfo streamInfo;
public static PlaylistCreationDialog newInstance(final StreamInfo info) {
PlaylistCreationDialog dialog = new PlaylistCreationDialog();
dialog.setInfo(info);
return dialog;
}
private void setInfo(final StreamInfo info) {
this.streamInfo = info;
}
/*//////////////////////////////////////////////////////////////////////////
// LifeCycle
//////////////////////////////////////////////////////////////////////////*/
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (streamInfo != null) {
outState.putSerializable(INFO_KEY, streamInfo);
}
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
if (savedInstanceState != null && streamInfo == null) {
final Object infoCandidate = savedInstanceState.getSerializable(INFO_KEY);
if (infoCandidate != null && infoCandidate instanceof StreamInfo) {
streamInfo = (StreamInfo) infoCandidate;
}
}
if (streamInfo == null) return super.onCreateDialog(savedInstanceState);
View dialogView = View.inflate(getContext(),
R.layout.dialog_create_playlist, null);
EditText nameInput = dialogView.findViewById(R.id.playlist_name);
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext())
.setTitle(R.string.create_playlist)
.setView(dialogView)
.setCancelable(true)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.create, (dialogInterface, i) -> {
final String name = nameInput.getText().toString();
final LocalPlaylistManager playlistManager =
new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext()));
final List<StreamEntity> streams =
Collections.singletonList(new StreamEntity(streamInfo));
playlistManager.createPlaylist(name, streams)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(longs -> Toast.makeText(getActivity(),
"Playlist " + name + " successfully created",
Toast.LENGTH_SHORT).show());
});
return dialogBuilder.create();
}
}

View file

@ -44,4 +44,31 @@ public class StreamRecordManager {
public int removeHistory(final long streamId) {
return historyTable.deleteHistory(streamId);
}
public void removeRecord() {
historyTable.getStatistics().firstElement().subscribe(
new MaybeObserver<List<StreamStatisticsEntry>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(List<StreamStatisticsEntry> streamStatisticsEntries) {
hashCode();
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
}
);
}
}