Java tutorial
/* * Copyright (c) 2016-2017. Vijai Chandra Prasad R. * * This program 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. * * This program 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 this program. If not, see http://www.gnu.org/licenses */ package com.orpheusdroid.screenrecorder.adapter; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.preference.PreferenceManager; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.view.ActionMode; import android.support.v7.widget.PopupMenu; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.orpheusdroid.screenrecorder.Const; import com.orpheusdroid.screenrecorder.EditVideoActivity; import com.orpheusdroid.screenrecorder.R; import com.orpheusdroid.screenrecorder.VideosListFragment; import com.orpheusdroid.screenrecorder.encoder.Mp4toGIFConverter; import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Locale; /** * <p> * Custom Recycler view adapter for video list fragment * </p> * * @author Vijai Chandra Prasad .R * @see SectionViewHolder * @see ItemViewHolder */ public class VideoRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { /** * Integer value for Section view type */ private static final int VIEW_SECTION = 0; /** * Integer value for Video item view type */ private static final int VIEW_ITEM = 1; /** * VideoListFragment object */ private VideosListFragment videosListFragment; /** * ArrayList containing the videos */ private ArrayList<Video> videos; private Context context; /** * Boolean to set if multi select to be enabled */ private boolean isMultiSelect = false; private int count = 0; /** * Actionbar actionmode object */ private ActionMode mActionMode; /** * Show a contextual menu in multiselect mode */ private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.video_list_action_menu, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; // Return false if nothing is done } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // Build an arraylist of selected item positions when an menu item is clicked switch (item.getItemId()) { case R.id.delete: ArrayList<Video> deleteFiles = new ArrayList<>(); for (Video video : videos) { if (video.isSelected()) { //deleFiles.add(new File(videos.get(videos.indexOf(video)).getFile().getPath())); deleteFiles.add(video); } } if (!deleteFiles.isEmpty()) confirmDelete(deleteFiles); mActionMode.finish(); break; case R.id.share: ArrayList<Integer> positions = new ArrayList<>(); for (Video video : videos) { if (video.isSelected()) { positions.add(videos.indexOf(video)); } } if (!positions.isEmpty()) shareVideos(positions); mActionMode.finish(); break; case R.id.select_all: for (Video video : videos) video.setSelected(true); mActionMode.setTitle("" + videos.size()); notifyDataSetChanged(); break; } return true; } @Override public void onDestroyActionMode(ActionMode mode) { // remove all selected videos and reload recyclerview for (Video video : videos) { video.setSelected(false); } isMultiSelect = false; notifyDataSetChanged(); } }; public VideoRecyclerAdapter(Context context, ArrayList<Video> android, VideosListFragment videosListFragment) { this.videos = android; this.context = context; this.videosListFragment = videosListFragment; } /** * Find if the view is a section type or video type * * @param position position of the arraylist of videos * @return the item type */ @Override public int getItemViewType(int position) { return isSection(position) ? VIEW_SECTION : VIEW_ITEM; } /** * Method to determine the type * @param position position of the arraylist of videos * @return true if the item is a section. False otherwise */ public boolean isSection(int position) { return videos.get(position).isSection(); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { View view; switch (viewType) { case VIEW_SECTION: view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.content_video_section, viewGroup, false); return new SectionViewHolder(view); case VIEW_ITEM: view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.content_video, viewGroup, false); return new ItemViewHolder(view); default: view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.content_video, viewGroup, false); return new ItemViewHolder(view); } } @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) { final Video video = videos.get(position); switch (holder.getItemViewType()) { case VIEW_ITEM: final ItemViewHolder itemViewHolder = (ItemViewHolder) holder; //Set video file name itemViewHolder.tv_fileName.setText(video.getFileName()); //If thumbnail has failed for some reason, set empty image resource to imageview if (videos.get(position).getThumbnail() != null) { itemViewHolder.iv_thumbnail.setImageBitmap(video.getThumbnail()); } else { itemViewHolder.iv_thumbnail.setImageResource(0); Log.d(Const.TAG, "thumbnail error"); } // Hide the play image over thumbnail and overflow menu if multiselect enabled if (isMultiSelect) { itemViewHolder.iv_play.setVisibility(View.INVISIBLE); itemViewHolder.overflow.setVisibility(View.INVISIBLE); } else { itemViewHolder.iv_play.setVisibility(View.VISIBLE); itemViewHolder.overflow.setVisibility(View.VISIBLE); } // Set foreground color to identify selected items if (video.isSelected()) { itemViewHolder.selectableFrame.setForeground( new ColorDrawable(ContextCompat.getColor(context, R.color.multiSelectColor))); } else { itemViewHolder.selectableFrame.setForeground( new ColorDrawable(ContextCompat.getColor(context, android.R.color.transparent))); } itemViewHolder.overflow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { PopupMenu popupMenu = new PopupMenu(context, view); popupMenu.inflate(R.menu.popupmenu); popupMenu.show(); popupMenu.getMenu().getItem(3).setEnabled(PreferenceManager.getDefaultSharedPreferences(context) .getBoolean(context.getString(R.string.preference_save_gif_key), false)); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.share: shareVideo(itemViewHolder.getAdapterPosition()); break; case R.id.delete: confirmDelete(holder.getAdapterPosition()); break; case R.id.edit: Toast.makeText(context, "Edit video for " + itemViewHolder.getAdapterPosition(), Toast.LENGTH_SHORT).show(); Intent editIntent = new Intent(context, EditVideoActivity.class); editIntent.putExtra(Const.VIDEO_EDIT_URI_KEY, Uri.fromFile(video.getFile()).toString()); Log.d(Const.TAG, "Uri: " + Uri.fromFile(video.getFile())); videosListFragment.startActivityForResult(editIntent, Const.VIDEO_EDIT_REQUEST_CODE); break; case R.id.savegif: Mp4toGIFConverter gif = new Mp4toGIFConverter(context); gif.setVideoUri(Uri.fromFile(video.getFile())); gif.convertToGif(); } return true; } }); } }); //Show user a chooser to play the video with itemViewHolder.videoCard.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Video video = videos.get(itemViewHolder.getAdapterPosition()); // If multiselect is enabled, select the items pressed by user if (isMultiSelect) { // main count of the selected items // If the video is already selected, reduce count else increment count if (video.isSelected()) count--; else count++; // Enable disable selection based on previous choice video.setSelected(!video.isSelected()); notifyDataSetChanged(); mActionMode.setTitle("" + count); // If the count is 0, disable muliselect if (count == 0) setMultiSelect(false); return; } File videoFile = video.getFile(); Log.d("Videos List", "video position clicked: " + itemViewHolder.getAdapterPosition()); Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", videoFile); Log.d(Const.TAG, fileUri.toString()); Intent openVideoIntent = new Intent(); openVideoIntent.setAction(Intent.ACTION_VIEW).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .setDataAndType(fileUri, context.getContentResolver().getType(fileUri)); context.startActivity(openVideoIntent); } }); // LongClickListener to enable multiselect itemViewHolder.videoCard.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { if (!isMultiSelect) { setMultiSelect(true); video.setSelected(true); count++; mActionMode.setTitle("" + count); notifyDataSetChanged(); } return true; } }); break; case VIEW_SECTION: SectionViewHolder sectionViewHolder = (SectionViewHolder) holder; sectionViewHolder.section.setText(generateSectionTitle(video.getLastModified())); break; } } /** * method to set if multi select to be enabled * @param isMultiSelect boolean */ private void setMultiSelect(boolean isMultiSelect) { if (isMultiSelect) { this.isMultiSelect = true; count = 0; mActionMode = ((AppCompatActivity) videosListFragment.getActivity()) .startSupportActionMode(mActionModeCallback); } else { this.isMultiSelect = false; mActionMode.finish(); } } /** * Share the videos selected * * @param position Integer value representing the position of the video to be shared * @see #shareVideos(ArrayList positions) */ private void shareVideo(int position) { Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", videos.get(position).getFile()); Intent Shareintent = new Intent().setAction(Intent.ACTION_SEND).setType("video/*") .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION).putExtra(Intent.EXTRA_STREAM, fileUri); context.startActivity( Intent.createChooser(Shareintent, context.getString(R.string.share_intent_notification_title))); } /** * Share the videos selected * * @param positions Integer ArrayList containing the positions of the videos to be shared * * @see #shareVideo(int postion) */ private void shareVideos(ArrayList<Integer> positions) { ArrayList<Uri> videoList = new ArrayList<>(); for (int position : positions) { videoList.add(FileProvider.getUriForFile(context, context.getPackageName() + ".provider", videos.get(position).getFile())); } Intent Shareintent = new Intent().setAction(Intent.ACTION_SEND_MULTIPLE).setType("video/*") .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .putParcelableArrayListExtra(Intent.EXTRA_STREAM, videoList); context.startActivity( Intent.createChooser(Shareintent, context.getString(R.string.share_intent_notification_title))); } /** * Delete the videos selected * * @param position integer value representing the position of the video to be deleted * * @see #deleteVideo(int position) */ private void deleteVideo(int position) { Log.d("Videos List", "delete position clicked: " + position); File file = new File(videos.get(position).getFile().getPath()); if (file.delete()) { Toast.makeText(context, "File deleted successfully", Toast.LENGTH_SHORT).show(); videos.remove(position); notifyItemRemoved(position); notifyItemRangeChanged(position, videos.size()); } } /** * Delete the videos selected * * @param deleteVideos ArrayList of integers containing the position of the videos to be deleted * * @see #deleteVideo(int position) */ private void deleteVideos(ArrayList<Video> deleteVideos) { for (Video video : deleteVideos) { if (video.getFile().delete()) { notifyItemRemoved(videos.indexOf(video)); videos.remove(videos.indexOf(video)); } } notifyDataSetChanged(); } /** * Show confirmation dialog before the video is deleted * * @param position integer representing the postion of the video in the dataset to delete */ private void confirmDelete(final int position) { new AlertDialog.Builder(context) .setTitle(context.getResources().getQuantityString(R.plurals.delete_alert_title, 1)) .setMessage(context.getResources().getQuantityString(R.plurals.delete_alert_message, 1)) .setCancelable(false) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { deleteVideo(position); } }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { } }).show(); } /** * Show confirmation dialog before the video is deleted * * @param deleteVideos Array list of integer containing the positions of the videos in the dataset to delete */ private void confirmDelete(final ArrayList<Video> deleteVideos) { int count = deleteVideos.size(); new AlertDialog.Builder(context) .setTitle(context.getResources().getQuantityString(R.plurals.delete_alert_title, count)) .setMessage(context.getResources().getQuantityString(R.plurals.delete_alert_message, count, count)) .setCancelable(false) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { deleteVideos(deleteVideos); } }).setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { } }).show(); } /** * Generate title for the section depending on the recording date * @param date Date when the videos where recorded * @return Simplified string for the section header */ private String generateSectionTitle(Date date) { Calendar sDate = toCalendar(new Date().getTime()); Calendar eDate = toCalendar(date.getTime()); // Get the represented date in milliseconds long milis1 = sDate.getTimeInMillis(); long milis2 = eDate.getTimeInMillis(); // Calculate difference in milliseconds int dayDiff = (int) Math.abs((milis2 - milis1) / (24 * 60 * 60 * 1000)); int yearDiff = sDate.get(Calendar.YEAR) - eDate.get(Calendar.YEAR); Log.d("ScreenRecorder", "yeardiff: " + yearDiff); if (yearDiff == 0) { switch (dayDiff) { case 0: return "Today"; case 1: return "Yesterday"; default: SimpleDateFormat format = new SimpleDateFormat("EEEE, dd MMM", Locale.getDefault()); return format.format(date); } } else { SimpleDateFormat format = new SimpleDateFormat("EEEE, dd MMM YYYY", Locale.getDefault()); return format.format(date); } } /** * Generate Calendar object and return it * @param timestamp timestamp for which Calendar object to be created * @return Calendar object */ private Calendar toCalendar(long timestamp) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timestamp); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar; } @Override public int getItemCount() { return videos.size(); } /** * ViewHolder class for video items */ private final class ItemViewHolder extends RecyclerView.ViewHolder { private TextView tv_fileName; private ImageView iv_thumbnail; private RelativeLayout videoCard; private FrameLayout selectableFrame; private ImageButton overflow; private ImageView iv_play; ItemViewHolder(View view) { super(view); tv_fileName = view.findViewById(R.id.fileName); iv_thumbnail = view.findViewById(R.id.thumbnail); iv_thumbnail.setScaleType(ImageView.ScaleType.CENTER_CROP); videoCard = view.findViewById(R.id.videoCard); overflow = view.findViewById(R.id.ic_overflow); selectableFrame = view.findViewById(R.id.selectableFrame); iv_play = view.findViewById(R.id.play_iv); } } /** * ViewHolder class for sections */ private final class SectionViewHolder extends RecyclerView.ViewHolder { private TextView section; SectionViewHolder(View view) { super(view); section = view.findViewById(R.id.sectionID); } } }