Update podcast feature

This commit is contained in:
David Development 2014-09-02 11:11:39 +02:00
parent 68c6255285
commit e4a93c512c
14 changed files with 234 additions and 21 deletions

3
.gitmodules vendored
View file

@ -10,3 +10,6 @@
[submodule "ShowcaseView"]
path = ShowcaseView
url = https://github.com/amlcurran/ShowcaseView.git
[submodule "android-HoloCircularProgressBar"]
path = android-HoloCircularProgressBar
url = https://github.com/passsy/android-HoloCircularProgressBar.git

View file

@ -93,6 +93,7 @@
<orderEntry type="library" exported="" name="butterknife-5.1.2" level="project" />
<orderEntry type="module" module-name="library" exported="" />
<orderEntry type="module" module-name="ownCloud-Account-Importer" exported="" />
<orderEntry type="module" module-name="android-HoloCircularProgressBar-library" exported="" />
<orderEntry type="module" module-name="MessageBar" exported="" />
<orderEntry type="module" module-name="ChangeLogLibrary" exported="" />
</component>

View file

@ -54,6 +54,7 @@ dependencies {
compile project(':MessageBar')
compile project(':ownCloud-Account-Importer')
compile project(':ShowcaseView:library')
compile project(':android-HoloCircularProgressBar:library')
compile 'com.android.support:support-v4:20.+'
compile 'com.android.support:appcompat-v7:20.+'
compile 'com.jakewharton:butterknife:5.1.+'

View file

@ -47,6 +47,7 @@ import java.util.ArrayList;
import butterknife.ButterKnife;
import butterknife.InjectView;
import de.greenrobot.dao.query.LazyList;
import de.greenrobot.event.EventBus;
import de.luhmer.owncloudnewsreader.ListView.BlockingListView;
import de.luhmer.owncloudnewsreader.ListView.SubscriptionExpandableListAdapter;
import de.luhmer.owncloudnewsreader.adapter.NewsListArrayAdapter;
@ -55,6 +56,7 @@ import de.luhmer.owncloudnewsreader.cursor.NewsListCursorAdapter;
import de.luhmer.owncloudnewsreader.database.DatabaseConnection.SORT_DIRECTION;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm;
import de.luhmer.owncloudnewsreader.database.model.RssItem;
import de.luhmer.owncloudnewsreader.services.PodcastDownloadService;
/**
* A fragment representing a single NewsReader detail screen. This fragment is
@ -169,6 +171,21 @@ public class NewsReaderDetailFragment extends ListFragment implements IOnStayUnr
}
}
@Override
public void onResume() {
EventBus.getDefault().register(this);
//Reload data. Use case: download was finished while app was not in foreground
notifyDataSetChangedOnAdapter();
super.onResume();
}
@Override
public void onPause() {
EventBus.getDefault().unregister(this);
super.onPause();
}
public void UpdateMenuItemsState()
{
@ -254,6 +271,22 @@ public class NewsReaderDetailFragment extends ListFragment implements IOnStayUnr
}
public void onEventMainThread(PodcastDownloadService.DownloadProgressUpdate downloadProgress) {
NewsListArrayAdapter nca = (NewsListArrayAdapter) getListAdapter();
if(nca != null) {
nca.downloadProgressList.put((int) downloadProgress.podcast.itemId, downloadProgress.podcast.downloadProgress);
RssItem currentRssItem;
for (int i = getListView().getFirstVisiblePosition(); i < getListView().getLastVisiblePosition(); i++) {
currentRssItem = (RssItem) getListAdapter().getItem(i);
if (currentRssItem.getId().equals(downloadProgress.podcast.itemId)) {
int position = i - getListView().getFirstVisiblePosition();
nca.setDownloadPodcastProgressbar(getListView().getChildAt(position), currentRssItem);
break;
}
}
}
}
public void notifyDataSetChangedOnAdapter()
{

View file

@ -2,8 +2,11 @@ package de.luhmer.owncloudnewsreader;
import android.animation.Animator;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Resources;
@ -23,7 +26,6 @@ import com.nineoldandroids.view.ViewHelper;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.util.Arrays;
import butterknife.ButterKnife;
import butterknife.InjectView;
@ -34,6 +36,8 @@ import de.luhmer.owncloudnewsreader.database.model.RssItem;
import de.luhmer.owncloudnewsreader.events.podcast.RegisterVideoOutput;
import de.luhmer.owncloudnewsreader.events.podcast.UpdatePodcastStatusEvent;
import de.luhmer.owncloudnewsreader.events.podcast.VideoDoubleClicked;
import de.luhmer.owncloudnewsreader.helper.FileUtils;
import de.luhmer.owncloudnewsreader.helper.ImageHandler;
import de.luhmer.owncloudnewsreader.helper.SizeAnimator;
import de.luhmer.owncloudnewsreader.interfaces.IPlayPodcastClicked;
import de.luhmer.owncloudnewsreader.model.PodcastItem;
@ -90,6 +94,10 @@ public class PodcastFragmentActivity extends ActionBarActivity implements IPlayP
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, PodcastPlaybackService.class);
if(!isMyServiceRunning(PodcastPlaybackService.class)) {
startService(intent);
}
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@ -136,6 +144,16 @@ public class PodcastFragmentActivity extends ActionBarActivity implements IPlayP
super.onPause();
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@ -147,9 +165,7 @@ public class PodcastFragmentActivity extends ActionBarActivity implements IPlayP
PodcastPlaybackService.LocalBinder binder = (PodcastPlaybackService.LocalBinder) service;
mPodcastPlaybackService = binder.getService();
if(mPodcastPlaybackService.getCurrentlyPlayingPodcast() != null) {
Picasso.with(PodcastFragmentActivity.this).load(mPodcastPlaybackService.getCurrentlyPlayingPodcast().favIcon).into(mPodcastFragment.imgFavIcon);
}
loadPodcastFavIcon();
mBound = true;
}
@ -161,6 +177,23 @@ public class PodcastFragmentActivity extends ActionBarActivity implements IPlayP
};
public void loadPodcastFavIcon() {
if(mPodcastPlaybackService.getCurrentlyPlayingPodcast() != null && mPodcastPlaybackService.getCurrentlyPlayingPodcast().favIcon != null) {
String favIconUrl = mPodcastPlaybackService.getCurrentlyPlayingPodcast().favIcon;
File cacheFile = ImageHandler.getFullPathOfCacheFileSafe(favIconUrl, FileUtils.getPathFavIcons(this));
if(cacheFile != null && cacheFile.exists()) {
Picasso.with(PodcastFragmentActivity.this)
.load(cacheFile)
.placeholder(R.drawable.default_feed_icon_light)
.into(mPodcastFragment.imgFavIcon);
} else {
Picasso.with(PodcastFragmentActivity.this)
.load(favIconUrl)
.placeholder(R.drawable.default_feed_icon_light)
.into(mPodcastFragment.imgFavIcon);
}
}
}
public PodcastSlidingUpPanelLayout getSlidingLayout() {
return sliding_layout;
@ -192,26 +225,30 @@ public class PodcastFragmentActivity extends ActionBarActivity implements IPlayP
boolean currentlyPlaying = false;
boolean surfaceInitalized = false;
boolean surfaceInitialized = false;
boolean isVideoViewVisible = true;
public void onEventMainThread(UpdatePodcastStatusEvent podcast) {
if(podcast.isFileLoaded() || podcast.isPreparingFile() && !currentlyPlaying) {
if((podcast.isFileLoaded() || podcast.isPreparingFile()) && !currentlyPlaying) {
//Expand view
sliding_layout.setPanelHeight((int)dipToPx(68));
currentlyPlaying = true;
Log.v(TAG, "expanding podcast view!");
} else if(!(podcast.isPreparingFile() || podcast.isFileLoaded()) && currentlyPlaying) {
//Hide view
sliding_layout.setPanelHeight(0);
currentlyPlaying = false;
Log.v(TAG, "collapsing podcast view!");
}
if (podcast.isVideoFile()) {
if((!isVideoViewVisible || !surfaceInitalized) && rlVideoPodcastSurfaceWrapper.isPositionReady()) {
surfaceInitalized = true;
if((!isVideoViewVisible || !surfaceInitialized) && rlVideoPodcastSurfaceWrapper.isPositionReady()) {
surfaceInitialized = true;
isVideoViewVisible = true;
rlVideoPodcastSurfaceWrapper.setVisibility(View.VISIBLE);
@ -571,22 +608,44 @@ public class PodcastFragmentActivity extends ActionBarActivity implements IPlayP
}
@Override
public void openPodcast(RssItem rssItem) {
PodcastItem podcastItem = DatabaseConnectionOrm.ParsePodcastItemFromRssItem(this, rssItem);
public void openPodcast(final RssItem rssItem) {
final PodcastItem podcastItem = DatabaseConnectionOrm.ParsePodcastItemFromRssItem(this, rssItem);
if(podcastItem.mimeType.equals("youtube") && !podcastItem.offlineCached)
Toast.makeText(this, "Cannot stream from youtube. Please download the video first.", Toast.LENGTH_SHORT).show();
else {
File file = new File(PodcastDownloadService.getUrlToPodcastFile(this, podcastItem.link, false));
if(file.exists())
if(file.exists()) {
podcastItem.link = file.getAbsolutePath();
else if(!podcastItem.offlineCached)
Toast.makeText(this, "Starting podcast.. please wait", Toast.LENGTH_SHORT).show(); //Only show if we need to stream the file
//EventBus.getDefault().post(new OpenPodcastEvent(podcastItem.link, podcastItem.title, isVideo));
mPodcastPlaybackService.openFile(podcastItem);
mPodcastPlaybackService.openFile(podcastItem);
loadPodcastFavIcon();// Picasso.with(this).load(rssItem.getFeed().getFaviconUrl()).into(mPodcastFragment.imgFavIcon);
} else if(!podcastItem.offlineCached) {
Picasso.with(this).load(rssItem.getFeed().getFaviconUrl()).into(mPodcastFragment.imgFavIcon);
new AlertDialog.Builder(this)
.setPositiveButton("Stream", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
mPodcastPlaybackService.openFile(podcastItem);
//Picasso.with(PodcastFragmentActivity.this).load(rssItem.getFeed().getFaviconUrl()).into(mPodcastFragment.imgFavIcon);
loadPodcastFavIcon();
}
})
.setNegativeButton("Abort", null)
.setNeutralButton("Download", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
PodcastDownloadService.startPodcastDownload(PodcastFragmentActivity.this, podcastItem);
Toast.makeText(PodcastFragmentActivity.this, "Starting download of podcast. Please wait..", Toast.LENGTH_SHORT).show();
}
})
.setTitle("Podcast")
.setMessage("Choose if you want to download or stream the selected podcast")
.show();
}
}
}
}

View file

@ -12,6 +12,7 @@ import android.text.SpannableString;
import android.text.format.DateUtils;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -28,10 +29,15 @@ import android.widget.TextView;
import com.devspark.robototextview.widget.RobotoCheckBox;
import com.devspark.robototextview.widget.RobotoTextView;
import java.io.File;
import java.util.HashMap;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.Optional;
import de.greenrobot.dao.query.LazyList;
import de.greenrobot.event.EventBus;
import de.luhmer.owncloudnewsreader.ListView.PodcastArrayAdapter;
import de.luhmer.owncloudnewsreader.NewsDetailFragment;
import de.luhmer.owncloudnewsreader.NewsReaderListActivity;
import de.luhmer.owncloudnewsreader.R;
@ -45,8 +51,11 @@ import de.luhmer.owncloudnewsreader.helper.FontHelper;
import de.luhmer.owncloudnewsreader.helper.PostDelayHandler;
import de.luhmer.owncloudnewsreader.helper.ThemeChooser;
import de.luhmer.owncloudnewsreader.interfaces.IPlayPodcastClicked;
import de.luhmer.owncloudnewsreader.model.PodcastItem;
import de.luhmer.owncloudnewsreader.reader.IReader;
import de.luhmer.owncloudnewsreader.reader.owncloud.OwnCloud_Reader;
import de.luhmer.owncloudnewsreader.services.PodcastDownloadService;
import de.passsy.holocircularprogressbar.HoloCircularProgressBar;
/**
* Created by David on 18.07.2014.
@ -55,6 +64,8 @@ public class NewsListArrayAdapter extends GreenDaoListAdapter<RssItem> {
private static final String TAG = "NewsListArrayAdapter";
public static SparseArray<Integer> downloadProgressList = new SparseArray<Integer>();
DatabaseConnectionOrm dbConn;
IReader _Reader;
final int LengthBody = 400;
@ -65,6 +76,8 @@ public class NewsListArrayAdapter extends GreenDaoListAdapter<RssItem> {
FragmentActivity mActivity;
IPlayPodcastClicked playPodcastClicked;
public NewsListArrayAdapter(FragmentActivity activity, LazyList<RssItem> lazyList, IOnStayUnread onStayUnread, IPlayPodcastClicked playPodcastClicked) {
super(activity, lazyList);
@ -197,8 +210,41 @@ public class NewsListArrayAdapter extends GreenDaoListAdapter<RssItem> {
}
}
/*
public void onEventMainThread(PodcastDownloadService.DownloadProgressUpdate downloadProgress) {
downloadProgressList.put((int) downloadProgress.podcast.itemId, downloadProgress.podcast.downloadProgress);
//get invalidateViews();
//notifyDataSetChanged();
/*
for(int i = 0; i < getCount(); i++) {
if(getItem(i).getId().equals(downloadProgress.podcast.itemId)) {
if(getItem(i).downloadProgress != downloadProgress.podcast.downloadProgress) { //If Progress changed
PodcastItem pItem = podcastArrayAdapter.getItem(i);
if (downloadProgress.podcast.downloadProgress == 100) {
pItem.downloadProgress = PodcastItem.DOWNLOAD_COMPLETED;
File file = new File(PodcastDownloadService.getUrlToPodcastFile(getActivity(), pItem.link, false));
pItem.offlineCached = file.exists();
} else
pItem.downloadProgress = downloadProgress.podcast.downloadProgress;
podcastTitleGrid.invalidateViews();
}
return;
notifyDataSetChanged();
}
}
}
*/
static class SimpleLayout {
@InjectView(R.id.divider) View viewDivider;
@InjectView(R.id.summary) TextView textViewSummary;
@ -239,8 +285,12 @@ public class NewsListArrayAdapter extends GreenDaoListAdapter<RssItem> {
simpleLayout.viewDivider.setBackgroundColor(mActivity.getResources().getColor(R.color.divider_row_color_light_theme));
}
//Podcast stuff
if(DatabaseConnectionOrm.ALLOWED_PODCASTS_TYPES.contains(rssItem.getEnclosureMime())) {
simpleLayout.btnPlayPodcast.setVisibility(View.VISIBLE);
//Enable podcast buttons in view
simpleLayout.flPlayPodcastWrapper.setVisibility(View.VISIBLE);
if(ThemeChooser.isDarkTheme(mActivity)) {
simpleLayout.btnPlayPodcast.setBackgroundResource(android.R.drawable.ic_media_play);
}
@ -254,11 +304,35 @@ public class NewsListArrayAdapter extends GreenDaoListAdapter<RssItem> {
}
});
setDownloadPodcastProgressbar(view, rssItem);
} else {
simpleLayout.btnPlayPodcast.setVisibility(View.GONE);
simpleLayout.flPlayPodcastWrapper.setVisibility(View.GONE);
}
}
public void setDownloadPodcastProgressbar(View view, RssItem rssItem) {
HoloCircularProgressBar pbPodcastDownloadProgress = (HoloCircularProgressBar) view.findViewById(R.id.podcastDownloadProgress);
if(!ThemeChooser.isDarkTheme(mActivity)) {
pbPodcastDownloadProgress.setProgressBackgroundColor(context.getResources().getColor(R.color.slide_up_panel_header_background_color));
}
if(PodcastAlreadyCached(context, rssItem.getEnclosureLink()))
pbPodcastDownloadProgress.setProgress(1);
else {
if(downloadProgressList.get(rssItem.getId().intValue()) != null) {
float progressInPercent = downloadProgressList.get(rssItem.getId().intValue()) / 100f;
pbPodcastDownloadProgress.setProgress(progressInPercent);
} else {
pbPodcastDownloadProgress.setProgress(0);
}
}
}
public static boolean PodcastAlreadyCached(Context context, String podcastUrl) {
File file = new File(PodcastDownloadService.getUrlToPodcastFile(context, podcastUrl, false));
return file.exists();
}
public void setExtendedLayout(View view, RssItem rssItem)

View file

@ -54,7 +54,6 @@ public class PodcastDownloadService extends IntentService {
*
* @see IntentService
*/
// TODO: Customize helper method
public static void startPodcastDownload(Context context, PodcastItem podcastItem/*, ResultReceiver receiver*/) {
Intent intent = new Intent(context, PodcastDownloadService.class);
intent.setAction(ACTION_DOWNLOAD);

View file

@ -56,6 +56,8 @@ public class PodcastPlaybackService extends Service {
@Override
public void onCreate() {
Log.v(TAG, "onCreate PodcastPlaybackService");
podcastNotification = new PodcastNotification(this);
mediaTitle = getString(R.string.no_podcast_selected);

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="90"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360">
<shape
android:innerRadiusRatio="6"
android:shape="ring"
android:thicknessRatio="3.0">
<gradient
android:centerColor="#ffd6aa98"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:angle="0"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>

View file

@ -31,7 +31,8 @@
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/podcast_horizontal_margin"
android:layout_marginRight="@dimen/podcast_horizontal_margin" />
android:layout_marginRight="@dimen/podcast_horizontal_margin"
android:src="@drawable/default_feed_icon_light"/>
<LinearLayout
android:id="@+id/ll_podcast_header"

View file

@ -2,6 +2,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="72dp"
android:orientation="horizontal" >
@ -106,7 +107,22 @@
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:layout_marginLeft="2dp"
android:background="@drawable/av_play"/>
<de.passsy.holocircularprogressbar.HoloCircularProgressBar
android:id="@+id/podcastDownloadProgress"
android:layout_gravity="center"
android:layout_width="50dp"
android:layout_height="50dp"
app:stroke_width="2dp"
app:progress="0.4"
app:progress_color="@android:color/holo_blue_dark"
app:progress_background_color="#cccccc"
app:marker_visible="false"
app:thumb_visible="false"/>
</FrameLayout>
<com.devspark.robototextview.widget.RobotoCheckBox

@ -1 +1 @@
Subproject commit 392e7c345a4bfd2b67058a66759f7889c2d9d601
Subproject commit 3f35ebba39cc341459113c57e59e8abc8bb55995

@ -0,0 +1 @@
Subproject commit 98a1f817bc42c5be16221656bdac7b148581c69c

View file

@ -1,3 +1,4 @@
include ':News-Android-App', ':MessageBar', ':ownCloud-Account-Importer'
include ':Changeloglib:ChangeLogLibrary'
include ':ShowcaseView:library'
include ':android-HoloCircularProgressBar:library'