diff --git a/app/app-release.apk b/app/app-release.apk index 4cc486d..15d995e 100644 Binary files a/app/app-release.apk and b/app/app-release.apk differ diff --git a/app/build.gradle b/app/build.gradle index f6c0389..ffb470f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ */ apply plugin: 'com.android.application' -apply plugin: 'android-apt' +//apply plugin: 'android-apt' android { signingConfigs { @@ -24,14 +24,18 @@ android { } } + dataBinding { + enabled = true + } + compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "uk.ac.hutton.ics.buntata" minSdkVersion 16 targetSdkVersion 25 - versionCode 12 - versionName "1.17.04.25" + versionCode 13 + versionName "1.17.05.10" multiDexEnabled true } @@ -70,20 +74,19 @@ android { repositories { mavenCentral() /* The standard Java Maven repository. */ - maven { url "http://maven.restlet.org" } maven { url 'https://jitpack.io' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.google.android.gms:play-services-analytics:10.2.1' + compile 'com.google.android.gms:play-services-analytics:10.2.4' compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.android.support:recyclerview-v7:25.3.1' compile 'com.android.support:cardview-v7:25.3.1' compile 'com.android.support:design:25.3.1' compile 'com.android.support:palette-v7:25.3.1' compile 'com.squareup.picasso:picasso:2.5.2' - compile 'com.heinrichreimersoftware:material-intro:1.6' + compile 'com.heinrichreimersoftware:material-intro:1.6.2' compile 'me.relex:circleindicator:1.2.1@aar' compile 'com.andkulikov:transitionseverywhere:1.7.0' compile 'com.afollestad:sectioned-recyclerview:0.2.3' @@ -91,8 +94,9 @@ dependencies { compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3' compile 'com.squareup.retrofit2:converter-jackson:2.0.0-beta3' compile 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0' - compile 'com.jakewharton:butterknife:8.4.0' - apt 'com.jakewharton:butterknife-compiler:8.4.0' + compile 'com.jakewharton:butterknife:8.5.1' + annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' +// apt 'com.jakewharton:butterknife-compiler:8.5.1' } // Get the key store information from the properties file @@ -101,5 +105,4 @@ props.load(new FileInputStream(project.file("release.properties"))) android.signingConfigs.release.storeFile rootProject.file(props.keyStore) android.signingConfigs.release.storePassword props.keyStorePassword android.signingConfigs.release.keyAlias props.keyAlias -android.signingConfigs.release.keyPassword props.keyAliasPassword -0 +android.signingConfigs.release.keyPassword props.keyAliasPassword \ No newline at end of file diff --git a/app/src/main/java/uk/ac/hutton/ics/buntata/activity/MainActivity.java b/app/src/main/java/uk/ac/hutton/ics/buntata/activity/MainActivity.java index 25837a7..9715a3f 100644 --- a/app/src/main/java/uk/ac/hutton/ics/buntata/activity/MainActivity.java +++ b/app/src/main/java/uk/ac/hutton/ics/buntata/activity/MainActivity.java @@ -114,6 +114,34 @@ public void onClick(View v) }); } + @Override + protected void onPostCreate(Bundle savedInstanceState) + { + super.onPostCreate(savedInstanceState); + +// if (PreferenceUtils.getPreferenceAsBoolean(this, PreferenceUtils.PREFS_SHOW_DATASOURCE_SELECTION_HELP, true)) +// { +// drawerLayout.openDrawer(Gravity.START); +// +// navigationView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() +// { +// @Override +// public void onGlobalLayout() +// { +// navigationView.getViewTreeObserver().removeOnGlobalLayoutListener(this); +// +// /* Show a Snackbar with a button to open the datasource activity */ +// int textColor = ContextCompat.getColor(MainActivity.this, android.R.color.primary_text_dark); +// SnackbarUtils.create(getSnackbarParentView(), R.string.snackbar_updates_available, textColor, ContextCompat.getColor(MainActivity.this, R.color.colorPrimaryDark), 5000) +// .setActionTextColor(textColor) +// .show(); +// +// PreferenceUtils.setPreferenceAsBoolean(MainActivity.this, PreferenceUtils.PREFS_SHOW_DATASOURCE_SELECTION_HELP, false); +// } +// }); +// } + } + @Override protected void onResume() { diff --git a/app/src/main/java/uk/ac/hutton/ics/buntata/adapter/DatasourceAdapter.java b/app/src/main/java/uk/ac/hutton/ics/buntata/adapter/DatasourceAdapter.java index 3f11e0a..753b76e 100644 --- a/app/src/main/java/uk/ac/hutton/ics/buntata/adapter/DatasourceAdapter.java +++ b/app/src/main/java/uk/ac/hutton/ics/buntata/adapter/DatasourceAdapter.java @@ -16,10 +16,8 @@ package uk.ac.hutton.ics.buntata.adapter; -import android.animation.*; import android.app.*; import android.content.*; -import android.graphics.*; import android.support.design.widget.*; import android.support.v4.app.*; import android.support.v4.content.*; @@ -103,7 +101,7 @@ static class ItemViewHolder extends AbstractViewHolder @BindView(R.id.datasource_download_progress) ProgressBar progressBar; @BindView(R.id.datasource_download_indicator) - ImageView downloadStatus; + Button downloadStatus; @BindView(R.id.datasource_details_view) LinearLayout detailsView; @BindView(R.id.datasource_provider_view) @@ -167,36 +165,36 @@ public DatasourceAdapter.AbstractViewHolder onCreateViewHolder(ViewGroup parent, private void animate(final ItemViewHolder itemViewHolder) { - final int color = ContextCompat.getColor(context, R.color.colorAccent); - - final ValueAnimator colorAnim = ObjectAnimator.ofFloat(0f, 1f); - colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() - { - @Override - public void onAnimationUpdate(ValueAnimator animation) - { - float mul = (Float) animation.getAnimatedValue(); - int alphaOrange = adjustAlpha(color, mul); - itemViewHolder.downloadStatus.setColorFilter(alphaOrange, PorterDuff.Mode.SRC_ATOP); - if (mul == 0.0) - { - itemViewHolder.downloadStatus.setColorFilter(null); - } - } - }); - - colorAnim.setDuration(500); - colorAnim.start(); - } - - private int adjustAlpha(int color, float factor) - { - int alpha = Math.round(Color.alpha(color) * factor); - int red = Color.red(color); - int green = Color.green(color); - int blue = Color.blue(color); - return Color.argb(alpha, red, green, blue); +// final int color = ContextCompat.getColor(context, R.color.colorAccent); +// +// final ValueAnimator colorAnim = ObjectAnimator.ofFloat(0f, 1f); +// colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() +// { +// @Override +// public void onAnimationUpdate(ValueAnimator animation) +// { +// float mul = (Float) animation.getAnimatedValue(); +// int alphaOrange = adjustAlpha(color, mul); +// itemViewHolder.downloadStatus.setColorFilter(alphaOrange, PorterDuff.Mode.SRC_ATOP); +// if (mul == 0.0) +// { +// itemViewHolder.downloadStatus.setColorFilter(null); +// } +// } +// }); +// +// colorAnim.setDuration(500); +// colorAnim.start(); } +// +// private int adjustAlpha(int color, float factor) +// { +// int alpha = Math.round(Color.alpha(color) * factor); +// int red = Color.red(color); +// int green = Color.green(color); +// int blue = Color.blue(color); +// return Color.argb(alpha, red, green, blue); +// } @Override public int getSectionCount() @@ -317,25 +315,8 @@ public void onClick(View v) final BuntataDatasourceAdvanced ds = get(section, relativePosition); holder.progressBar.setVisibility(ds.isDownloading() ? View.VISIBLE : View.GONE); - /* Set the state icon */ - int resource; - switch (ds.getState()) - { - case INSTALLED_NO_UPDATE: - resource = R.drawable.action_ok; - break; - - case INSTALLED_HAS_UPDATE: - resource = R.drawable.action_update; - break; - - case NOT_INSTALLED: - default: - resource = R.drawable.action_download; - break; - } - - holder.downloadStatus.setImageResource(resource); + setState(ds, holder); +// holder.downloadStatus.setImageResource(resource); // holder.downloadStatus.setColorFilter(ContextCompat.getColor(context, R.color.colorPrimaryDark)); /* If there is an icon, set it */ @@ -453,6 +434,7 @@ public void onClick(DialogInterface dialog, int which) holder.progressBar.setVisibility(View.GONE); ds.setDownloading(false); downloadTask = null; + setState(ds, holder); } } }, null); @@ -473,22 +455,11 @@ public void onClick(DialogInterface dialog, int which) switch (ds.getState()) { case INSTALLED_NO_UPDATE: - if (context instanceof DatasourceActivity) - { - /* If we're coming from the DatasourceActivity and the user clicked on a data source that has already been downloaded - * then we just remember the selected id and close the activity to return to wherever we came from */ - PreferenceUtils.setPreferenceAsInt(context, PreferenceUtils.PREFS_SELECTED_DATASOURCE_ID, ds.getId()); - context.setResult(Activity.RESULT_OK); - context.finish(); - return; - } - /* Else, we're coming from the introduction activity and we don't want to return anywhere */ - else - { - SnackbarUtils.show(v, R.string.snackbar_already_downloaded, ContextCompat.getColor(context, android.R.color.primary_text_dark), ContextCompat.getColor(context, R.color.colorPrimaryDark), Snackbar.LENGTH_LONG); - PreferenceUtils.setPreferenceAsInt(context, PreferenceUtils.PREFS_SELECTED_DATASOURCE_ID, ds.getId()); - return; - } + /* Just remember the selected id and close the activity to return to wherever we came from */ + PreferenceUtils.setPreferenceAsInt(context, PreferenceUtils.PREFS_SELECTED_DATASOURCE_ID, ds.getId()); + context.setResult(Activity.RESULT_OK); + context.finish(); + return; case INSTALLED_HAS_UPDATE: case NOT_INSTALLED: @@ -514,10 +485,37 @@ public void onClick(DialogInterface dialog, int which) }); } + private void setState(BuntataDatasourceAdvanced ds, ItemViewHolder holder) + { + /* Set the state icon */ + int resource; + switch (ds.getState()) + { + case INSTALLED_NO_UPDATE: + resource = R.string.datasource_status_select; + break; + + case INSTALLED_HAS_UPDATE: + resource = R.string.datasource_status_update; + break; + + case NOT_INSTALLED: + default: + resource = R.string.datasource_status_download; + break; + } + + if (ds.isDownloading()) + resource = R.string.datasource_status_cancel; + + holder.downloadStatus.setText(resource); + } + private void initDownload(boolean includeVideos, final ItemViewHolder holder, final BuntataDatasourceAdvanced ds) { holder.progressBar.setVisibility(View.VISIBLE); holder.progressBar.setIndeterminate(true); + holder.downloadStatus.setText(R.string.datasource_status_cancel); ds.setDownloading(true); /* Start the download */ @@ -528,9 +526,12 @@ public void onFailure(Throwable caught) { super.onFailure(caught); + GoogleAnalyticsUtils.trackException(context, BaseActivity.getTracker(context, BaseActivity.TrackerName.APP_TRACKER), caught); + holder.progressBar.setVisibility(View.GONE); ds.setDownloading(false); downloadTask = null; + setState(ds, holder); SnackbarUtils.show(holder.view, R.string.snackbar_download_unsuccessful, ContextCompat.getColor(context, android.R.color.primary_text_dark), ContextCompat.getColor(context, R.color.colorPrimaryDark), Snackbar.LENGTH_LONG); } @@ -543,6 +544,7 @@ public void onSuccess(File result) holder.progressBar.setVisibility(View.GONE); ds.setState(BuntataDatasourceAdvanced.InstallState.INSTALLED_NO_UPDATE); ds.setDownloading(false); + setState(ds, holder); PreferenceUtils.setPreferenceAsInt(context, PreferenceUtils.PREFS_SELECTED_DATASOURCE_ID, ds.getId()); SnackbarUtils.show(holder.view, R.string.snackbar_download_successful, ContextCompat.getColor(context, android.R.color.primary_text_dark), ContextCompat.getColor(context, R.color.colorPrimaryDark), Snackbar.LENGTH_LONG); diff --git a/app/src/main/java/uk/ac/hutton/ics/buntata/fragment/DatasourceFragment.java b/app/src/main/java/uk/ac/hutton/ics/buntata/fragment/DatasourceFragment.java index 295dbd8..564fba1 100644 --- a/app/src/main/java/uk/ac/hutton/ics/buntata/fragment/DatasourceFragment.java +++ b/app/src/main/java/uk/ac/hutton/ics/buntata/fragment/DatasourceFragment.java @@ -43,12 +43,17 @@ */ public class DatasourceFragment extends Fragment { + @BindView(R.id.datasource_network_layout) + LinearLayout layout; @BindView(R.id.datasource_text) TextView text; @BindView(R.id.datasource_recycler_view) RecyclerView recyclerView; @BindView(R.id.datasource_network_warning) TextView networkWarning; + @BindView(R.id.datasource_network_refresh) + Button networkButton; + private DatasourceAdapter adapter; private Unbinder unbinder; @@ -105,11 +110,17 @@ private void updateStatus() // } // else // { - networkWarning.setVisibility(View.GONE); + layout.setVisibility(View.GONE); requestData(); // } } + @OnClick(R.id.datasource_network_refresh) + public void onNetworkRefresh() + { + requestData(); + } + private void requestData() { final boolean cancelable = getActivity() instanceof DatasourceActivity; @@ -127,11 +138,11 @@ public void onSuccess(List result) { if (result.size() < 1) { - networkWarning.setVisibility(View.VISIBLE); + layout.setVisibility(View.VISIBLE); } else { - networkWarning.setVisibility(View.GONE); + layout.setVisibility(View.GONE); adapter = new DatasourceAdapter(getActivity(), recyclerView, result); recyclerView.setAdapter(adapter); diff --git a/app/src/main/java/uk/ac/hutton/ics/buntata/service/DatasourceService.java b/app/src/main/java/uk/ac/hutton/ics/buntata/service/DatasourceService.java index 964c7b3..bfd083f 100644 --- a/app/src/main/java/uk/ac/hutton/ics/buntata/service/DatasourceService.java +++ b/app/src/main/java/uk/ac/hutton/ics/buntata/service/DatasourceService.java @@ -255,7 +255,7 @@ protected void processData(File file) { if (file == null) { - callback.onFailure(new IOException("File not found")); + callback.onFailure(null); return; } diff --git a/app/src/main/java/uk/ac/hutton/ics/buntata/service/RemoteCallback.java b/app/src/main/java/uk/ac/hutton/ics/buntata/service/RemoteCallback.java index d5176e1..6d8cecd 100644 --- a/app/src/main/java/uk/ac/hutton/ics/buntata/service/RemoteCallback.java +++ b/app/src/main/java/uk/ac/hutton/ics/buntata/service/RemoteCallback.java @@ -17,7 +17,6 @@ package uk.ac.hutton.ics.buntata.service; import android.content.*; -import android.widget.*; /** * The {@link RemoteCallback} is a very basic callback with an {@link #onSuccess(T)} and a {@link #onFailure(Throwable)} method. @@ -48,9 +47,7 @@ public RemoteCallback(Context context) */ public void onFailure(Throwable caught) { - caught.printStackTrace(); - - // TODO: error handling - Toast.makeText(context, "ERROR: " + caught.getLocalizedMessage(), Toast.LENGTH_LONG).show(); + if (caught != null) + caught.printStackTrace(); } } diff --git a/app/src/main/java/uk/ac/hutton/ics/buntata/util/GoogleAnalyticsUtils.java b/app/src/main/java/uk/ac/hutton/ics/buntata/util/GoogleAnalyticsUtils.java index c5f1caf..0adc329 100644 --- a/app/src/main/java/uk/ac/hutton/ics/buntata/util/GoogleAnalyticsUtils.java +++ b/app/src/main/java/uk/ac/hutton/ics/buntata/util/GoogleAnalyticsUtils.java @@ -67,9 +67,7 @@ public static void trackEvent(Context context, Tracker tracker, String category, public static void trackEvent(Context context, Tracker tracker, String category, String action, String label, Long value) { if (tracker == null) - { return; - } /* If we're using the debug version, don't track to Google Analytics */ String packageName = context.getPackageName(); @@ -94,4 +92,24 @@ public static void trackEvent(Context context, Tracker tracker, String category, /* Build and send an Event */ tracker.send(builder.build()); } + + public static void trackException(Context context, Tracker tracker, Throwable e) + { + if (tracker == null) + return; + + /* If we're using the debug version, don't track to Google Analytics */ + String packageName = context.getPackageName(); + /* Also, if the user disabled tracking, we don't track to Google Analytics */ + if (packageName != null && packageName.endsWith(".debug") || !PreferenceUtils.getPreferenceAsBoolean(context, PreferenceUtils.PREFS_GA_OPT_OUT, true)) + { + return; + } + + /* Build and send an Event */ + tracker.send(new HitBuilders.ExceptionBuilder() + .setDescription(new StandardExceptionParser(context, null).getDescription(Thread.currentThread().getName(), e)) + .setFatal(false) + .build()); + } } diff --git a/app/src/main/java/uk/ac/hutton/ics/buntata/util/PreferenceUtils.java b/app/src/main/java/uk/ac/hutton/ics/buntata/util/PreferenceUtils.java index 83694f2..ec76faa 100644 --- a/app/src/main/java/uk/ac/hutton/ics/buntata/util/PreferenceUtils.java +++ b/app/src/main/java/uk/ac/hutton/ics/buntata/util/PreferenceUtils.java @@ -27,16 +27,17 @@ public class PreferenceUtils { - public static final String PREFS_KNODEL_SERVER_URL = "prefs.general.restlet.api.url"; - public static final String PREFS_AT_LEAST_ONE_DATASOURCE = "prefs.at.least.one.datasource"; - public static final String PREFS_EULA_ACCEPTED = "prefs.eula.accepted"; - public static final String PREFS_EULA_TYPE = "prefs.eula.type"; - public static final String PREFS_SELECTED_DATASOURCE_ID = "prefs.selected.datasource.id"; - public static final String PREFS_GA_OPT_OUT = "prefs.google.analytics.opt.out"; - public static final String PREFS_LAST_VERSION = "prefs.last.version.code"; - public static final String PREFS_SHOW_CHANGELOG = "prefs.show.changelog"; - public static final String PREFS_COLUMNS_PORTRAIT = "prefs.columns.portrait"; - public static final String PREFS_COLUMNS_LANDSCAPE = "prefs.columns.landscape"; + public static final String PREFS_KNODEL_SERVER_URL = "prefs.general.restlet.api.url"; + public static final String PREFS_AT_LEAST_ONE_DATASOURCE = "prefs.at.least.one.datasource"; + public static final String PREFS_SHOW_DATASOURCE_SELECTION_HELP = "prefs.show.datasource.selection.help"; + public static final String PREFS_EULA_ACCEPTED = "prefs.eula.accepted"; + public static final String PREFS_EULA_TYPE = "prefs.eula.type"; + public static final String PREFS_SELECTED_DATASOURCE_ID = "prefs.selected.datasource.id"; + public static final String PREFS_GA_OPT_OUT = "prefs.google.analytics.opt.out"; + public static final String PREFS_LAST_VERSION = "prefs.last.version.code"; + public static final String PREFS_SHOW_CHANGELOG = "prefs.show.changelog"; + public static final String PREFS_COLUMNS_PORTRAIT = "prefs.columns.portrait"; + public static final String PREFS_COLUMNS_LANDSCAPE = "prefs.columns.landscape"; private static final String DEFAULT_PREF_SERVER_URL = "https://ics.hutton.ac.uk/buntata/v1.1/"; @@ -60,11 +61,10 @@ public static void setDefaults(final Context context) editor.putInt(PREFS_COLUMNS_PORTRAIT, 2); if (!preferences.contains(PREFS_COLUMNS_LANDSCAPE)) editor.putInt(PREFS_COLUMNS_LANDSCAPE, 3); + if (!preferences.contains(PREFS_SHOW_DATASOURCE_SELECTION_HELP)) + editor.putBoolean(PREFS_SHOW_DATASOURCE_SELECTION_HELP, true); -// if (!preferences.contains(PREFS_KNODEL_SERVER_URL)) -// { editor.putString(PREFS_KNODEL_SERVER_URL, DEFAULT_PREF_SERVER_URL); -// } editor.apply(); } diff --git a/app/src/main/res/layout-land/fragment_eula.xml b/app/src/main/res/layout-land/fragment_eula.xml new file mode 100644 index 0000000..21e2af1 --- /dev/null +++ b/app/src/main/res/layout-land/fragment_eula.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + +