unified gallery pager for videos and image files

This commit is contained in:
Andrew Dolgov 2017-06-02 14:25:05 +03:00
parent bbab856e3f
commit 047bb1cc37
14 changed files with 556 additions and 581 deletions

View File

@ -258,11 +258,6 @@
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
android:theme="@style/DarkDialogTheme" />
<activity
android:name=".VideoPlayerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/title_activity_video_player" >
</activity>
<activity
android:name=".YoutubePlayerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"

View File

@ -24,18 +24,10 @@ import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
import com.bumptech.glide.request.target.Target;
public class ArticleImageFragment extends Fragment {
public class ArticleImageFragment extends GalleryBaseFragment {
private final String TAG = this.getClass().getSimpleName();
String m_url;
private ArticleImagesPagerActivity m_activity;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -128,48 +120,6 @@ public class ArticleImageFragment extends Fragment {
return true;
}*/
public boolean onImageMenuItemSelected(MenuItem item, String url) {
switch (item.getItemId()) {
case R.id.article_img_open:
if (url != null) {
try {
m_activity.openUri(Uri.parse(url));
} catch (Exception e) {
e.printStackTrace();
m_activity.toast(R.string.error_other_error);
}
}
return true;
case R.id.article_img_copy:
if (url != null) {
m_activity.copyToClipboard(url);
}
return true;
case R.id.article_img_share:
if (url != null) {
m_activity.shareText(url);
}
return true;
case R.id.article_img_view_caption:
if (url != null) {
m_activity.displayImageCaption(url, m_activity.m_content);
}
return true;
default:
Log.d(TAG, "onImageMenuItemSelected, unhandled id=" + item.getItemId());
return false;
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
m_activity = (ArticleImagesPagerActivity) activity;
}
@Override
public void onSaveInstanceState (Bundle out) {
super.onSaveInstanceState(out);

View File

@ -24,6 +24,7 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@ -33,46 +34,80 @@ import me.relex.circleindicator.CircleIndicator;
public class ArticleImagesPagerActivity extends CommonActivity {
private final String TAG = this.getClass().getSimpleName();
private ArrayList<String> m_urls;
private ArrayList<String> m_checkedUrls;
private ArrayList<GalleryEntry> m_items;
//private ArrayList<GalleryEntry> m_checkedItems;
private String m_title;
private ArticleImagesPagerAdapter m_adapter;
public String m_content;
private ProgressBar m_progress;
private ViewPager m_pager;
private class ArticleImagesPagerAdapter extends FragmentStatePagerAdapter {
private List<String> m_urls;
private enum GalleryEntryType { TYPE_IMAGE, TYPE_VIDEO };
public ArticleImagesPagerAdapter(FragmentManager fm, List<String> urls) {
private class GalleryEntry implements Serializable {
String url;
GalleryEntryType type;
String coverUrl;
}
private class ArticleImagesPagerAdapter extends FragmentStatePagerAdapter {
private List<GalleryEntry> m_items;
public ArticleImagesPagerAdapter(FragmentManager fm, List<GalleryEntry> items) {
super(fm);
m_urls = urls;
m_items = items;
}
@Override
public int getCount() {
return m_urls.size();
return m_items.size();
}
@Override
public Fragment getItem(int position) {
ArticleImageFragment frag = new ArticleImageFragment();
Log.d(TAG, "getItem: " + position + " " + m_urls.get(position));
//Log.d(TAG, "getItem: " + position + " " + m_urls.get(position));
frag.initialize(m_urls.get(position));
GalleryEntry item = m_items.get(position);
return frag;
switch (item.type) {
case TYPE_IMAGE:
if (true) {
ArticleImageFragment frag = new ArticleImageFragment();
frag.initialize(item.url);
return frag;
}
break;
case TYPE_VIDEO:
if (true) {
ArticleVideoFragment frag = new ArticleVideoFragment();
frag.initialize(item.url, item.coverUrl);
return frag;
}
break;
}
return null;
}
}
private class ImageCheckTask extends AsyncTask<List<String>, String, Integer> {
/*private class ImageCheckTask extends AsyncTask<List<GalleryEntry>, Integer, List<GalleryEntry>> {
private GalleryEntry m_lastCheckedItem;
@Override
protected Integer doInBackground(List<String>... urls) {
protected List<GalleryEntry> doInBackground(List<GalleryEntry>... items) {
List<GalleryEntry> tmp = new ArrayList<>(items[0]);
int position = 0;
for (String url : urls[0]) {
for (GalleryEntry item : tmp) {
if (!isCancelled()) {
String url = item.url;
position++;
try {
@ -83,9 +118,11 @@ public class ArticleImagesPagerActivity extends CommonActivity {
.get();
if (bmp != null && bmp.getWidth() > 128 && bmp.getHeight() > 128) {
publishProgress(url, String.valueOf(position));
m_lastCheckedItem = item;
publishProgress(position);
} else {
publishProgress(null, String.valueOf(position));
m_lastCheckedItem = null;
publishProgress(position);
}
} catch (InterruptedException e) {
@ -101,24 +138,21 @@ public class ArticleImagesPagerActivity extends CommonActivity {
}
@Override
protected void onProgressUpdate(String... checkedUrl) {
protected void onProgressUpdate(Integer... progress) {
if (!isFinishing() && m_adapter != null) {
if (checkedUrl[0] != null) {
m_checkedUrls.add(checkedUrl[0]);
m_adapter.notifyDataSetChanged();
}
Log.d(TAG, "progr=" + progress[0]);
Log.d(TAG, "progr=" + checkedUrl[1]);
m_adapter.notifyDataSetChanged();
m_progress.setProgress(Integer.valueOf(checkedUrl[1]));
m_progress.setProgress(Integer.valueOf(progress[1]));
} else {
cancel(true);
}
}
@Override
protected void onPostExecute(Integer result) {
protected void onPostExecute(List<GalleryEntry> result) {
m_progress.setVisibility(View.GONE);
CircleIndicator indicator = (CircleIndicator) findViewById(R.id.article_images_indicator);
@ -129,7 +163,7 @@ public class ArticleImagesPagerActivity extends CommonActivity {
}
}
}
} */
@Override
public void onCreate(Bundle savedInstanceState) {
@ -160,54 +194,79 @@ public class ArticleImagesPagerActivity extends CommonActivity {
String imgSrcFirst = getIntent().getStringExtra("firstSrc");
m_urls = new ArrayList<String>();
m_items = new ArrayList<GalleryEntry>();
Document doc = Jsoup.parse(m_content);
Elements imgs = doc.select("img");
Elements elems = doc.select("img,video");
boolean firstFound = false;
for (Element img : imgs) {
String imgSrc = img.attr("src");
for (Element elem : elems) {
if (imgSrc.startsWith("//")) {
imgSrc = "https:" + imgSrc;
GalleryEntry item = new GalleryEntry();
if ("video".equals(elem.tagName().toLowerCase())) {
String cover = elem.attr("poster");
Element source = elem.select("source").first();
String src = source.attr("src");
if (src.startsWith("//")) {
src = "https:" + src;
}
if (imgSrcFirst.equals(src))
firstFound = true;
item.url = src;
item.coverUrl = cover;
item.type = GalleryEntryType.TYPE_VIDEO;
} else {
String src = elem.attr("src");
if (src.startsWith("//")) {
src = "https:" + src;
}
if (imgSrcFirst.equals(src))
firstFound = true;
item.url = src;
item.type = GalleryEntryType.TYPE_IMAGE;
}
if (imgSrcFirst.equals(imgSrc))
firstFound = true;
if (firstFound) {
m_urls.add(imgSrc);
if (firstFound && item.url != null) {
m_items.add(item);
}
}
} else {
m_urls = savedInstanceState.getStringArrayList("urls");
m_items = (ArrayList<GalleryEntry>) savedInstanceState.getSerializable("items");
m_title = savedInstanceState.getString("title");
m_content = savedInstanceState.getString("content");
}
if (m_urls.size() > 1) {
/*if (m_items.size() > 1) {
m_progress.setProgress(0);
m_progress.setMax(m_urls.size());
m_checkedUrls = new ArrayList<String>();
m_progress.setMax(m_items.size());
m_checkedItems = new ArrayList<>();
ArrayList<String> tmp = new ArrayList<String>(m_urls);
ArrayList<GalleryEntry> tmp = new ArrayList<>(m_items);
m_checkedUrls.add(tmp.get(0));
m_checkedItems.add(tmp.get(0));
tmp.remove(0);
ImageCheckTask ict = new ImageCheckTask();
ict.execute(tmp);
} else {
m_checkedUrls = new ArrayList<String>(m_urls);
m_checkedItems = new ArrayList<>(m_items);
m_progress.setVisibility(View.GONE);
}
} */
setTitle(m_title);
m_adapter = new ArticleImagesPagerAdapter(getSupportFragmentManager(), m_urls);
m_adapter = new ArticleImagesPagerAdapter(getSupportFragmentManager(), m_items);
m_pager = (ViewPager) findViewById(R.id.article_images_pager);
m_pager.setAdapter(m_adapter);
@ -215,12 +274,6 @@ public class ArticleImagesPagerActivity extends CommonActivity {
}
@SuppressLint("NewApi")
@Override
public void onResume() {
super.onResume();
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
@ -234,7 +287,7 @@ public class ArticleImagesPagerActivity extends CommonActivity {
public void onSaveInstanceState(Bundle out) {
super.onSaveInstanceState(out);
out.putStringArrayList("urls", m_urls);
out.putSerializable("items", m_items);
out.putString("title", m_title);
out.putString("content", m_content);
}

View File

@ -0,0 +1,327 @@
package org.fox.ttrss;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.PopupMenu;
import android.widget.ProgressBar;
import com.bogdwellers.pinchtozoom.ImageMatrixTouchHandler;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
import com.bumptech.glide.request.target.Target;
import java.io.IOException;
public class ArticleVideoFragment extends GalleryBaseFragment {
private final String TAG = this.getClass().getSimpleName();
String m_url;
String m_coverUrl;
MediaPlayer m_mediaPlayer;
private boolean m_userVisibleHint = false;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_article_image, container, false);
if (savedInstanceState != null) {
m_url = savedInstanceState.getString("url");
m_coverUrl = savedInstanceState.getString("coverUrl");
}
Log.d(TAG, "called for URL: " + m_url + " Cover: " + m_coverUrl);
ImageView imgView = (ImageView) view.findViewById(R.id.flavor_image);
ViewCompat.setTransitionName(imgView, "gallery:" + m_url);
//registerForContextMenu(imgView);
view.findViewById(R.id.flavor_image_overflow).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(getContext(), v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.context_article_content_img, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return onImageMenuItemSelected(item, m_url);
}
});
popup.show();
}
});
final GlideDrawableImageViewTarget glideImage = new GlideDrawableImageViewTarget(imgView);
Glide.with(this)
.load(m_coverUrl)
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.skipMemoryCache(false)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
ActivityCompat.startPostponedEnterTransition(m_activity);
initializeVideoPlayer(view);
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
ActivityCompat.startPostponedEnterTransition(m_activity);
initializeVideoPlayer(view);
return false;
}
})
.into(glideImage);
return view;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
m_userVisibleHint = isVisibleToUser;
Log.d(TAG, "setUserVisibleHint: " + isVisibleToUser);
if (getView() == null) return;
try {
if (isVisibleToUser) {
if (m_mediaPlayer != null && !m_mediaPlayer.isPlaying()) {
m_mediaPlayer.start();
}
} else {
if (m_mediaPlayer != null && m_mediaPlayer.isPlaying()) {
m_mediaPlayer.pause();
}
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
private void initializeVideoPlayer(final View view) {
Log.d(TAG, "initializeVideoPlayer: " + m_activity + " " + view);
final MediaController m_mediaController = new MediaController(m_activity);
final TextureView textureView = (TextureView) view.findViewById(R.id.flavor_video);
textureView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!m_mediaController.isShowing())
m_mediaController.show(5000);
else
m_mediaController.hide();
}
});
m_mediaController.setAnchorView(textureView);
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface s = new Surface(surface);
m_mediaPlayer = new MediaPlayer();
m_mediaController.setMediaPlayer(new MediaController.MediaPlayerControl() {
@Override
public void start() {
m_mediaPlayer.start();
}
@Override
public void pause() {
m_mediaPlayer.pause();
}
@Override
public int getDuration() {
return m_mediaPlayer.getDuration();
}
@Override
public int getCurrentPosition() {
return m_mediaPlayer.getCurrentPosition();
}
@Override
public void seekTo(int pos) {
m_mediaPlayer.seekTo(pos);
}
@Override
public boolean isPlaying() {
return m_mediaPlayer.isPlaying();
}
@Override
public int getBufferPercentage() {
return 0;
}
@Override
public boolean canPause() {
return true;
}
@Override
public boolean canSeekBackward() {
return true;
}
@Override
public boolean canSeekForward() {
return true;
}
@Override
public int getAudioSessionId() {
return 0;
}
});
m_mediaPlayer.setSurface(s);
try {
m_mediaPlayer.setDataSource(m_url);
} catch (IOException e) {
view.findViewById(R.id.flavor_image_error).setVisibility(View.VISIBLE);
e.printStackTrace();
}
m_mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
getView().findViewById(R.id.flavor_image).setVisibility(View.GONE);
getView().findViewById(R.id.flavor_image_progress).setVisibility(View.GONE);
resizeSurface(textureView);
mp.setLooping(true);
if (m_userVisibleHint) {
mp.start();
}
}
});
m_mediaPlayer.prepareAsync();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
m_mediaPlayer.release();
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
});
}
public void initialize(String url, String coverUrl) {
m_url = url;
m_coverUrl = coverUrl;
}
/*@Override
public boolean onContextItemSelected(MenuItem item) {
int position = m_pager.getCurrentItem();
String url = m_checkedUrls.get(position);
if (!onImageMenuItemSelected(item, url))
return super.onContextItemSelected(item);
else
return true;
}*/
@Override
public void onSaveInstanceState (Bundle out) {
super.onSaveInstanceState(out);
out.setClassLoader(getClass().getClassLoader());
out.putString("url", m_url);
out.putString("coverUrl", m_coverUrl);
}
protected void resizeSurface(View surfaceView) {
// get the dimensions of the video (only valid when surfaceView is set)
float videoWidth = m_mediaPlayer.getVideoWidth();
float videoHeight = m_mediaPlayer.getVideoHeight();
Rect rectangle = new Rect();
m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle);
int actionBarHeight = m_activity.isPortrait() ? m_activity.getSupportActionBar().getHeight() : 0;
Display display = m_activity.getWindowManager().getDefaultDisplay();
float containerWidth = display.getWidth();
float containerHeight = display.getHeight() - rectangle.top - actionBarHeight;
// set dimensions to surfaceView's layout params (maintaining aspect ratio)
android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
lp.width = (int) containerWidth;
lp.height = (int) ((videoHeight / videoWidth) * containerWidth);
if(lp.height > containerHeight) {
lp.width = (int) ((videoWidth / videoHeight) * containerHeight);
lp.height = (int) containerHeight;
}
surfaceView.setLayoutParams(lp);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
resizeSurface(getView().findViewById(R.id.flavor_video));
}
}

View File

@ -0,0 +1,64 @@
package org.fox.ttrss;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.MenuItem;
public class GalleryBaseFragment extends Fragment {
private final String TAG = this.getClass().getSimpleName();
protected ArticleImagesPagerActivity m_activity;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public boolean onImageMenuItemSelected(MenuItem item, String url) {
switch (item.getItemId()) {
case R.id.article_img_open:
if (url != null) {
try {
m_activity.openUri(Uri.parse(url));
} catch (Exception e) {
e.printStackTrace();
m_activity.toast(R.string.error_other_error);
}
}
return true;
case R.id.article_img_copy:
if (url != null) {
m_activity.copyToClipboard(url);
}
return true;
case R.id.article_img_share:
if (url != null) {
m_activity.shareText(url);
}
return true;
case R.id.article_img_view_caption:
if (url != null) {
m_activity.displayImageCaption(url, m_activity.m_content);
}
return true;
default:
Log.d(TAG, "onImageMenuItemSelected, unhandled id=" + item.getItemId());
return false;
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
m_activity = (ArticleImagesPagerActivity) activity;
}
}

View File

@ -1206,11 +1206,17 @@ public class HeadlinesFragment extends Fragment {
holder.flavorImageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
releaseSurface();
openGalleryForType(article, holder, holder.flavorImageView);
return true;
}
});
openGalleryForType(article, holder, null);
holder.flavorVideoView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
releaseSurface();
openGalleryForType(article, holder, holder.flavorImageView);
return true;
}
});
@ -1218,9 +1224,7 @@ public class HeadlinesFragment extends Fragment {
holder.flavorImageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
releaseSurface();
m_mediaPlayer = new MediaPlayer();
try {
@ -1240,10 +1244,14 @@ public class HeadlinesFragment extends Fragment {
holder.flavorVideoView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (m_mediaPlayer.isPlaying())
m_mediaPlayer.pause();
else
m_mediaPlayer.start();
try {
if (m_mediaPlayer.isPlaying())
m_mediaPlayer.pause();
else
m_mediaPlayer.start();
} catch (IllegalStateException e) {
releaseSurface();
}
}
});
@ -1310,7 +1318,7 @@ public class HeadlinesFragment extends Fragment {
holder.flavorImageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
openGalleryForType(article, holder, null);
openGalleryForType(article, holder, holder.flavorImageView);
}
});
}
@ -1474,6 +1482,8 @@ public class HeadlinesFragment extends Fragment {
}
private void openGalleryForType(Article article, ArticleViewHolder holder, View transitionView) {
//Log.d(TAG, "openGalleryForType: " + article + " " + holder + " " + transitionView);
if ("iframe".equals(article.flavorImage.tagName().toLowerCase())) {
if (m_youtubeInstalled) {
@ -1489,35 +1499,18 @@ public class HeadlinesFragment extends Fragment {
m_activity.openUri(Uri.parse(article.flavorStreamUri));
}
} else if ("video".equals(article.flavorImage.tagName().toLowerCase())) {
Intent intent = new Intent(m_activity, VideoPlayerActivity.class);
intent.putExtra("streamUri", article.flavorStreamUri);
intent.putExtra("title", article.title);
intent.putExtra("coverSrc", article.flavorImageUri);
//startActivity(intent);
//m_activity.overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
ActivityOptionsCompat options =
ActivityOptionsCompat.makeSceneTransitionAnimation(m_activity,
transitionView != null ? transitionView : holder.flavorImageView,
"gallery:" + article.flavorImageUri);
ActivityCompat.startActivity(m_activity, intent, options.toBundle());
} else {
Intent intent = new Intent(m_activity, ArticleImagesPagerActivity.class);
intent.putExtra("firstSrc", article.flavorImageUri);
intent.putExtra("firstSrc", article.flavorStreamUri != null ? article.flavorStreamUri : article.flavorImageUri);
intent.putExtra("title", article.title);
intent.putExtra("content", article.content);
ActivityOptionsCompat options =
ActivityOptionsCompat.makeSceneTransitionAnimation(m_activity,
transitionView != null ? transitionView : holder.flavorImageView,
"gallery:" + article.flavorImageUri);
"gallery:" + (article.flavorStreamUri != null ? article.flavorStreamUri : article.flavorImageUri));
ActivityCompat.startActivity(m_activity, intent, options.toBundle());
}

View File

@ -1,368 +0,0 @@
package org.fox.ttrss;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Display;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.PopupMenu;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import java.io.IOException;
public class VideoPlayerActivity extends CommonActivity {
private final String TAG = this.getClass().getSimpleName();
private String m_streamUri;
private MediaPlayer mediaPlayer;
private SurfaceView surfaceView;
private String m_coverUri;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.DarkTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_player);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().hide();
surfaceView = (SurfaceView) findViewById(R.id.video_player);
registerForContextMenu(surfaceView);
setTitle(getIntent().getStringExtra("title"));
if (savedInstanceState == null) {
m_streamUri = getIntent().getStringExtra("streamUri");
m_coverUri = getIntent().getStringExtra("coverSrc");
} else {
m_streamUri = savedInstanceState.getString("streamUri");
m_coverUri = savedInstanceState.getString("coverSrc");
}
ImageView coverView = (ImageView)findViewById(R.id.video_player_cover);
if (m_coverUri != null) {
ActivityCompat.postponeEnterTransition(VideoPlayerActivity.this);
ViewCompat.setTransitionName(coverView, "gallery:" + m_coverUri);
Glide.with(this)
.load(m_coverUri)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.skipMemoryCache(false)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
ActivityCompat.startPostponedEnterTransition(VideoPlayerActivity.this);
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
ActivityCompat.startPostponedEnterTransition(VideoPlayerActivity.this);
return false;
}
})
.into(coverView);
/*ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(m_coverUri, coverView, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String s, View view) {
ActivityCompat.startPostponedEnterTransition(VideoPlayerActivity.this);
}
@Override
public void onLoadingFailed(String s, View view, FailReason failReason) {
ActivityCompat.startPostponedEnterTransition(VideoPlayerActivity.this);
}
@Override
public void onLoadingComplete(String s, View view, Bitmap bitmap) {
ActivityCompat.startPostponedEnterTransition(VideoPlayerActivity.this);
}
@Override
public void onLoadingCancelled(String s, View view) {
ActivityCompat.startPostponedEnterTransition(VideoPlayerActivity.this);
}
});*/
} else {
coverView.setVisibility(View.GONE);
}
findViewById(R.id.video_player_overflow).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(VideoPlayerActivity.this, v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.activity_video_player, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return onVideoMenuItemSelected(item);
}
});
popup.show();
}
});
final MediaController mediaController = new MediaController(this);
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mediaController.isShowing())
mediaController.show(5000);
else
mediaController.hide();
}
});
mediaPlayer = new MediaPlayer();
mediaController.setMediaPlayer(new MediaController.MediaPlayerControl() {
@Override
public void start() {
mediaPlayer.start();
}
@Override
public void pause() {
mediaPlayer.pause();
}
@Override
public int getDuration() {
return mediaPlayer.getDuration();
}
@Override
public int getCurrentPosition() {
return mediaPlayer.getCurrentPosition();
}
@Override
public void seekTo(int pos) {
mediaPlayer.seekTo(pos);
}
@Override
public boolean isPlaying() {
return mediaPlayer.isPlaying();
}
@Override
public int getBufferPercentage() {
return 0;
}
@Override
public boolean canPause() {
return true;
}
@Override
public boolean canSeekBackward() {
return true;
}
@Override
public boolean canSeekForward() {
return true;
}
@Override
public int getAudioSessionId() {
return 0;
}
});
SurfaceHolder sh = surfaceView.getHolder();
try {
mediaPlayer.setDataSource(this, Uri.parse(m_streamUri));
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, surfaceView.getWidth() + " " + surfaceView.getHeight());
final FrameLayout.LayoutParams svLayoutParams = new FrameLayout.LayoutParams(surfaceView.getWidth(), surfaceView.getHeight());
sh.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
mediaPlayer.setDisplay(holder);
try {
mediaPlayer.prepareAsync();
} catch (IllegalStateException e) {
e.printStackTrace();
}
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
View loadingBar = findViewById(R.id.video_loading);
if (loadingBar != null)
loadingBar.setVisibility(View.GONE);
View coverView = findViewById(R.id.video_player_cover);
if (coverView != null)
coverView.setVisibility(View.GONE);
resizeSurface();
mp.setLooping(true);
mp.start();
}
}
);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mediaPlayer.release();
}
});
mediaController.setAnchorView(surfaceView);
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
resizeSurface();
}
@Override
public void onSaveInstanceState(Bundle out) {
super.onSaveInstanceState(out);
out.putString("streamUri", m_streamUri);
out.putString("coverSrc", m_coverUri);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
getMenuInflater().inflate(R.menu.activity_video_player, menu);
super.onCreateContextMenu(menu, v, menuInfo);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
if (!onVideoMenuItemSelected(item))
return super.onContextItemSelected(item);
else
return true;
}
public boolean onVideoMenuItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case R.id.article_vid_open:
if (m_streamUri != null) {
try {
openUri(Uri.parse(m_streamUri));
} catch (Exception e) {
e.printStackTrace();
toast(R.string.error_other_error);
}
}
return true;
case R.id.article_vid_copy:
if (m_streamUri != null) {
copyToClipboard(m_streamUri);
}
return true;
case R.id.article_vid_share:
if (m_streamUri != null) {
shareText(m_streamUri);
}
return true;
default:
Log.d(TAG, "onVideoMenuItemSelected, unhandled id=" + item.getItemId());
return false;
}
}
protected void resizeSurface() {
// get the dimensions of the video (only valid when surfaceView is set)
float videoWidth = mediaPlayer.getVideoWidth();
float videoHeight = mediaPlayer.getVideoHeight();
Rect rectangle = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle);
int actionBarHeight = isPortrait() ? getSupportActionBar().getHeight() : 0;
Display display = getWindowManager().getDefaultDisplay();
float containerWidth = display.getWidth();
float containerHeight = display.getHeight() - rectangle.top - actionBarHeight;
// set dimensions to surfaceView's layout params (maintaining aspect ratio)
android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
lp.width = (int) containerWidth;
lp.height = (int) ((videoHeight / videoWidth) * containerWidth);
if(lp.height > containerHeight) {
lp.width = (int) ((videoWidth / videoHeight) * containerHeight);
lp.height = (int) containerHeight;
}
surfaceView.setLayoutParams(lp);
}
/*@Override
public void onPause() {
super.onPause();
if (isFinishing()) {
}
}*/
}

View File

@ -73,7 +73,7 @@ public class YoutubePlayerActivity extends CommonActivity implements YouTubePlay
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_video_player, menu);
getMenuInflater().inflate(R.menu.activity_youtube_player, menu);
return true;
}
@ -82,7 +82,7 @@ public class YoutubePlayerActivity extends CommonActivity implements YouTubePlay
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
getMenuInflater().inflate(R.menu.activity_video_player, menu);
getMenuInflater().inflate(R.menu.activity_youtube_player, menu);
super.onCreateContextMenu(menu, v, menuInfo);
}

View File

@ -72,10 +72,10 @@ public class Article implements Parcelable {
if ("iframe".equals(e.tagName().toLowerCase())) {
flavorImage = e;
break;
} else if ("video".equals(e.tagName().toLowerCase())) {
} /*else if ("video".equals(e.tagName().toLowerCase())) {
flavorImage = e;
break;
}
}*/
}
if (flavorImage == null) {

View File

@ -1,46 +0,0 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="@android:color/black"
tools:context="org.fox.ttrss.VideoPlayerActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar">
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:id="@+id/video_player" />
<ImageView
android:id="@+id/video_player_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/video_loading"
android:layout_gravity="center"
android:indeterminate="true" />
<ImageView
android:id="@+id/video_player_overflow"
android:clickable="true"
android:layout_width="wrap_content"
android:layout_height="26dp"
android:layout_weight="0"
android:background="@drawable/ripple"
android:src="@drawable/ic_dots_vertical"
android:layout_gravity="top|right"
android:layout_marginRight="8dp"
android:layout_marginTop="@dimen/activity_vertical_margin" />
</FrameLayout>
<include layout="@layout/toolbar" android:id="@+id/toolbar" />
</RelativeLayout>

View File

@ -2,8 +2,7 @@
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="@android:color/black"
tools:context="org.fox.ttrss.VideoPlayerActivity">
android:background="@android:color/black">
<FrameLayout
android:layout_width="match_parent"

View File

@ -19,6 +19,7 @@
android:id="@+id/article_images_progress"
android:progress="0"
android:indeterminate="false"
android:visibility="gone"
android:layout_above="@+id/article_images_indicator"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"

View File

@ -12,11 +12,13 @@
android:text="@string/error_loading_image"
android:id="@+id/flavor_image_error" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<TextureView
android:id="@+id/flavor_video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:layout_gravity="center"
android:id="@+id/flavor_image_progress" />
android:scaleType="fitCenter" />
<ImageView
android:id="@+id/flavor_image"
@ -26,6 +28,12 @@
android:layout_gravity="center"
android:scaleType="fitCenter" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="@+id/flavor_image_progress" />
<ImageView
android:id="@+id/flavor_image_overflow"
android:clickable="true"

View File

@ -1,20 +1,19 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.fox.ttrss.VideoPlayerActivity">
<item
android:id="@+id/article_vid_open"
app:showAsAction=""
android:title="@string/open_with"/>
<item
android:id="@+id/article_vid_copy"
app:showAsAction=""
android:icon="@drawable/ic_content_copy"
android:title="@string/article_link_copy"/>
<item
android:id="@+id/article_vid_share"
android:icon="@drawable/ic_share"
app:showAsAction="ifRoom"
android:title="@string/video_player_share"/>
</menu>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/article_vid_open"
app:showAsAction=""
android:title="@string/open_with"/>
<item
android:id="@+id/article_vid_copy"
app:showAsAction=""
android:icon="@drawable/ic_content_copy"
android:title="@string/article_link_copy"/>
<item
android:id="@+id/article_vid_share"
android:icon="@drawable/ic_share"
app:showAsAction="ifRoom"
android:title="@string/video_player_share"/>
</menu>