From 0c11d8fba5a8e52c9b223d31d7de79abf2cd8328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schu=CC=88ller?= Date: Sat, 5 Jan 2019 23:05:01 +0100 Subject: [PATCH] - Like / dislike cleanup - Video download - Version bump --- CHANGELOG.md | 4 + app/build.gradle | 4 +- .../fragment/VideoMetaDataFragment.java | 231 +++++++++++------- .../schueller/peertube/intents/Intents.java | 34 +++ .../net/schueller/peertube/model/File.java | 45 ++++ .../net/schueller/peertube/model/Rating.java | 28 +++ .../peertube/network/GetVideoDataService.java | 6 + app/src/main/res/layout/activity_login.xml | 3 +- .../main/res/layout/fragment_video_meta.xml | 46 +--- app/src/main/res/values/strings.xml | 22 +- 10 files changed, 295 insertions(+), 128 deletions(-) create mode 100644 app/src/main/java/net/schueller/peertube/model/Rating.java diff --git a/CHANGELOG.md b/CHANGELOG.md index aae0181..62c0dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### Version 1.0.22 Tag: v1.0.22 (2019-01-05) + * Cleaned up like/dislike + * Added video download + ### Version 1.0.21 Tag: v1.0.21 (2019-01-05) * Added more video meta data * Very basic like and dislike functionality diff --git a/app/build.gradle b/app/build.gradle index 743bc74..c00b78b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "net.schueller.peertube" minSdkVersion 21 targetSdkVersion 28 - versionCode 1021 - versionName "1.0.21" + versionCode 1022 + versionName "1.0.22" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" ext { libVersions = [ diff --git a/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.java b/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.java index 95507a6..0a717f2 100644 --- a/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.java +++ b/app/src/main/java/net/schueller/peertube/fragment/VideoMetaDataFragment.java @@ -1,12 +1,15 @@ package net.schueller.peertube.fragment; +import android.Manifest; import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; import android.os.Bundle; -import android.util.ArrayMap; import android.util.Log; +import android.util.TypedValue; import android.view.LayoutInflater; -import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -14,30 +17,27 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; -import com.mikepenz.fontawesome_typeface_library.FontAwesome; import com.mikepenz.iconics.Iconics; -import com.mikepenz.iconics.IconicsDrawable; import com.squareup.picasso.Picasso; import net.schueller.peertube.R; -import net.schueller.peertube.activity.VideoPlayActivity; import net.schueller.peertube.helper.APIUrlHelper; import net.schueller.peertube.helper.MetaDataHelper; import net.schueller.peertube.intents.Intents; import net.schueller.peertube.model.Account; import net.schueller.peertube.model.Avatar; +import net.schueller.peertube.model.Rating; import net.schueller.peertube.model.Video; import net.schueller.peertube.network.GetVideoDataService; import net.schueller.peertube.network.RetrofitInstance; import net.schueller.peertube.network.Session; import net.schueller.peertube.service.VideoPlayerService; -import org.json.JSONObject; import androidx.annotation.NonNull; import androidx.appcompat.widget.PopupMenu; +import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Call; @@ -48,6 +48,8 @@ public class VideoMetaDataFragment extends Fragment { private static final String TAG = "VideoMetaDataFragment"; + private Rating videoRating; + private ColorStateList defaultTextColor; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -63,113 +65,79 @@ public class VideoMetaDataFragment extends Fragment { Context context = getContext(); Activity activity = getActivity(); + String apiBaseURL = APIUrlHelper.getUrlWithVersion(context); + GetVideoDataService videoDataService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class); // Thumbs up Button thumbsUpButton = activity.findViewById(R.id.video_thumbs_up); + defaultTextColor = thumbsUpButton.getTextColors(); thumbsUpButton.setText(R.string.video_thumbs_up_icon); new Iconics.IconicsBuilder().ctx(context).on(thumbsUpButton).build(); thumbsUpButton.setOnClickListener(v -> { - - if (Session.getInstance().isLoggedIn()) { - - // TODO: move this out helper/service - RequestBody body = RequestBody.create( - okhttp3.MediaType.parse("application/json"), - "{\"rating\":\"like\"}" - ); - - String apiBaseURL = APIUrlHelper.getUrlWithVersion(context); - GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class); - - Call call = service.rateVideo(video.getId(), body); - - call.enqueue(new Callback() { - - @Override - public void onResponse(Call call, Response response) { - - Log.v(TAG, response.toString() ); - - // if 20x update likes - } - - @Override - public void onFailure(Call call, Throwable t) { - Toast.makeText(context, "Rating Failed", Toast.LENGTH_SHORT).show(); - } - }); - } else { - Toast.makeText(context, "You must login to use this service", Toast.LENGTH_SHORT).show(); - - } - + rateVideo(true, video.getId()); }); TextView thumbsUpButtonTotal = activity.findViewById(R.id.video_thumbs_up_total); thumbsUpButtonTotal.setText(video.getLikes().toString()); // Thumbs Down - TextView thumbsDownButton = activity.findViewById(R.id.video_thumbs_down); + Button thumbsDownButton = activity.findViewById(R.id.video_thumbs_down); thumbsDownButton.setText(R.string.video_thumbs_down_icon); new Iconics.IconicsBuilder().ctx(context).on(thumbsDownButton).build(); thumbsDownButton.setOnClickListener(v -> { - - if (Session.getInstance().isLoggedIn()) { - - // TODO: move this out helper/service - RequestBody body = RequestBody.create( - okhttp3.MediaType.parse("application/json"), - "{\"rating\":\"dislike\"}" - ); - - String apiBaseURL = APIUrlHelper.getUrlWithVersion(context); - GetVideoDataService service = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class); - - Call call = service.rateVideo(video.getId(), body); - - call.enqueue(new Callback() { - - @Override - public void onResponse(Call call, Response response) { - - // if 20x update likes - - Log.v(TAG, response.toString() ); - - } - - @Override - public void onFailure(Call call, Throwable t) { - Toast.makeText(context, "Rating Failed", Toast.LENGTH_SHORT).show(); - } - }); - } else { - Toast.makeText(context, "You must login to use this service", Toast.LENGTH_SHORT).show(); - - } - + rateVideo(false, video.getId()); }); + + // video rating + videoRating = new Rating(); + videoRating.setRating("none"); // default + updateVideoRating(); + + if (Session.getInstance().isLoggedIn()) { + Call call = videoDataService.getVideoRating(video.getId()); + call.enqueue(new Callback() { + + @Override + public void onResponse(Call call, Response response) { + videoRating = response.body(); + updateVideoRating(); + } + + @Override + public void onFailure(Call call, Throwable t) { +// Toast.makeText(context, "Rating Failed", Toast.LENGTH_SHORT).show(); + } + }); + } + + TextView thumbsDownButtonTotal = activity.findViewById(R.id.video_thumbs_down_total); thumbsDownButtonTotal.setText(video.getDislikes().toString()); // Share - TextView videoShareButton = activity.findViewById(R.id.video_share); + Button videoShareButton = activity.findViewById(R.id.video_share); videoShareButton.setText(R.string.video_share_icon); new Iconics.IconicsBuilder().ctx(context).on(videoShareButton).build(); videoShareButton.setOnClickListener(v -> Intents.Share(context, video)); // Download - TextView videoDownloadButton = activity.findViewById(R.id.video_download); + Button videoDownloadButton = activity.findViewById(R.id.video_download); videoDownloadButton.setText(R.string.video_download_icon); new Iconics.IconicsBuilder().ctx(context).on(videoDownloadButton).build(); - videoDownloadButton.setOnClickListener(v -> Toast.makeText(context, "Not Implemented", Toast.LENGTH_SHORT).show()); - - // add to playlist - TextView videoSaveButton = activity.findViewById(R.id.video_save); - videoSaveButton.setText(R.string.video_save_icon); - new Iconics.IconicsBuilder().ctx(context).on(videoSaveButton).build(); - videoSaveButton.setOnClickListener(v -> Toast.makeText(context, "Not Implemented", Toast.LENGTH_SHORT).show()); + videoDownloadButton.setOnClickListener(v -> { + // get permission to store file + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + Intents.Download(context, video); + } else { + Toast.makeText(context, getString(R.string.video_download_permission_error), Toast.LENGTH_LONG).show(); + } + } else { + Intents.Download(context, video); + } + }); Account account = video.getAccount(); @@ -245,11 +213,11 @@ public class VideoMetaDataFragment extends Fragment { popup.setOnMenuItemClickListener(menuItem -> { switch (menuItem.getItemId()) { case R.id.video_more_report: - Log.v(TAG, "Report" ); + Log.v(TAG, "Report"); Toast.makeText(context, "Not Implemented", Toast.LENGTH_SHORT).show(); return true; case R.id.video_more_blacklist: - Log.v(TAG, "Blacklist" ); + Log.v(TAG, "Blacklist"); Toast.makeText(context, "Not Implemented", Toast.LENGTH_SHORT).show(); return true; default: @@ -275,4 +243,91 @@ public class VideoMetaDataFragment extends Fragment { } + + void updateVideoRating() { + Button thumbsUpButton = getActivity().findViewById(R.id.video_thumbs_up); + Button thumbsDownButton = getActivity().findViewById(R.id.video_thumbs_down); + + TypedValue typedValue = new TypedValue(); + + TypedArray a = getContext().obtainStyledAttributes(typedValue.data, new int[]{R.attr.colorPrimary}); + int accentColor = a.getColor(0, 0); + + if (videoRating.getRating().equals(getString(R.string.video_rating_none))) { + thumbsUpButton.setTextColor(defaultTextColor); + thumbsDownButton.setTextColor(defaultTextColor); + //Log.v(TAG, getString(R.string.video_rating_none)); + + } else if (videoRating.getRating().equals(getString(R.string.video_rating_like))) { + thumbsUpButton.setTextColor(accentColor); + thumbsDownButton.setTextColor(defaultTextColor); + //Log.v(TAG, getString(R.string.video_rating_like)); + + } else if (videoRating.getRating().equals(getString(R.string.video_rating_dislike))) { + thumbsUpButton.setTextColor(defaultTextColor); + thumbsDownButton.setTextColor(accentColor); + //Log.v(TAG, getString(R.string.video_rating_dislike)); + + } + + a.recycle(); + } + + void rateVideo(Boolean rate, Integer videoId) { + + // TODO cleanup + + if (Session.getInstance().isLoggedIn()) { + + String ratePayload = getString(R.string.video_rating_none); + + if (rate) { + // thumbsup + if (videoRating.getRating().equals(getString(R.string.video_rating_none))) { + ratePayload = getString(R.string.video_rating_like); + } + } else { + // thumbsdown + if (videoRating.getRating().equals(getString(R.string.video_rating_none))) { + ratePayload = getString(R.string.video_rating_dislike); + } + } + + RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json"), "{\"rating\":\"" + ratePayload + "\"}"); + + String apiBaseURL = APIUrlHelper.getUrlWithVersion(getContext()); + GetVideoDataService videoDataService = RetrofitInstance.getRetrofitInstance(apiBaseURL).create(GetVideoDataService.class); + + Call call = videoDataService.rateVideo(videoId, body); + + final String newRating = ratePayload; + + call.enqueue(new Callback() { + + @Override + public void onResponse(Call call, Response response) { + + //Log.v(TAG, response.toString()); + + // if 20x update likes + if (response.isSuccessful()) { + videoRating.setRating(newRating); + updateVideoRating(); + + // TODO: update count under thumb + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Toast.makeText(getContext(), getString(R.string.video_rating_failed), Toast.LENGTH_SHORT).show(); + } + }); + } else { + Toast.makeText(getContext(), getString(R.string.video_login_required_for_service), Toast.LENGTH_SHORT).show(); + + } + + } + } diff --git a/app/src/main/java/net/schueller/peertube/intents/Intents.java b/app/src/main/java/net/schueller/peertube/intents/Intents.java index 2ca421b..29ea9c3 100644 --- a/app/src/main/java/net/schueller/peertube/intents/Intents.java +++ b/app/src/main/java/net/schueller/peertube/intents/Intents.java @@ -17,11 +17,23 @@ */ package net.schueller.peertube.intents; +import android.Manifest; +import android.app.DownloadManager; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.webkit.URLUtil; + +import com.github.se_bastiaan.torrentstream.TorrentOptions; + import net.schueller.peertube.helper.APIUrlHelper; import net.schueller.peertube.model.Video; +import androidx.core.app.ActivityCompat; + public class Intents { @@ -32,6 +44,7 @@ public class Intents { * @param context context * @param video video */ + // TODO, offer which version to download public static void Share(Context context, Video video) { Intent intent = new Intent(); @@ -43,4 +56,25 @@ public class Intents { context.startActivity(intent); } + + /** + * + * @param context context + * @param video video + */ + // TODO, offer which version to download + public static void Download(Context context, Video video) { + + String url = video.getFiles().get(0).getFileDownloadUrl(); + DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); + request.setDescription(video.getDescription()); + request.setTitle(video.getName()); + request.allowScanningByMediaScanner(); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, null, null)); + + // get download service and enqueue file + DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + manager.enqueue(request); + } } diff --git a/app/src/main/java/net/schueller/peertube/model/File.java b/app/src/main/java/net/schueller/peertube/model/File.java index eb426ba..fe993da 100644 --- a/app/src/main/java/net/schueller/peertube/model/File.java +++ b/app/src/main/java/net/schueller/peertube/model/File.java @@ -18,13 +18,50 @@ package net.schueller.peertube.model; public class File { + private Integer id; + private String fileDownloadUrl; + private Integer fps; + private String label; private Resolution resolution; private String resolutionLabel; private String magnetUri; private Integer size; private String torrentUrl; + private String torrentDownloadUrl; private String fileUrl; + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getFileDownloadUrl() { + return fileDownloadUrl; + } + + public void setFileDownloadUrl(String fileDownloadUrl) { + this.fileDownloadUrl = fileDownloadUrl; + } + + public Integer getFps() { + return fps; + } + + public void setFps(Integer fps) { + this.fps = fps; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + public Resolution getResolution() { return resolution; } @@ -65,6 +102,14 @@ public class File { this.torrentUrl = torrentUrl; } + public String getTorrentDownloadUrl() { + return torrentDownloadUrl; + } + + public void setTorrentDownloadUrl(String torrentDownloadUrl) { + this.torrentDownloadUrl = torrentDownloadUrl; + } + public String getFileUrl() { return fileUrl; } diff --git a/app/src/main/java/net/schueller/peertube/model/Rating.java b/app/src/main/java/net/schueller/peertube/model/Rating.java new file mode 100644 index 0000000..05c4b01 --- /dev/null +++ b/app/src/main/java/net/schueller/peertube/model/Rating.java @@ -0,0 +1,28 @@ +package net.schueller.peertube.model; + +import com.google.gson.annotations.SerializedName; + +public class Rating { + + @SerializedName("videoId") + private Integer videoId; + + @SerializedName("rating") + private String rating; + + public Integer getVideoId() { + return videoId; + } + + public void setVideoId(Integer videoId) { + this.videoId = videoId; + } + + public String getRating() { + return rating; + } + + public void setRating(String rating) { + this.rating = rating; + } +} diff --git a/app/src/main/java/net/schueller/peertube/network/GetVideoDataService.java b/app/src/main/java/net/schueller/peertube/network/GetVideoDataService.java index e88afbc..51cc6d0 100644 --- a/app/src/main/java/net/schueller/peertube/network/GetVideoDataService.java +++ b/app/src/main/java/net/schueller/peertube/network/GetVideoDataService.java @@ -17,6 +17,7 @@ */ package net.schueller.peertube.network; +import net.schueller.peertube.model.Rating; import net.schueller.peertube.model.Video; import net.schueller.peertube.model.VideoList; @@ -59,6 +60,11 @@ public interface GetVideoDataService { @Query("languageOneOf") Set languages ); + @GET("users/me/videos/{id}/rating") + Call getVideoRating( + @Path(value = "id", encoded = true) Integer id + ); + @PUT("videos/{id}/rate") Call rateVideo( @Path(value = "id", encoded = true) Integer id, diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 6ea1ec6..fd5bdc0 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -46,7 +46,8 @@ + android:textSize="16sp" + android:text="Alpha! Login is still in heavy development and may not work correctly! You must have an account on the instance you are connecting to. Registration is currently not supported" /> @@ -173,7 +173,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" - android:text="Download" + android:text="@string/video_meta_button_download" android:textSize="12sp" /> @@ -183,28 +183,6 @@ android:layout_height="1dp" android:layout_weight="1" /> - - -