Manage playlists

This commit is contained in:
tom79 2019-05-26 19:41:04 +02:00
parent 8a824b27b8
commit 0847a67063
8 changed files with 230 additions and 144 deletions

View File

@ -1541,7 +1541,7 @@ public abstract class BaseMainActivity extends BaseActivity
}else{
delete_all.show();
}
if( id != R.id.nav_list && id != R.id.nav_filters){
if( id != R.id.nav_list && id != R.id.nav_filters && id != R.id.nav_peertube_playlists){
add_new.hide();
}else{
add_new.show();

View File

@ -78,12 +78,8 @@ public class ManagePlaylistsAsyncTask extends AsyncTask<Void, Void, Void> {
apiResponse = new PeertubeAPI(contextReference.get()).getPlayists(account.getUsername());
}else if(apiAction == action.GET_LIST_VIDEOS){
apiResponse = new PeertubeAPI(contextReference.get()).getPlaylistVideos(playlist.getId(),max_id, null);
}else if( apiAction == action.CREATE_PLAYLIST){
apiResponse = new PeertubeAPI(contextReference.get()).createPlaylist(playlist);
}else if(apiAction == action.DELETE_PLAYLIST){
statusCode = new PeertubeAPI(contextReference.get()).deletePlaylist(playlist.getId());
}else if(apiAction == action.UPDATE_PLAYLIST){
apiResponse = new PeertubeAPI(contextReference.get()).updatePlaylist(playlist);
}else if(apiAction == action.ADD_VIDEOS){
statusCode = new PeertubeAPI(contextReference.get()).addVideoPlaylist(playlist.getId(),videoId);
}else if(apiAction == action.DELETE_VIDEOS){

View File

@ -25,8 +25,10 @@ public class PeertubeInformation {
private LinkedHashMap<String, String> languages;
private LinkedHashMap<Integer, String> licences;
private LinkedHashMap<Integer, String> privacies;
private LinkedHashMap<Integer, String> playlistPrivacies;
private LinkedHashMap<String, String> translations;
public static final LinkedHashMap<String, String> langueMapped;
static {
LinkedHashMap<String, String> aMap = new LinkedHashMap<>();
@ -86,4 +88,12 @@ public class PeertubeInformation {
public void setPrivacies(LinkedHashMap<Integer, String> privacies) {
this.privacies = privacies;
}
public LinkedHashMap<Integer, String> getPlaylistPrivacies() {
return playlistPrivacies;
}
public void setPlaylistPrivacies(LinkedHashMap<Integer, String> playlistPrivacies) {
this.playlistPrivacies = playlistPrivacies;
}
}

View File

@ -321,6 +321,15 @@ public class PeertubeAPI {
peertubeInformation.setPrivacies(_pprivacies);
response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl("/video-playlists/privacies"), 60, null, null);
JSONObject plprivacies = new JSONObject(response);
LinkedHashMap<Integer, String> _plprivacies = new LinkedHashMap<>();
for( int i = 1 ; i <= plprivacies.length() ; i++){
_plprivacies.put(i, plprivacies.getString(String.valueOf(i)));
}
peertubeInformation.setPlaylistPrivacies(_plprivacies);
response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl("/videos/licences"), 60, null, null);
JSONObject licences = new JSONObject(response);
LinkedHashMap<Integer, String> _plicences = new LinkedHashMap<>();
@ -1342,7 +1351,7 @@ public class PeertubeAPI {
List<Playlist> playlists = new ArrayList<>();
try {
String response = new HttpsConnection(context, this.instance).get(getAbsoluteUrl(String.format("/accounts/%s/video-playlists", username)), 60, null, prefKeyOauthTokenT);
playlists = parsePlaylists(context, new JSONArray(response));
playlists = parsePlaylists(context, new JSONObject(response).getJSONArray("data"));
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
} catch (NoSuchAlgorithmException e) {
@ -1359,45 +1368,6 @@ public class PeertubeAPI {
}
/**
* Posts a Playlist
* @param playlist Playlist, the playlist
* @return APIResponse
*/
public APIResponse createPlaylist(Playlist playlist){
HashMap<String, String> params = new HashMap<>();
params.put("displayName",playlist.getDisplayName());
if( playlist.getDescription() != null)
params.put("description",playlist.getDescription());
if( playlist.getVideoChannelId() != null)
params.put("videoChannelId",playlist.getVideoChannelId());
if( playlist.getPrivacy() != null) {
Map.Entry<Integer, String> privacyM = playlist.getPrivacy().entrySet().iterator().next();
Integer idPrivacy = privacyM.getKey();
params.put("privacy", String.valueOf(idPrivacy));
}
List<Playlist> playlists = new ArrayList<>();
Playlist playlistReply;
try {
String response = new HttpsConnection(context, this.instance).post(getAbsoluteUrl("/video-playlists"), 60, params, prefKeyOauthTokenT);
playlistReply = parsePlaylist(context, new JSONObject(response));
playlists.add(playlistReply);
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
apiResponse.setPlaylists(playlists);
return apiResponse;
}
/**
@ -1422,45 +1392,6 @@ public class PeertubeAPI {
return actionCode;
}
/**
* Update a Playlist
* @param playlist Playlist, the playlist
* @return APIResponse
*/
public APIResponse updatePlaylist(Playlist playlist){
HashMap<String, String> params = new HashMap<>();
params.put("displayName",playlist.getDisplayName());
if( playlist.getDescription() != null)
params.put("description",playlist.getDescription());
if( playlist.getVideoChannelId() != null)
params.put("videoChannelId",playlist.getVideoChannelId());
if( playlist.getPrivacy() != null) {
Map.Entry<Integer, String> privacyM = playlist.getPrivacy().entrySet().iterator().next();
Integer idPrivacy = privacyM.getKey();
params.put("privacy", String.valueOf(idPrivacy));
}
List<Playlist> playlists = new ArrayList<>();
Playlist playlistReply;
try {
String response = new HttpsConnection(context, this.instance).post(getAbsoluteUrl(String.format("/video-playlists/%s", playlist.getId())), 60, params, prefKeyOauthTokenT);
playlistReply = parsePlaylist(context, new JSONObject(response));
playlists.add(playlistReply);
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
apiResponse.setPlaylists(playlists);
return apiResponse;
}
/**
* Delete video in a Playlist
@ -2124,13 +2055,13 @@ public class PeertubeAPI {
type.put(resobj.getJSONObject("type").getInt("id"), resobj.getJSONObject("type").get("label").toString());
playlist.setType(type);
playlist.setPrivacy(privacy);
}catch (Exception ignored){}
}catch (Exception ignored){ignored.printStackTrace();}
try{
playlist.setUpdatedAt(Helper.stringToDate(context, resobj.getString("updatedAt")));
}catch (Exception ignored){}
}catch (Exception ignored){}
}catch (Exception ignored){ignored.printStackTrace();}
}catch (Exception ignored){ignored.printStackTrace();}
return playlist;
}

View File

@ -15,10 +15,13 @@ package app.fedilab.android.drawers;
* see <http://www.gnu.org/licenses>. */
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
@ -33,24 +36,31 @@ import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.activities.PlaylistsActivity;
import app.fedilab.android.asynctasks.ManagePlaylistsAsyncTask;
import app.fedilab.android.client.APIResponse;
import app.fedilab.android.client.Entities.Playlist;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.interfaces.OnPlaylistActionInterface;
/**
* Created by Thomas on 26/05/2019.
* Adapter for playlists
*/
public class PlaylistAdapter extends BaseAdapter {
public class PlaylistAdapter extends BaseAdapter implements OnPlaylistActionInterface {
private List<Playlist> playlists;
private LayoutInflater layoutInflater;
private Context context;
private PlaylistAdapter playlistAdapter;
private RelativeLayout textviewNoAction;
public PlaylistAdapter(Context context, List<Playlist> lists, RelativeLayout textviewNoAction){
this.playlists = lists;
layoutInflater = LayoutInflater.from(context);
this.context = context;
playlistAdapter = this;
this.textviewNoAction = textviewNoAction;
}
@Override
@ -113,9 +123,52 @@ public class PlaylistAdapter extends BaseAdapter {
context.startActivity(intent);
}
});
int style;
if (theme == Helper.THEME_DARK) {
style = R.style.DialogDark;
} else if (theme == Helper.THEME_BLACK){
style = R.style.DialogBlack;
}else {
style = R.style.Dialog;
}
holder.search_container.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(context, style);
builder.setTitle(context.getString(R.string.action_lists_delete) + ": " + playlist.getDisplayName());
builder.setMessage(context.getString(R.string.action_lists_confirm_delete) );
builder.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
playlists.remove(playlist);
playlistAdapter.notifyDataSetChanged();
new ManagePlaylistsAsyncTask(context, ManagePlaylistsAsyncTask.action.DELETE_PLAYLIST,playlist, null, null, PlaylistAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
if( playlists.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE)
textviewNoAction.setVisibility(View.VISIBLE);
dialog.dismiss();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.show();
return false;
}
});
return convertView;
}
@Override
public void onActionDone(ManagePlaylistsAsyncTask.action actionType, APIResponse apiResponse, int statusCode) {
}
private class ViewHolder {
LinearLayout search_container;
TextView search_title;

View File

@ -16,6 +16,7 @@ package app.fedilab.android.fragments;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -25,8 +26,10 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog;
import android.text.InputFilter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -40,6 +43,18 @@ import android.widget.Toast;
import com.jaredrummler.materialspinner.MaterialSpinner;
import net.gotev.uploadservice.MultipartUploadRequest;
import net.gotev.uploadservice.ServerResponse;
import net.gotev.uploadservice.UploadInfo;
import net.gotev.uploadservice.UploadNotificationAction;
import net.gotev.uploadservice.UploadNotificationConfig;
import net.gotev.uploadservice.UploadStatusDelegate;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -48,8 +63,12 @@ import java.util.List;
import java.util.Map;
import app.fedilab.android.R;
import app.fedilab.android.activities.BaseMainActivity;
import app.fedilab.android.activities.ListActivity;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.activities.PeertubeEditUploadActivity;
import app.fedilab.android.activities.PeertubeUploadActivity;
import app.fedilab.android.activities.PlaylistsActivity;
import app.fedilab.android.asynctasks.ManagePlaylistsAsyncTask;
import app.fedilab.android.asynctasks.RetrievePeertubeChannelsAsyncTask;
import app.fedilab.android.client.APIResponse;
@ -170,24 +189,89 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi
dialogBuilder.setPositiveButton(R.string.validate, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
if( display_name.getText() != null && display_name.getText().toString().trim().length() > 0 ) {
Playlist playlist = new Playlist();
playlist.setDisplayName(display_name.getText().toString().trim());
if( description.getText() != null ){
if( description.getText() != null && description.getText().toString().trim().length() > 0 ){
playlist.setDescription(description.getText().toString().trim());
}
if( channelToSend != null) {
String idChannel = null;
if( channelToSend != null ) {
Map.Entry<String, String> channelM = channelToSend.entrySet().iterator().next();
String idChannel = channelM.getValue();
playlist.setVideoChannelId(idChannel);
idChannel = channelM.getValue();
if( idChannel.length() > 0)
playlist.setVideoChannelId(idChannel);
}
if( privacyToSend != null){
playlist.setPrivacy(privacyToSend);
Map.Entry<Integer, String> privacyM = privacyToSend.entrySet().iterator().next();
String label = privacyM.getValue();
String idPrivacy = String.valueOf(privacyM.getKey());
if( label.equals("Public") && (playlist.getVideoChannelId() == null || playlist.getVideoChannelId().equals(""))){
Toasty.error(context, context.getString(R.string.error_channel_mandatory),Toast.LENGTH_LONG).show();
}else{
if( privacyToSend != null){
playlist.setPrivacy(privacyToSend);
}
//new ManagePlaylistsAsyncTask(context, ManagePlaylistsAsyncTask.action.CREATE_PLAYLIST, playlist, null, null, DisplayPlaylistsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
UploadNotificationConfig uploadConfig = new UploadNotificationConfig();
uploadConfig.getCompleted().autoClear = true;
try {
String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
new MultipartUploadRequest(context, "https://" + Helper.getLiveInstance(context) + "/api/v1/video-playlists/")
//.addFileToUpload(uri.toString().replace("file://",""), "videofile")
.addHeader("Authorization", "Bearer " + token)
.setNotificationConfig(uploadConfig)
// .addParameter("name", filename)
.addParameter("videoChannelId", idChannel)
.addParameter("privacy", idPrivacy)
.addParameter("displayName", playlist.getDisplayName())
.addParameter("description", playlist.getDescription())
.setMaxRetries(1)
.setDelegate(new UploadStatusDelegate() {
@Override
public void onProgress(Context context, UploadInfo uploadInfo) {
// your code here
}
@Override
public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse,
Exception exception) {
// your code here
exception.printStackTrace();
}
@Override
public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {
DisplayPlaylistsFragment displayPlaylistsFragment;
if( getActivity() == null)
return;
displayPlaylistsFragment = (DisplayPlaylistsFragment) getActivity().getSupportFragmentManager().findFragmentByTag("PLAYLISTS");
final FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
if( displayPlaylistsFragment != null) {
ft.detach(displayPlaylistsFragment);
ft.attach(displayPlaylistsFragment);
ft.commit();
}
}
@Override
public void onCancelled(Context context, UploadInfo uploadInfo) {
// your code here
}
})
.startUpload();
} catch (MalformedURLException e) {
e.printStackTrace();
}
dialog.dismiss();
add_new.setEnabled(false);
}
new ManagePlaylistsAsyncTask(context, ManagePlaylistsAsyncTask.action.CREATE_PLAYLIST, playlist, null, null, DisplayPlaylistsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}else{
Toasty.error(context, context.getString(R.string.error_display_name),Toast.LENGTH_LONG).show();
}
dialog.dismiss();
add_new.setEnabled(false);
}
});
dialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@ -199,7 +283,7 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi
AlertDialog alertDialog = dialogBuilder.create();
alertDialog.setTitle(getString(R.string.action_lists_create));
alertDialog.setTitle(getString(R.string.action_playlist_create));
alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
@ -250,8 +334,9 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi
Toasty.error(context, apiResponse.getError().getError(),Toast.LENGTH_LONG).show();
return;
}
if( actionType == ManagePlaylistsAsyncTask.action.GET_PLAYLIST) {
if (apiResponse.getLists() != null && apiResponse.getLists().size() > 0) {
if (apiResponse.getPlaylists() != null && apiResponse.getPlaylists().size() > 0) {
this.playlists.addAll(apiResponse.getPlaylists());
playlistAdapter.notifyDataSetChanged();
textviewNoAction.setVisibility(View.GONE);
@ -259,13 +344,10 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi
textviewNoAction.setVisibility(View.VISIBLE);
}
}else if( actionType == ManagePlaylistsAsyncTask.action.CREATE_PLAYLIST){
if (apiResponse.getLists() != null && apiResponse.getLists().size() > 0) {
String listId = apiResponse.getLists().get(0).getId();
String title = apiResponse.getLists().get(0).getTitle();
Intent intent = new Intent(context, ListActivity.class);
if (apiResponse.getPlaylists() != null && apiResponse.getPlaylists().size() > 0) {
Intent intent = new Intent(context, PlaylistsActivity.class);
Bundle b = new Bundle();
b.putString("id", listId);
b.putString("title", title);
b.putParcelable("playlist", apiResponse.getPlaylists().get(0));
intent.putExtras(b);
context.startActivity(intent);
this.playlists.add(0, apiResponse.getPlaylists().get(0));
@ -303,9 +385,11 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi
//Populate channels
List<Account> accounts = apiResponse.getAccounts();
String[] channelName = new String[accounts.size()];
String[] channelId = new String[accounts.size()];
int i = 0;
String[] channelName = new String[accounts.size()+1];
String[] channelId = new String[accounts.size()+1];
int i = 1;
channelName[0] = "";
channelId[0] = "";
for (Account account : accounts) {
channels.put(account.getUsername(), account.getId());
channelName[i] = account.getUsername();
@ -323,11 +407,11 @@ public class DisplayPlaylistsFragment extends Fragment implements OnPlaylistActi
if (peertubeInformation.getTranslations() != null)
translations = new LinkedHashMap<>(peertubeInformation.getTranslations());
LinkedHashMap<Integer, String> privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies());
LinkedHashMap<Integer, String> privaciesInit = new LinkedHashMap<>(peertubeInformation.getPlaylistPrivacies());
Map.Entry<Integer, String> entryInt = privaciesInit.entrySet().iterator().next();
privacyToSend = new HashMap<>();
privacyToSend.put(entryInt.getKey(), entryInt.getValue());
LinkedHashMap<Integer, String> privacies = new LinkedHashMap<>(peertubeInformation.getPrivacies());
LinkedHashMap<Integer, String> privacies = new LinkedHashMap<>(peertubeInformation.getPlaylistPrivacies());
//Populate privacies
String[] privaciesA = new String[privacies.size()];
Iterator it = privacies.entrySet().iterator();

View File

@ -33,45 +33,54 @@
/>
<!-- Videos channels -->
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:gravity="center"
android:textSize="16sp"
android:layout_width="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="wrap_content"
android:text="@string/channel"/>
<com.jaredrummler.materialspinner.MaterialSpinner
android:textSize="16sp"
android:id="@+id/set_upload_channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:gravity="center_vertical"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:gravity="center"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/channel"/>
<com.jaredrummler.materialspinner.MaterialSpinner
android:textSize="16sp"
android:id="@+id/set_upload_channel"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- Videos Privacy -->
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:gravity="center"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_privacy"/>
<com.jaredrummler.materialspinner.MaterialSpinner
android:textSize="16sp"
android:id="@+id/set_upload_privacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<!-- Videos Privacy -->
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:gravity="center"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/action_privacy"/>
<com.jaredrummler.materialspinner.MaterialSpinner
android:textSize="16sp"
android:id="@+id/set_upload_privacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View File

@ -956,6 +956,9 @@
<string name="privacy">Privacy</string>
<string name="create">Create</string>
<string name="action_playlist_add">You don\'t have any playlists. Click on the \"+\" icon to add a new playlist</string>
<string name="error_display_name">You must provide a display name!</string>
<string name="error_channel_mandatory">The channel is required when the playlist is public.</string>
<string name="action_playlist_create">Create a playlist</string>
<plurals name="number_of_vote">
<item quantity="one">%d vote</item>