diff --git a/app/build.gradle b/app/build.gradle index 240fd6f9f..73d751fb4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,7 +19,6 @@ dependencies { compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") { exclude group: "org.json", module: "json" } - compile "commons-io:commons-io:$commonsioVersion" compile "org.jsoup:jsoup:$jsoupVersion" compile "com.github.bumptech.glide:glide:$glideVersion" @@ -49,14 +48,14 @@ dependencies { def getMyVersionName() { def parsedManifestXml = (new XmlSlurper()) .parse("${projectDir}/src/main/AndroidManifest.xml") - .declareNamespace(android:"http://schemas.android.com/apk/res/android") + .declareNamespace(android: "http://schemas.android.com/apk/res/android") return parsedManifestXml."@android:versionName" } def getMyVersionCode() { def parsedManifestXml = (new XmlSlurper()) .parse("${projectDir}/src/main/AndroidManifest.xml") - .declareNamespace(android:"http://schemas.android.com/apk/res/android") + .declareNamespace(android: "http://schemas.android.com/apk/res/android") return parsedManifestXml."@android:versionCode".toInteger() } @@ -150,7 +149,7 @@ task filterAbout { from "src/main/templates/about.html" into "src/main/assets" filter(ReplaceTokens, tokens: [versionname: android.defaultConfig.versionName, - commit: "git rev-parse --short HEAD".execute().text]) + commit : "git rev-parse --short HEAD".execute().text]) } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java index 6c0f0ab4d..3b5168f51 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -43,13 +43,17 @@ import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; +import de.danoeh.antennapod.core.service.playback.PlayerStatus; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.FeedItemUtil; import de.danoeh.antennapod.core.util.StorageUtils; +import de.danoeh.antennapod.core.util.playback.Playable; +import de.danoeh.antennapod.core.util.playback.PlaybackController; import de.danoeh.antennapod.dialog.RatingDialog; import de.danoeh.antennapod.fragment.AddFeedFragment; import de.danoeh.antennapod.fragment.DownloadsFragment; @@ -58,6 +62,7 @@ import de.danoeh.antennapod.fragment.ExternalPlayerFragment; import de.danoeh.antennapod.fragment.ItemlistFragment; import de.danoeh.antennapod.fragment.PlaybackHistoryFragment; import de.danoeh.antennapod.fragment.QueueFragment; +import de.danoeh.antennapod.fragment.SubscriptionFragment; import de.danoeh.antennapod.menuhandler.NavDrawerActivity; import de.danoeh.antennapod.preferences.PreferenceController; import de.greenrobot.event.EventBus; @@ -94,6 +99,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity EpisodesFragment.TAG, DownloadsFragment.TAG, PlaybackHistoryFragment.TAG, + SubscriptionFragment.TAG, AddFeedFragment.TAG }; @@ -269,7 +275,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity } public void loadFragment(int index, Bundle args) { - Log.d(TAG, "loadFragment(index: " + index + ", args: " + args +")"); + Log.d(TAG, "loadFragment(index: " + index + ", args: " + args + ")"); if (index < navAdapter.getSubscriptionOffset()) { String tag = navAdapter.getTags().get(index); loadFragment(tag, args); @@ -298,6 +304,11 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity case AddFeedFragment.TAG: fragment = new AddFeedFragment(); break; + case SubscriptionFragment.TAG: + SubscriptionFragment subscriptionFragment = new SubscriptionFragment(); + subscriptionFragment.setItemAccess(itemAccess); + fragment = subscriptionFragment; + break; default: // default to the queue tag = QueueFragment.TAG; @@ -646,6 +657,7 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity public int getFeedCounter(long feedId) { return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0; } + }; private void loadData() { @@ -671,6 +683,10 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity loadData(); } + public void onEvent(SubscriptionFragment.SubscriptionEvent event) { + loadFeedFragmentById(event.feed.getId(), null); + } + public void onEventMainThread(ProgressEvent event) { Log.d(TAG, "onEvent(" + event + ")"); switch(event.action) { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java index c98a2fac7..0227aeee4 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -19,6 +19,7 @@ import com.bumptech.glide.Glide; import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.widget.IconTextView; +import de.danoeh.antennapod.fragment.SubscriptionFragment; import org.apache.commons.lang3.ArrayUtils; import java.util.ArrayList; @@ -108,6 +109,9 @@ public class NavListAdapter extends BaseAdapter case PlaybackHistoryFragment.TAG: icon = R.attr.ic_history; break; + case SubscriptionFragment.TAG: + icon = R.attr.ic_folder; + break; case AddFeedFragment.TAG: icon = R.attr.content_new; break; @@ -127,7 +131,11 @@ public class NavListAdapter extends BaseAdapter @Override public int getCount() { - return getSubscriptionOffset() + itemAccess.getCount(); + int baseCount = getSubscriptionOffset(); + if (UserPreferences.showSubscriptionsInDrawer()) { + baseCount += itemAccess.getCount(); + } + return baseCount; } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java new file mode 100644 index 000000000..de000570b --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java @@ -0,0 +1,70 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.view.SubscriptionViewItem; + +/** + * Adapter for subscriptions + */ +public class SubscriptionsAdapter extends BaseAdapter { + + private NavListAdapter.ItemAccess mItemAccess; + + private Context mContext; + + public SubscriptionsAdapter(Context context, NavListAdapter.ItemAccess itemAccess) { + mItemAccess = itemAccess; + mContext = context; + } + + public void setItemAccess(NavListAdapter.ItemAccess itemAccess) { + mItemAccess = itemAccess; + } + + @Override + public int getCount() { + return mItemAccess.getCount(); + } + + @Override + public Object getItem(int position) { + return mItemAccess.getItem(position); + } + + @Override + public long getItemId(int position) { + return mItemAccess.getItem(position).getId(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + final Feed item = (Feed) getItem(position); + if (item == null) return null; + + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = + (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.subscription_item, parent, false); + holder.itemView = (SubscriptionViewItem) convertView.findViewById(R.id.subscription_item); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.itemView.setFeed(item); + return convertView; + } + + static class Holder { + SubscriptionViewItem itemView; + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java new file mode 100644 index 000000000..286212891 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java @@ -0,0 +1,113 @@ +package de.danoeh.antennapod.fragment; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.GridView; + +import java.util.ArrayList; +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.adapter.NavListAdapter; +import de.danoeh.antennapod.adapter.SubscriptionsAdapter; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.storage.DBReader; +import de.greenrobot.event.EventBus; +import rx.Observable; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; + +/** + * Fragment for displaying feed subscriptions + */ +public class SubscriptionFragment extends Fragment { + + public static final String TAG = "SubscriptionFragment"; + + private GridView mSubscriptionGridLayout; + private DBReader.NavDrawerData mDrawerData; + private SubscriptionsAdapter mSubscriptionAdapter; + private NavListAdapter.ItemAccess mItemAccess; + + private List mSubscriptionList = new ArrayList<>(); + + + public SubscriptionFragment() { + } + + + public void setItemAccess(NavListAdapter.ItemAccess itemAccess) { + mItemAccess = itemAccess; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.fragment_subscriptions, container, false); + mSubscriptionGridLayout = (GridView) root.findViewById(R.id.subscriptions_grid); + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mSubscriptionAdapter = new SubscriptionsAdapter(getActivity(), mItemAccess); + + mSubscriptionGridLayout.setAdapter(mSubscriptionAdapter); + + Observable.fromCallable(() -> loadData()) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + mDrawerData = result; + mSubscriptionList = mDrawerData.feeds; + mSubscriptionAdapter.setItemAccess(mItemAccess); + mSubscriptionAdapter.notifyDataSetChanged(); + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); + + + mSubscriptionGridLayout.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + EventBus.getDefault().post(new SubscriptionEvent(mSubscriptionList.get(position))); + } + }); + + if (getActivity() instanceof MainActivity) { + ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.my_subscriptions); + } + + } + + @Override + public void onResume() { + super.onResume(); + } + + public class SubscriptionEvent { + public final Feed feed; + + SubscriptionEvent(Feed f) { + feed = f; + } + } + + + private DBReader.NavDrawerData loadData() { + return DBReader.getNavDrawerData(); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/view/SubscriptionViewItem.java b/app/src/main/java/de/danoeh/antennapod/view/SubscriptionViewItem.java new file mode 100644 index 000000000..67973a7ef --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/SubscriptionViewItem.java @@ -0,0 +1,83 @@ +package de.danoeh.antennapod.view; + +import android.content.Context; +import android.net.Uri; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.Feed; + +/** + * Custom view for handling feed item. + */ +public class SubscriptionViewItem extends RelativeLayout { + + private ImageView mImageView; + private TextView mTextTime; + private TextView mFeedTitle; + private Context mContext; + + public SubscriptionViewItem(Context context) { + super(context); + init(context); + } + + public SubscriptionViewItem(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public SubscriptionViewItem(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, widthMeasureSpec); + } + + private void init(Context context) { + mContext = context; + LayoutInflater mLayoutInflater = + (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = mLayoutInflater.inflate(R.layout.subscription_view, this); + mTextTime = (TextView) view.findViewById(R.id.txtvTime); + mFeedTitle = (TextView) view.findViewById(R.id.txtvTitle); + mImageView = (ImageView) view.findViewById(R.id.imgvCover); + } + + public void setFeed(Feed feed) { + mFeedTitle.setVisibility(VISIBLE); + mFeedTitle.setText(feed.getTitle()); + Glide.with(mContext) + .load(feed.getImageUri()) + .listener(new RequestListener() { + @Override + public boolean onException(Exception e, Uri model, Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(GlideDrawable resource, Uri model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { + mFeedTitle.setVisibility(INVISIBLE); + return false; + } + }) + .centerCrop() + .into(mImageView); + + mTextTime.setVisibility(GONE); + } + +} diff --git a/app/src/main/res/drawable/unread_circle.xml b/app/src/main/res/drawable/unread_circle.xml new file mode 100644 index 000000000..c31e753b1 --- /dev/null +++ b/app/src/main/res/drawable/unread_circle.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml new file mode 100644 index 000000000..8a61e5fa5 --- /dev/null +++ b/app/src/main/res/layout/fragment_subscriptions.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/subscription_item.xml b/app/src/main/res/layout/subscription_item.xml new file mode 100644 index 000000000..fc89ab74d --- /dev/null +++ b/app/src/main/res/layout/subscription_item.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/subscription_view.xml b/app/src/main/res/layout/subscription_view.xml new file mode 100644 index 000000000..84dc00ba5 --- /dev/null +++ b/app/src/main/res/layout/subscription_view.xml @@ -0,0 +1,43 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..9c055f887 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,10 @@ + + + just now + a min ago + an hour ago + " min ago" + yesterday + " hours ago" + " days ago" + \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 675687fb8..93df4e3e0 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -36,6 +36,12 @@ android:summary="@string/pref_nav_drawer_feed_counter_sum" android:defaultValue="0" app:useStockLayout="true"/> + @string/episodes_label @string/downloads_label @string/playback_history_label + @string/my_subscriptions @string/add_feed_label diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml index 74eef525a..c3ee4d3e2 100644 --- a/core/src/main/res/values/attrs.xml +++ b/core/src/main/res/values/attrs.xml @@ -21,6 +21,7 @@ + diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml index 9aafd14e3..4f549efd7 100644 --- a/core/src/main/res/values/dimens.xml +++ b/core/src/main/res/values/dimens.xml @@ -30,6 +30,7 @@ 16dp 8dp + 8dp 16dp 16dp diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index d7a9e3877..8d0ef56d9 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -22,6 +22,7 @@ Running Completed Log + Subscriptions Cancel\nDownload Playback History gpodder.net @@ -383,6 +384,8 @@ Always expand the notification to show playback buttons. Persistent Playback Controls Keep notification and lockscreen controls when playback is paused. + Show subscriptions + Show subscription list directly in navigation drawer Set Lockscreen Background Set the lockscreen background to the current episode\'s image. As a side effect, this will also show the image in third party apps. Show Download Report diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index 27500b3e4..f7775a0bf 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -37,6 +37,7 @@ @color/white @drawable/ic_new_releases_grey600_24dp @drawable/ic_history_grey600_24dp + @drawable/ic_folder_grey600_24dp @drawable/ic_play_arrow_grey600_36dp @drawable/ic_pause_grey600_36dp @drawable/ic_fast_forward_grey600_36dp @@ -94,6 +95,7 @@ #3B3B3B @drawable/ic_new_releases_white_24dp @drawable/ic_history_white_24dp + @drawable/ic_folder_white_24dp @drawable/ic_play_arrow_white_36dp @drawable/ic_pause_white_36dp @drawable/ic_fast_forward_white_36dp @@ -152,6 +154,7 @@ @color/white @drawable/ic_new_releases_grey600_24dp @drawable/ic_history_grey600_24dp + @drawable/ic_folder_grey600_24dp @drawable/ic_play_arrow_grey600_36dp @drawable/ic_pause_grey600_36dp @drawable/ic_fast_forward_grey600_36dp @@ -210,6 +213,7 @@ #3B3B3B @drawable/ic_new_releases_white_24dp @drawable/ic_history_white_24dp + @drawable/ic_folder_white_24dp @drawable/ic_play_arrow_white_36dp @drawable/ic_pause_white_36dp @drawable/ic_fast_forward_white_36dp diff --git a/submodules/dslv b/submodules/dslv new file mode 160000 index 000000000..5f58dff34 --- /dev/null +++ b/submodules/dslv @@ -0,0 +1 @@ +Subproject commit 5f58dff340f705b4dc7f920f81c33d382919c3ad