From 810b2c2df59d60e4bc5097b6406cc4a6d5a6d3a7 Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Mon, 30 Nov 2015 18:26:11 +0100 Subject: [PATCH 01/16] Upgrade to latest versions --- app/build.gradle | 11 +- .../test/antennapod/ui/UITestUtilsTest.java | 8 +- .../fragment/ItunesSearchFragment.java | 143 +++++++++--------- build.gradle | 17 ++- core/build.gradle | 2 +- .../core/gpoddernet/GpodnetService.java | 16 +- .../service/download/APRedirectHandler.java | 54 ------- .../service/download/DownloadService.java | 3 +- .../core/service/download/HttpDownloader.java | 3 +- .../core/service/playback/ShakeListener.java | 5 +- 10 files changed, 100 insertions(+), 162 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java diff --git a/app/build.gradle b/app/build.gradle index eb4b25de8..2fe94d576 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,7 +14,7 @@ dependencies { compile "com.android.support:gridlayout-v7:$supportVersion" compile "com.android.support:cardview-v7:$supportVersion" compile "com.android.support:design:$supportVersion" - compile "com.android.support:recyclerview-v7:22.2.+" + compile "com.android.support:recyclerview-v7:$supportVersion" compile "org.apache.commons:commons-lang3:$commonslangVersion" compile("org.shredzone.flattr4j:flattr4j-core:$flattr4jVersion") { exclude group: "org.json", module: "json" @@ -31,9 +31,12 @@ dependencies { compile "io.reactivex:rxjava:$rxJavaVersion" // And ProGuard rules for RxJava! compile "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion" - compile "com.joanzapata.iconify:android-iconify-fontawesome:2.1.0" - compile "com.afollestad:material-dialogs:0.7.8.1" - compile "com.yqritc:recyclerview-flexibledivider:1.2.6" + compile "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyFontawesomeVersion" + compile "com.joanzapata.iconify:android-iconify-material:$iconifyFontawesomeVersion" + compile("com.github.afollestad.material-dialogs:commons:$materialDialogsVersion") { + transitive = true + } + compile "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion" compile "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion" diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java index 6c5a350de..53fd7d7fd 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java @@ -1,15 +1,15 @@ package de.test.antennapod.ui; import android.test.InstrumentationTestCase; -import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.feed.FeedItem; -import org.apache.http.HttpStatus; import java.io.File; import java.net.HttpURLConnection; import java.net.URL; import java.util.List; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedItem; + /** * Test for the UITestUtils. Makes sure that all URLs are reachable and that the class does not cause any crashes. */ @@ -55,7 +55,7 @@ public class UITestUtilsTest extends InstrumentationTestCase { conn.setRequestMethod("GET"); conn.connect(); int rc = conn.getResponseCode(); - assertEquals(HttpStatus.SC_OK, rc); + assertEquals(HttpURLConnection.HTTP_OK, rc); conn.disconnect(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java index 72704245f..e92df4885 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java @@ -2,21 +2,20 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.content.res.Resources; -import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.widget.SearchView; +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 org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.util.EntityUtils; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -30,13 +29,23 @@ import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.OnlineFeedViewActivity; import de.danoeh.antennapod.adapter.itunes.ItunesAdapter; +import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast; //Searches iTunes store for given string and displays results in a list public class ItunesSearchFragment extends Fragment { - final String TAG = "ItunesSearchFragment"; + + private static final String TAG = "ItunesSearchFragment"; + + private static final String API_URL = "https://itunes.apple.com/search?media=podcast&term=%s"; + /** * Search input field */ @@ -52,6 +61,8 @@ public class ItunesSearchFragment extends Fragment { */ private List searchResults; + private Subscription subscription; + /** * Replace adapter data with provided search results from SearchTask. * @param result List of Podcast objects containing search results @@ -117,7 +128,7 @@ public class ItunesSearchFragment extends Fragment { //This prevents onQueryTextSubmit() from being called twice when keyboard is used //to submit the query. searchView.clearFocus(); - new SearchTask(s).execute(); + search(s); return false; } @@ -137,77 +148,59 @@ public class ItunesSearchFragment extends Fragment { return view; } - /** - * Search the iTunes store for podcasts using the given query - */ - class SearchTask extends AsyncTask { - /** - * Incomplete iTunes API search URL - */ - final String apiUrl = "https://itunes.apple.com/search?media=podcast&term=%s"; - - /** - * Search terms - */ - final String query; - - /** - * Search result - */ - final List taskData = new ArrayList<>(); - - /** - * Constructor - * - * @param query Search string - */ - public SearchTask(String query) { - String encodedQuery = null; - try { - encodedQuery = URLEncoder.encode(query, "UTF-8"); - } catch(UnsupportedEncodingException e) { - // this won't ever be thrown - } - if(encodedQuery != null) { - this.query = encodedQuery; - } else { - this.query = query; // failsafe - } + private void search(String query) { + if (subscription != null) { + subscription.unsubscribe(); } + subscription = rx.Observable.create((Observable.OnSubscribe>) subscriber -> { + String encodedQuery = null; + try { + encodedQuery = URLEncoder.encode(query, "UTF-8"); + } catch (UnsupportedEncodingException e) { + // this won't ever be thrown + } + if (encodedQuery == null) { + encodedQuery = query; // failsafe + } - //Get the podcast data - @Override - protected Void doInBackground(Void... params) { + //Spaces in the query need to be replaced with '+' character. + String formattedUrl = String.format(API_URL, query).replace(' ', '+'); - //Spaces in the query need to be replaced with '+' character. - String formattedUrl = String.format(apiUrl, query).replace(' ', '+'); + OkHttpClient client = AntennapodHttpClient.getHttpClient(); + Request.Builder httpReq = new Request.Builder() + .url(formattedUrl) + .header("User-Agent", ClientConfig.USER_AGENT); + List podcasts = new ArrayList<>(); + try { + Response response = client.newCall(httpReq.build()).execute(); - HttpClient client = new DefaultHttpClient(); - HttpGet get = new HttpGet(formattedUrl); + if(response.isSuccessful()) { + String resultString = response.body().string(); + JSONObject result = new JSONObject(resultString); + JSONArray j = result.getJSONArray("results"); - try { - HttpResponse response = client.execute(get); - String resultString = EntityUtils.toString(response.getEntity()); - JSONObject result = new JSONObject(resultString); - JSONArray j = result.getJSONArray("results"); - - for (int i = 0; i < j.length(); i++){ - JSONObject podcastJson = j.getJSONObject(i); - Podcast podcast = new Podcast(podcastJson); - taskData.add(podcast); - } - - } catch (IOException | JSONException e) { - e.printStackTrace(); - } - return null; - } - - //Save the data and update the list - @Override - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - updateData(taskData); - } + for (int i = 0; i < j.length(); i++) { + JSONObject podcastJson = j.getJSONObject(i); + Podcast podcast = new Podcast(podcastJson); + podcasts.add(podcast); + } + } + else { + subscriber.onError(new IOException("Unexpected error: " + response)); + } + } catch (IOException | JSONException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } + subscriber.onNext(podcasts); + subscriber.onCompleted(); + }) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(podcasts -> { + updateData(podcasts); + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } + } diff --git a/build.gradle b/build.gradle index a82809ca4..bf2d68a60 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "com.android.tools.build:gradle:1.5.0" - classpath "me.tatarka:gradle-retrolambda:3.2.3" + classpath "me.tatarka:gradle-retrolambda:3.2.4" classpath "me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2" // Exclude the version that the android plugin depends on. @@ -36,27 +36,30 @@ subprojects { } project.ext { - compileSdkVersion = 22 - buildToolsVersion = "22.0.1" + compileSdkVersion = 23 + buildToolsVersion = "23.0.2" minSdkVersion = 10 - targetSdkVersion = 22 + targetSdkVersion = 23 - supportVersion = "22.2.1" + supportVersion = "23.1.1" commonsioVersion = "2.4" commonslangVersion = "3.4" eventbusVersion = "2.4.0" flattr4jVersion = "2.12" glideVersion = "3.6.1" jsoupVersion = "1.7.3" + iconifyFontawesomeVersion = "2.1.1" + materialDialogsVersion = "0.8.5.1@aar" + recyclerviewFlexibledividerVersion = "1.2.6" rxAndroidVersion = "1.0.1" rxJavaVersion = "1.0.16" rxJavaRulesVersion = "1.0.16.1" - okhttpVersion = "2.5.0" + okhttpVersion = "2.6.0" okioVersion = "1.6.0" audioPlayerVersion = "v1.0.7" } task wrapper(type: Wrapper) { - gradleVersion = "2.4" + gradleVersion = "2.9" } diff --git a/core/build.gradle b/core/build.gradle index 93f6f94db..d8e6b6287 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -46,7 +46,7 @@ dependencies { exclude group: "org.json", module: "json" } compile "commons-io:commons-io:$commonsioVersion" - compile "com.jayway.android.robotium:robotium-solo:5.5.2" + compile "com.jayway.android.robotium:robotium-solo:5.5.3" compile "org.jsoup:jsoup:$jsoupVersion" compile "com.github.bumptech.glide:glide:$glideVersion" compile "com.github.bumptech.glide:okhttp-integration:1.3.1" diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java index d2a13f768..a24e3a485 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java @@ -10,8 +10,6 @@ import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import com.squareup.okhttp.ResponseBody; -import org.apache.http.HttpStatus; -import org.apache.http.client.ClientProtocolException; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -19,6 +17,7 @@ import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -602,10 +601,7 @@ public class GpodnetService { checkStatusCode(response); body = response.body(); result = getStringFromResponseBody(body); - } catch (ClientProtocolException e) { - e.printStackTrace(); - throw new GpodnetServiceException(e); - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); throw new GpodnetServiceException(e); } finally { @@ -652,12 +648,12 @@ public class GpodnetService { private void checkStatusCode(@NonNull Response response) throws GpodnetServiceException { int responseCode = response.code(); - if (responseCode != HttpStatus.SC_OK) { - if (responseCode == HttpStatus.SC_UNAUTHORIZED) { + if (responseCode != HttpURLConnection.HTTP_OK) { + if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { throw new GpodnetServiceAuthenticationException("Wrong username or password"); } else { - throw new GpodnetServiceBadStatusCodeException( - "Bad response code: " + responseCode, responseCode); + throw new GpodnetServiceBadStatusCodeException("Bad response code: " + + responseCode, responseCode); } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java deleted file mode 100644 index 3efcf4da8..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/APRedirectHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -package de.danoeh.antennapod.core.service.download; - -import android.util.Log; -import de.danoeh.antennapod.core.BuildConfig; -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.apache.http.impl.client.DefaultRedirectHandler; -import org.apache.http.protocol.HttpContext; - -import java.net.URI; - -public class APRedirectHandler extends DefaultRedirectHandler { - // Identifier for logger - private static final String TAG = "APRedirectHandler"; - // Header field, which has to be potentially fixed - private static final String LOC = "Location"; - // Regular expressions for character strings, which should not appear in URLs - private static final String CHi[] = { "\\{", "\\}", "\\|", "\\\\", "\\^", "~", "\\[", "\\]", "\\`"}; - private static final String CHo[] = { "%7B", "%7D", "%7C", "%5C", "%5E", "%7E", "%5B", "%5D", "%60"}; - - /** - * Workaround for broken URLs in redirection. - * Proper solution involves LaxRedirectStrategy() which is not available in - * current API yet. - */ - @Override - public URI getLocationURI(HttpResponse response, HttpContext context) - throws org.apache.http.ProtocolException { - - Header h[] = response.getHeaders(LOC); - if (h.length>0) { - String s = h[0].getValue(); - - // Fix broken URL - for(int i=0; i 2.25f) { + double gForce = Math.sqrt(gX*gX + gY*gY + gZ*gZ); + if (gForce > 2.25) { Log.d(TAG, "Detected shake " + gForce); mSleepTimer.onShake(); } From 99800d98731ed2ef415932abebe1a66955df4f2e Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Mon, 30 Nov 2015 18:27:24 +0100 Subject: [PATCH 02/16] Change parameters of StorageUtils.storageAvailable --- .../danoeh/antennapod/activity/StorageErrorActivity.java | 2 +- .../antennapod/core/service/download/HttpDownloader.java | 2 +- .../de/danoeh/antennapod/core/util/StorageUtils.java | 9 +++------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java index 7f975b3c8..b02e82f0b 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java @@ -39,7 +39,7 @@ public class StorageErrorActivity extends ActionBarActivity { @Override protected void onResume() { super.onResume(); - if (StorageUtils.storageAvailable(this)) { + if (StorageUtils.storageAvailable()) { leaveErrorState(); } else { registerReceiver(mediaUpdate, new IntentFilter( diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java index 25ab2f6fd..0b9fba6f7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java @@ -161,7 +161,7 @@ public class HttpDownloader extends Downloader { return; } - if (!StorageUtils.storageAvailable(ClientConfig.applicationCallbacks.getApplicationInstance())) { + if (!StorageUtils.storageAvailable()) { onFail(DownloadError.ERROR_DEVICE_NOT_FOUND, null); return; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java index d64148715..1ef81bf64 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java @@ -1,14 +1,12 @@ package de.danoeh.antennapod.core.util; import android.app.Activity; -import android.content.Context; import android.os.Build; import android.os.StatFs; import android.util.Log; import java.io.File; -import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.preferences.UserPreferences; @@ -18,13 +16,12 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; public class StorageUtils { private static final String TAG = "StorageUtils"; - public static boolean storageAvailable(Context context) { + public static boolean storageAvailable() { File dir = UserPreferences.getDataFolder(null); if (dir != null) { return dir.exists() && dir.canRead() && dir.canWrite(); } else { - if (BuildConfig.DEBUG) - Log.d(TAG, "Storage not available: data folder is null"); + Log.d(TAG, "Storage not available: data folder is null"); return false; } } @@ -39,7 +36,7 @@ public class StorageUtils { * @return true if external storage is available */ public static boolean checkStorageAvailability(Activity activity) { - boolean storageAvailable = storageAvailable(activity); + boolean storageAvailable = storageAvailable(); if (!storageAvailable) { activity.finish(); activity.startActivity(ClientConfig.applicationCallbacks.getStorageErrorActivity(activity)); From 77f78269323a9ba95d06e18242629509c9493a80 Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Mon, 30 Nov 2015 18:29:26 +0100 Subject: [PATCH 03/16] getMainActivtyActionBar -> getSupportActionBar --- .../java/de/test/antennapod/ui/MainActivityTest.java | 2 +- .../java/de/danoeh/antennapod/activity/MainActivity.java | 9 --------- .../de/danoeh/antennapod/fragment/AddFeedFragment.java | 2 +- .../danoeh/antennapod/fragment/gpodnet/TagFragment.java | 2 +- .../antennapod/fragment/gpodnet/TagListFragment.java | 2 +- 5 files changed, 4 insertions(+), 13 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java index 4dae53a15..7c194df2c 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java @@ -137,7 +137,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2 Date: Mon, 30 Nov 2015 18:30:07 +0100 Subject: [PATCH 04/16] Nicify ItemFragment and ItemListFragment --- .../java/de/danoeh/antennapod/PodcastApp.java | 2 + .../antennapod/fragment/ItemFragment.java | 223 ++++++++---------- .../antennapod/fragment/ItemlistFragment.java | 56 ++--- app/src/main/res/layout/feeditem_fragment.xml | 127 +++++++++- .../res/layout/feeditem_fragment_header.xml | 136 ----------- 5 files changed, 247 insertions(+), 297 deletions(-) delete mode 100644 app/src/main/res/layout/feeditem_fragment_header.xml diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java index 835f43f40..c1d4bc4fd 100644 --- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java +++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java @@ -6,6 +6,7 @@ import android.os.StrictMode; import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.fonts.FontAwesomeModule; +import com.joanzapata.iconify.fonts.MaterialModule; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; @@ -62,6 +63,7 @@ public class PodcastApp extends Application { NetworkUtils.init(this); EventDistributor.getInstance(); Iconify.with(new FontAwesomeModule()); + Iconify.with(new MaterialModule()); SPAUtil.sendSPAppsQueryFeedsIntent(this); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index 10d56d5cf..58cd6c40a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -4,35 +4,33 @@ import android.annotation.TargetApi; import android.content.ClipData; import android.content.Context; import android.content.Intent; -import android.content.res.TypedArray; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.util.Pair; -import android.support.v7.widget.PopupMenu; -import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; import android.view.ContextMenu; 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.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; -import android.widget.Button; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.bumptech.glide.Glide; +import com.joanzapata.iconify.Iconify; +import com.joanzapata.iconify.widget.IconButton; import org.apache.commons.lang3.ArrayUtils; @@ -101,7 +99,6 @@ public class ItemFragment extends Fragment { private List downloaderList; private ViewGroup root; - private View header; private WebView webvDescription; private TextView txtvTitle; private TextView txtvDuration; @@ -109,10 +106,9 @@ public class ItemFragment extends Fragment { private ImageView imgvCover; private ProgressBar progbarDownload; private ProgressBar progbarLoading; - private Button butAction1; - private Button butAction2; - private ImageButton butMore; - private PopupMenu popupMenu; + private IconButton butAction1; + private IconButton butAction2; + private Menu popupMenu; private Subscription subscription; @@ -125,7 +121,7 @@ public class ItemFragment extends Fragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); - setHasOptionsMenu(false); + setHasOptionsMenu(true); itemID = getArguments().getLong(ARG_FEEDITEM, -1); } @@ -134,15 +130,12 @@ public class ItemFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); - ((MainActivity) getActivity()).getSupportActionBar().setTitle(""); - Toolbar toolbar = ((MainActivity) getActivity()).getToolbar(); View layout = inflater.inflate(R.layout.feeditem_fragment, container, false); - header = inflater.inflate(R.layout.feeditem_fragment_header, toolbar, false); root = (ViewGroup) layout.findViewById(R.id.content_root); - txtvTitle = (TextView) header.findViewById(R.id.txtvTitle); - txtvDuration = (TextView) header.findViewById(R.id.txtvDuration); - txtvPublished = (TextView) header.findViewById(R.id.txtvPublished); + txtvTitle = (TextView) layout.findViewById(R.id.txtvTitle); + txtvDuration = (TextView) layout.findViewById(R.id.txtvDuration); + txtvPublished = (TextView) layout.findViewById(R.id.txtvPublished); if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448 txtvTitle.setEllipsize(TextUtils.TruncateAt.END); } @@ -172,81 +165,43 @@ public class ItemFragment extends Fragment { }); registerForContextMenu(webvDescription); - imgvCover = (ImageView) header.findViewById(R.id.imgvCover); - progbarDownload = (ProgressBar) header.findViewById(R.id.progbarDownload); + imgvCover = (ImageView) layout.findViewById(R.id.imgvCover); + progbarDownload = (ProgressBar) layout.findViewById(R.id.progbarDownload); progbarLoading = (ProgressBar) layout.findViewById(R.id.progbarLoading); - butAction1 = (Button) header.findViewById(R.id.butAction1); - butAction2 = (Button) header.findViewById(R.id.butAction2); - butMore = (ImageButton) header.findViewById(R.id.butMoreActions); - popupMenu = new PopupMenu(getActivity(), butMore); + butAction1 = (IconButton) layout.findViewById(R.id.butAction1); + butAction2 = (IconButton) layout.findViewById(R.id.butAction2); - butAction1.setOnClickListener(new View.OnClickListener() { - DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity()); - - @Override - - public void onClick(View v) { - if (item == null) { - return; - } - actionButtonCallback.onActionButtonPressed(item); - FeedMedia media = item.getMedia(); - if (media != null && media.isDownloaded()) { - // playback was started, dialog should close itself - ((MainActivity) getActivity()).dismissChildFragment(); - } - } - } - ); + butAction1.setOnClickListener(v -> { + if (item == null) { + return; + } + DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getActivity()); + actionButtonCallback.onActionButtonPressed(item); + FeedMedia media = item.getMedia(); + if (media != null && media.isDownloaded()) { + // playback was started, dialog should close itself + ((MainActivity) getActivity()).dismissChildFragment(); + } + }); butAction2.setOnClickListener(v -> { - if (item == null) { - return; - } - - if (item.hasMedia()) { - FeedMedia media = item.getMedia(); - if (!media.isDownloaded()) { - DBTasks.playMedia(getActivity(), media, true, true, true); - ((MainActivity) getActivity()).dismissChildFragment(); - } else { - DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId()); - } - } else if (item.getLink() != null) { - Uri uri = Uri.parse(item.getLink()); - getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri)); - } + if (item == null) { + return; } - ); - butMore.setOnClickListener(v -> { - if (item == null) { - return; - } - popupMenu.getMenu().clear(); - popupMenu.inflate(R.menu.feeditem_options); - if (item.hasMedia()) { - FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue); + if (item.hasMedia()) { + FeedMedia media = item.getMedia(); + if (!media.isDownloaded()) { + DBTasks.playMedia(getActivity(), media, true, true, true); + ((MainActivity) getActivity()).dismissChildFragment(); } else { - // these are already available via button1 and button2 - FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue, - R.id.mark_read_item, R.id.visit_website_item); + DBWriter.deleteFeedMediaOfItem(getActivity(), media.getId()); } - popupMenu.show(); + } else if (item.getLink() != null) { + Uri uri = Uri.parse(item.getLink()); + getActivity().startActivity(new Intent(Intent.ACTION_VIEW, uri)); } - ); - - popupMenu.setOnMenuItemClickListener(menuItem -> { - - try { - return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item); - } catch (DownloadRequestException e) { - e.printStackTrace(); - Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show(); - return true; - } - } - ); + }); return layout; } @@ -254,8 +209,6 @@ public class ItemFragment extends Fragment { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - Toolbar toolbar = ((MainActivity) getActivity()).getToolbar(); - toolbar.addView(header); load(); } @@ -279,7 +232,6 @@ public class ItemFragment extends Fragment { @Override public void onDestroyView() { super.onDestroyView(); - resetViewState(); if(subscription != null) { subscription.unsubscribe(); } @@ -289,15 +241,37 @@ public class ItemFragment extends Fragment { } } - private void resetViewState() { - Toolbar toolbar = ((MainActivity) getActivity()).getToolbar(); - toolbar.removeView(header); + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + if(item == null) { + return; + } + inflater.inflate(R.menu.feeditem_options, menu); + popupMenu = menu; + if (item.hasMedia()) { + FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue); + } else { + // these are already available via button1 and button2 + FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue, + R.id.mark_read_item, R.id.visit_website_item); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + try { + return FeedItemMenuHandler.onMenuItemClicked(getActivity(), menuItem.getItemId(), item); + } catch (DownloadRequestException e) { + e.printStackTrace(); + Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show(); + return true; + } } private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() { @Override public void setItemVisibility(int id, boolean visible) { - MenuItem item = popupMenu.getMenu().findItem(id); + MenuItem item = popupMenu.findItem(id); if (item != null) { item.setVisible(visible); } @@ -319,7 +293,7 @@ public class ItemFragment extends Fragment { Log.d(TAG, "updateAppearance item is null"); return; } - + getActivity().supportInvalidateOptionsMenu(); txtvTitle.setText(item.getTitle()); if (item.getPubDate() != null) { @@ -347,54 +321,55 @@ public class ItemFragment extends Fragment { } FeedMedia media = item.getMedia(); + String butAction1Icon = null; + int butAction1Text = 0; + String butAction2Icon = null; + int butAction2Text = 0; if (media == null) { - TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.navigation_accept, - R.attr.location_web_site}); - if (!item.isPlayed()) { - butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null); - butAction1.setText(getActivity().getString(R.string.mark_read_label)); - butAction1.setVisibility(View.VISIBLE); - } else { - butAction1.setVisibility(View.INVISIBLE); + butAction1Icon = "{fa-check 24sp}"; + butAction1Text = R.string.mark_read_label; } - if (item.getLink() != null) { - butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null); - butAction2.setText(getActivity().getString(R.string.visit_website_label)); - } else { - butAction2.setEnabled(false); + butAction2Icon = "{ma-web 24sp}"; + butAction2Text = R.string.visit_website_label; } - - drawables.recycle(); - } else {if(media.getDuration() > 0) { + } else { + if(media.getDuration() > 0) { txtvDuration.setText(Converter.getDurationStringLong(media.getDuration())); } - boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media); - TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.av_play, - R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel}); - if (!media.isDownloaded()) { - butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(2), null, null, null); - butAction2.setText(getActivity().getString(R.string.stream_label)); + butAction2Icon = "{md-settings-input-antenna 24sp}"; + butAction2Text = R.string.stream_label; } else { - butAction2.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(3), null, null, null); - butAction2.setText(getActivity().getString(R.string.remove_episode_lable)); + butAction2Icon = "{md-delete 24sp}"; + butAction2Text = R.string.remove_label; } - if (isDownloading) { - butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(4), null, null, null); - butAction1.setText(getActivity().getString(R.string.cancel_download_label)); + butAction1Icon = "{md-cancel 24sp}"; + butAction1Text = R.string.cancel_label; } else if (media.isDownloaded()) { - butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null); - butAction1.setText(getActivity().getString(R.string.play_label)); + butAction1Icon = "{md-play-arrow 24sp}"; + butAction1Text = R.string.play_label; } else { - butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(1), null, null, null); - butAction1.setText(getActivity().getString(R.string.download_label)); + butAction1Icon = "{md-file-download 24sp}"; + butAction1Text = R.string.download_label; } - - drawables.recycle(); + } + if(butAction1Icon != null && butAction1Text != 0) { + butAction1.setText(butAction1Icon +"\u0020\u0020" + getActivity().getString(butAction1Text)); + Iconify.addIcons(butAction1); + butAction1.setVisibility(View.VISIBLE); + } else { + butAction1.setVisibility(View.INVISIBLE); + } + if(butAction2Icon != null && butAction2Text != 0) { + butAction2.setText(butAction2Icon +"\u0020\u0020" + getActivity().getString(butAction2Text)); + Iconify.addIcons(butAction2); + butAction2.setVisibility(View.VISIBLE); + } else { + butAction2.setVisibility(View.INVISIBLE); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java index fbe2274a3..1a40b3532 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -12,7 +12,6 @@ import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v4.util.Pair; import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.SearchView; import android.util.Log; import android.view.ContextMenu; @@ -152,27 +151,20 @@ public class ItemlistFragment extends ListFragment { } } - @Override - public void onStop() { - super.onStop(); - EventDistributor.getInstance().unregister(contentUpdate); - EventBus.getDefault().unregister(this); - if(subscription != null) { - subscription.unsubscribe(); - } - } - @Override public void onResume() { super.onResume(); Log.d(TAG, "onResume()"); + ((MainActivity)getActivity()).getSupportActionBar().setTitle(""); updateProgressBarVisibility(); loadItems(); } @Override - public void onDetach() { - super.onDetach(); + public void onPause() { + super.onPause(); + EventDistributor.getInstance().unregister(contentUpdate); + EventBus.getDefault().unregister(this); if(subscription != null) { subscription.unsubscribe(); } @@ -368,7 +360,6 @@ public class ItemlistFragment extends ListFragment { @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(""); registerForContextMenu(getListView()); @@ -382,7 +373,9 @@ public class ItemlistFragment extends ListFragment { public void onListItemClick(ListView l, View v, int position, long id) { FeedItem selection = adapter.getItem(position - l.getHeaderViewsCount()); if (selection != null) { - ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(selection.getId())); + MainActivity activity = (MainActivity) getActivity(); + activity.loadChildFragment(ItemFragment.newInstance(selection.getId())); + activity.getSupportActionBar().setTitle(feed.getTitle()); } } @@ -547,15 +540,12 @@ public class ItemlistFragment extends ListFragment { .dontAnimate() .into(imgvCover); - butShowInfo.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (viewsCreated && itemsLoaded) { - Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); - startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, - feed.getId()); - startActivity(startIntent); - } + butShowInfo.setOnClickListener(v -> { + if (viewsCreated && itemsLoaded) { + Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); + startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, + feed.getId()); + startActivity(startIntent); } }); } @@ -573,16 +563,13 @@ public class ItemlistFragment extends ListFragment { View header = inflater.inflate(R.layout.more_content_list_footer, lv, false); lv.addFooterView(header); listFooter = new MoreContentListFooterUtil(header); - listFooter.setClickListener(new MoreContentListFooterUtil.Listener() { - @Override - public void onClick() { - if (feed != null) { - try { - DBTasks.loadNextPageOfFeed(getActivity(), feed, false); - } catch (DownloadRequestException e) { - e.printStackTrace(); - DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); - } + listFooter.setClickListener(() -> { + if (feed != null) { + try { + DBTasks.loadNextPageOfFeed(getActivity(), feed, false); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); } } }); @@ -629,7 +616,6 @@ public class ItemlistFragment extends ListFragment { if(subscription != null) { subscription.unsubscribe(); } - subscription = Observable.fromCallable(() -> loadData()) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml index 5e1b580d2..78b47a74c 100644 --- a/app/src/main/res/layout/feeditem_fragment.xml +++ b/app/src/main/res/layout/feeditem_fragment.xml @@ -1,13 +1,136 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22,4 +145,4 @@ android:layout_gravity="center" android:indeterminate="true" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/feeditem_fragment_header.xml b/app/src/main/res/layout/feeditem_fragment_header.xml deleted file mode 100644 index 2534dddbe..000000000 --- a/app/src/main/res/layout/feeditem_fragment_header.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -