diff --git a/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java index bb49861e3..a1b5622d9 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseMainActivity.java @@ -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(); diff --git a/app/src/main/java/app/fedilab/android/asynctasks/ManagePlaylistsAsyncTask.java b/app/src/main/java/app/fedilab/android/asynctasks/ManagePlaylistsAsyncTask.java index 55c5f52d3..7fdf05cff 100644 --- a/app/src/main/java/app/fedilab/android/asynctasks/ManagePlaylistsAsyncTask.java +++ b/app/src/main/java/app/fedilab/android/asynctasks/ManagePlaylistsAsyncTask.java @@ -78,12 +78,8 @@ public class ManagePlaylistsAsyncTask extends AsyncTask { 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){ diff --git a/app/src/main/java/app/fedilab/android/client/Entities/PeertubeInformation.java b/app/src/main/java/app/fedilab/android/client/Entities/PeertubeInformation.java index 67d3a6f7e..504a971a1 100644 --- a/app/src/main/java/app/fedilab/android/client/Entities/PeertubeInformation.java +++ b/app/src/main/java/app/fedilab/android/client/Entities/PeertubeInformation.java @@ -25,8 +25,10 @@ public class PeertubeInformation { private LinkedHashMap languages; private LinkedHashMap licences; private LinkedHashMap privacies; + private LinkedHashMap playlistPrivacies; private LinkedHashMap translations; + public static final LinkedHashMap langueMapped; static { LinkedHashMap aMap = new LinkedHashMap<>(); @@ -86,4 +88,12 @@ public class PeertubeInformation { public void setPrivacies(LinkedHashMap privacies) { this.privacies = privacies; } + + public LinkedHashMap getPlaylistPrivacies() { + return playlistPrivacies; + } + + public void setPlaylistPrivacies(LinkedHashMap playlistPrivacies) { + this.playlistPrivacies = playlistPrivacies; + } } diff --git a/app/src/main/java/app/fedilab/android/client/PeertubeAPI.java b/app/src/main/java/app/fedilab/android/client/PeertubeAPI.java index 55b008ab1..b819ffc8b 100644 --- a/app/src/main/java/app/fedilab/android/client/PeertubeAPI.java +++ b/app/src/main/java/app/fedilab/android/client/PeertubeAPI.java @@ -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 _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 _plicences = new LinkedHashMap<>(); @@ -1342,7 +1351,7 @@ public class PeertubeAPI { List 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 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 privacyM = playlist.getPrivacy().entrySet().iterator().next(); - Integer idPrivacy = privacyM.getKey(); - params.put("privacy", String.valueOf(idPrivacy)); - } - - List 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 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 privacyM = playlist.getPrivacy().entrySet().iterator().next(); - Integer idPrivacy = privacyM.getKey(); - params.put("privacy", String.valueOf(idPrivacy)); - } - - List 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; } diff --git a/app/src/main/java/app/fedilab/android/drawers/PlaylistAdapter.java b/app/src/main/java/app/fedilab/android/drawers/PlaylistAdapter.java index 9e418b60e..7419961bb 100644 --- a/app/src/main/java/app/fedilab/android/drawers/PlaylistAdapter.java +++ b/app/src/main/java/app/fedilab/android/drawers/PlaylistAdapter.java @@ -15,10 +15,13 @@ package app.fedilab.android.drawers; * see . */ +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 playlists; private LayoutInflater layoutInflater; private Context context; + private PlaylistAdapter playlistAdapter; + private RelativeLayout textviewNoAction; public PlaylistAdapter(Context context, List 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; diff --git a/app/src/main/java/app/fedilab/android/fragments/DisplayPlaylistsFragment.java b/app/src/main/java/app/fedilab/android/fragments/DisplayPlaylistsFragment.java index 88b38f9fe..7d495e5a4 100644 --- a/app/src/main/java/app/fedilab/android/fragments/DisplayPlaylistsFragment.java +++ b/app/src/main/java/app/fedilab/android/fragments/DisplayPlaylistsFragment.java @@ -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 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 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 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 privaciesInit = new LinkedHashMap<>(peertubeInformation.getPrivacies()); + LinkedHashMap privaciesInit = new LinkedHashMap<>(peertubeInformation.getPlaylistPrivacies()); Map.Entry entryInt = privaciesInit.entrySet().iterator().next(); privacyToSend = new HashMap<>(); privacyToSend.put(entryInt.getKey(), entryInt.getValue()); - LinkedHashMap privacies = new LinkedHashMap<>(peertubeInformation.getPrivacies()); + LinkedHashMap privacies = new LinkedHashMap<>(peertubeInformation.getPlaylistPrivacies()); //Populate privacies String[] privaciesA = new String[privacies.size()]; Iterator it = privacies.entrySet().iterator(); diff --git a/app/src/main/res/layout/add_playlist.xml b/app/src/main/res/layout/add_playlist.xml index dea09134b..15c294776 100644 --- a/app/src/main/res/layout/add_playlist.xml +++ b/app/src/main/res/layout/add_playlist.xml @@ -33,45 +33,54 @@ /> - + - + android:gravity="center_vertical" + android:layout_gravity="center_horizontal" + android:orientation="vertical"> + + + + + + + + - - - - - + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 742501662..05d6fab4e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -956,6 +956,9 @@ Privacy Create You don\'t have any playlists. Click on the \"+\" icon to add a new playlist + You must provide a display name! + The channel is required when the playlist is public. + Create a playlist %d vote