From a53d6bfe007d64a7c39f6b36827afbf1ecfccac1 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Thu, 22 Sep 2016 00:11:40 +0200 Subject: [PATCH 1/5] Refactor/rewrite caching mechanism -> less inheritance, more composition --- .../common/LoaderToolbarActivity.java | 16 +- .../AssociationSelectPrefActivity.java | 4 +- .../hydra/activities/resto/MenuActivity.java | 2 +- .../java/be/ugent/zeus/hydra/cache/Cache.java | 72 ------- .../ugent/zeus/hydra/cache/CacheRequest.java | 47 ----- .../hydra/cache/CachedAsyncTaskLoader.java | 83 -------- .../cache/SystemCachedAsyncTaskLoader.java | 156 -------------- .../cache/exceptions/CacheException.java | 13 -- .../zeus/hydra/cache/file/CacheObject.java | 46 ----- .../zeus/hydra/cache/file/FileCache.java | 191 ------------------ .../zeus/hydra/cache/file/SerializeCache.java | 71 ------- .../be/ugent/zeus/hydra/caching/Cache.java | 106 ++++++++++ .../zeus/hydra/caching/CacheException.java | 13 ++ .../zeus/hydra/caching/CacheExecutor.java | 36 ++++ .../zeus/hydra/caching/CacheManager.java | 28 +++ .../ugent/zeus/hydra/caching/CacheObject.java | 69 +++++++ .../zeus/hydra/caching/CacheRequest.java | 29 +++ .../zeus/hydra/caching/GenericCache.java | 116 +++++++++++ .../hydra/caching/SerializableExecutor.java | 69 +++++++ .../zeus/hydra/fragments/InfoFragment.java | 2 - .../common/CachedLoaderFragment.java | 13 +- .../fragments/common/LoaderFragment.java | 4 +- .../home/CacheHomeLoaderCallback.java | 33 +-- .../fragments/home/HomeLoaderCallback.java | 2 +- .../hydra/fragments/home/MinervaCallback.java | 6 +- .../fragments/home/SpecialEventCallback.java | 6 +- .../minerva/CourseAgendaFragment.java | 2 +- .../minerva/CourseAnnouncementFragment.java | 2 +- .../fragments/minerva/MinervaFragment.java | 2 +- .../hydra/fragments/resto/RestoFragment.java | 1 - .../hydra/fragments/sko/TimelineFragment.java | 3 +- .../hydra/fragments/sko/VillageFragment.java | 3 +- .../hydra/loader/ErrorLoaderCallback.java | 25 --- .../zeus/hydra/loader/LoaderCallback.java | 54 ----- .../AbstractAsyncLoader.java | 12 +- .../hydra/loaders/ErrorLoaderCallback.java | 20 ++ .../{loader => loaders}/LoaderException.java | 2 +- .../hydra/loaders/RequestAsyncTaskLoader.java | 36 ++++ .../{loader => loaders}/ThrowableEither.java | 2 +- .../hydra/minerva/agenda/AgendaDaoLoader.java | 4 +- .../announcement/AnnouncementDaoLoader.java | 4 +- .../hydra/minerva/course/CourseDaoLoader.java | 4 +- .../hydra/requests/ActivitiesRequest.java | 3 +- .../hydra/requests/AssociationsRequest.java | 3 +- .../zeus/hydra/requests/InfoRequest.java | 5 +- .../zeus/hydra/requests/NewsRequest.java | 3 +- .../requests/SchamperArticlesRequest.java | 3 +- .../hydra/requests/SpecialEventRequest.java | 3 +- .../requests/common/CacheableRequest.java | 12 +- .../common/ProcessableCacheRequest.java | 68 +++++++ .../common/ProcessedCacheableRequest.java | 41 ---- .../zeus/hydra/requests/common/Request.java | 4 +- .../requests/common/SimpleCacheRequest.java | 26 +++ .../requests/executor/RequestExecutor.java | 99 --------- .../resto/RestoMenuOverviewRequest.java | 2 +- .../requests/resto/RestoMetaRequest.java | 2 +- .../resto/RestoSandwichesRequest.java | 2 +- .../hydra/requests/sko/LineupRequest.java | 2 +- .../requests/sko/StuVilExhibitorRequest.java | 2 +- .../hydra/requests/sko/TimelineRequest.java | 2 +- 60 files changed, 700 insertions(+), 991 deletions(-) delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/Cache.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/CacheRequest.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/CachedAsyncTaskLoader.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/SystemCachedAsyncTaskLoader.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/exceptions/CacheException.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/file/CacheObject.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/file/FileCache.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/cache/file/SerializeCache.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/CacheException.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/CacheExecutor.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/CacheManager.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/CacheObject.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/CacheRequest.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/caching/SerializableExecutor.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/loader/ErrorLoaderCallback.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/loader/LoaderCallback.java rename app/src/main/java/be/ugent/zeus/hydra/{loader => loaders}/AbstractAsyncLoader.java (89%) create mode 100644 app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java rename app/src/main/java/be/ugent/zeus/hydra/{loader => loaders}/LoaderException.java (88%) create mode 100644 app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java rename app/src/main/java/be/ugent/zeus/hydra/{loader => loaders}/ThrowableEither.java (97%) create mode 100644 app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessedCacheableRequest.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/requests/common/SimpleCacheRequest.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestExecutor.java diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java index a7e4a5144..1a4448487 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java @@ -1,5 +1,6 @@ package be.ugent.zeus.hydra.activities.common; +import android.content.Context; import android.os.Bundle; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; @@ -9,19 +10,21 @@ import android.view.View; import android.widget.ProgressBar; import android.widget.Toast; + import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.cache.CachedAsyncTaskLoader; -import be.ugent.zeus.hydra.loader.ErrorLoaderCallback; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ErrorLoaderCallback; +import be.ugent.zeus.hydra.loaders.RequestAsyncTaskLoader; +import be.ugent.zeus.hydra.loaders.ThrowableEither; +import be.ugent.zeus.hydra.requests.common.SimpleCacheRequest; import java.io.Serializable; /** - * Activity that uses the {@link CachedAsyncTaskLoader}. + * Activity that loads {@link be.ugent.zeus.hydra.caching.CacheRequest} using a loader. * * @author Niko Strijbol */ -public abstract class LoaderToolbarActivity extends ToolbarActivity implements ErrorLoaderCallback { +public abstract class LoaderToolbarActivity extends ToolbarActivity implements ErrorLoaderCallback { private static final String TAG = "LoaderToolbarActivity"; @@ -87,7 +90,8 @@ public void onLoadFinished(Loader> loader, ThrowableEither */ @Override public Loader> onCreateLoader(int id, Bundle args) { - return new CachedAsyncTaskLoader<>(getRequest(), getApplicationContext(), shouldRenew); + Context c = getApplicationContext(); + return new RequestAsyncTaskLoader<>(new SimpleCacheRequest<>(c, getRequest(), shouldRenew), c); } /** diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java index 9285ff486..6085c286f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java @@ -14,7 +14,7 @@ import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.common.LoaderToolbarActivity; -import be.ugent.zeus.hydra.cache.CacheRequest; +import be.ugent.zeus.hydra.caching.CacheRequest; import be.ugent.zeus.hydra.models.association.Association; import be.ugent.zeus.hydra.models.association.Associations; import be.ugent.zeus.hydra.recyclerview.adapters.MultiSelectListAdapter; @@ -100,7 +100,7 @@ public void receiveData(@NonNull Associations data) { } @Override - public CacheRequest getRequest() { + public CacheRequest getRequest() { return new AssociationsRequest(); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java index 6082707b6..37de9dc1d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java @@ -12,7 +12,7 @@ import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.resto.common.RestoWebsiteActivity; import be.ugent.zeus.hydra.fragments.resto.RestoFragment; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.models.resto.RestoMenu; import be.ugent.zeus.hydra.models.resto.RestoOverview; import be.ugent.zeus.hydra.requests.resto.RestoMenuOverviewRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/Cache.java b/app/src/main/java/be/ugent/zeus/hydra/cache/Cache.java deleted file mode 100644 index c8d62450b..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/Cache.java +++ /dev/null @@ -1,72 +0,0 @@ -package be.ugent.zeus.hydra.cache; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import be.ugent.zeus.hydra.requests.common.RequestFailureException; - -import java.io.Serializable; - -/** - * Generic interface for a cache. - * - * If the cache duration is set to {@link #NEVER}, the request will not be cached at all. - * - * @author Niko Strijbol - */ -@SuppressWarnings("unused") -public interface Cache { - - //Duration constants - long NEVER = -1; - long ONE_SECOND = 1000; - long ONE_MINUTE = 60 * ONE_SECOND; - long ONE_HOUR = 60 * ONE_MINUTE; - long ONE_DAY = 24 * ONE_HOUR; - long ONE_WEEK = 7 * ONE_DAY; - - /** - * Is the given cache expired or not? This reads the file from disk, so if you need it afterwards, you should read - * and check yourself. It is a bit more efficient than reading the file itself, so if you just need to check (large - * amount of files), you should use this. - * - * @param name Name of the cache file. - * @param duration Expiration to check against. - * - * @return True if it is expired, false otherwise. - */ - boolean isExpired(String name, long duration); - - /** - * Get data from a request. - * - * @param request The request to get data from. - * @param duration Expiration of the cache. - * @param Type of data from the request. - * @param Result of the request. - * - * @return The data - * - * @throws RequestFailureException If something goes wrong. - */ - @NonNull - R get(CacheRequest request, long duration) throws RequestFailureException; - - //This will be a default method once android supports it. - @NonNull - R get(CacheRequest request) throws RequestFailureException; - - //This will be a default method once android supports it. - - /** - * @return The data or null if the request failed. - * - * @see #get(CacheRequest) - */ - @Nullable - R getOrNull(CacheRequest request, long duration); - - //This will be a default method once android supports it. - @Nullable - R getOrNull(CacheRequest request); -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/CacheRequest.java b/app/src/main/java/be/ugent/zeus/hydra/cache/CacheRequest.java deleted file mode 100644 index bb2d4f39e..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/CacheRequest.java +++ /dev/null @@ -1,47 +0,0 @@ -package be.ugent.zeus.hydra.cache; - -import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.requests.common.Request; - -import java.io.Serializable; - -/** - * Represents a cacheable request for data. This is the class that provides the data for the {@link Cache}. - * - * Note that there is no guarantee for the order in which the methods of this class are called, if called at all. - * - * If your cache key or cache duration depends on the result, one solution is the perform the request as soon as - * one the of the methods is called, and saving the result locally in the class. - * - * The request itself must return data of type {@code T}. Sometimes it is necessary to do additional processing of the - * data. Because it is often handy to also do this on the background thread, the end result of the cache request should - * be data of type {@code } - * - * @param Type of data that is cached. - * @param Result of the request. - * - * @author Niko Strijbol - */ -public interface CacheRequest extends Request { - - /** - * @return The key under which the result will be stored by the {@link Cache}. - */ - @NonNull - String getCacheKey(); - - /** - * @return The maximal duration the data should be cached. - */ - long getCacheDuration(); - - /** - * Convert the data T from the cache to the result data R. - * - * @param data The data that the request produced. - * - * @return The data. - */ - @NonNull - R getData(@NonNull T data); -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/CachedAsyncTaskLoader.java b/app/src/main/java/be/ugent/zeus/hydra/cache/CachedAsyncTaskLoader.java deleted file mode 100644 index cbf0fb9a3..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/CachedAsyncTaskLoader.java +++ /dev/null @@ -1,83 +0,0 @@ -package be.ugent.zeus.hydra.cache; - -import android.content.Context; -import android.support.annotation.NonNull; - -import be.ugent.zeus.hydra.cache.file.SerializeCache; -import be.ugent.zeus.hydra.loader.AbstractAsyncLoader; -import be.ugent.zeus.hydra.loader.LoaderException; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; - -import java.io.Serializable; - -/** - * Cached task loader. The task loader requires a {@link CacheRequest} that will be executed. This loader uses a - * {@link SerializeCache} to cache the responses. - * - * For more information about the implementation of Loaders see the link below for a detailed guide. - * - * The loader has the option to ignore the cache. If set, the cache is ignored for the next request only. This request - * does save the data in the cache. All subsequent requests will honour the cache again. If you want to ignore the - * cache again, you need to call {@link #setNextRefresh()}. - * - * @param The result of the request. This value is cached, and so it must be Serializable. - * @param The result of the cached request. This enables a cached request to produce a result that is not serializable. - * - * @author Niko Strijbol - * @see Implementing loaders - */ -public class CachedAsyncTaskLoader extends AbstractAsyncLoader { - - private CacheRequest request; - private boolean refresh; - private final Cache cache; - - /** - * This loader will honour the cache settings of the request. - * - * @param request The request to execute. - * @param context The context. - */ - public CachedAsyncTaskLoader(CacheRequest request, Context context) { - this(request, context, false); - } - - /** - * This loader has the option to ignore the cache. - * - * @param request The request to execute. - * @param context The context. - * @param freshData If the data should be fresh or maybe cached. - */ - public CachedAsyncTaskLoader(CacheRequest request, Context context, boolean freshData) { - super(context); - this.request = request; - this.refresh = freshData; - this.cache = new SerializeCache(context); - } - - /** - * Sets the refresh flag. This means the next request will get new data, regardless of the cache. - */ - public void setNextRefresh() { - this.refresh = true; - } - - @NonNull - @Override - protected R getData() throws LoaderException { - try { - R content; - if (refresh) { - //Get new data - content = cache.get(request, Cache.NEVER); - } else { - content = cache.get(request); - } - this.refresh = false; - return content; - } catch (RequestFailureException e) { - throw new LoaderException(e); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/SystemCachedAsyncTaskLoader.java b/app/src/main/java/be/ugent/zeus/hydra/cache/SystemCachedAsyncTaskLoader.java deleted file mode 100644 index 9613893eb..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/SystemCachedAsyncTaskLoader.java +++ /dev/null @@ -1,156 +0,0 @@ -package be.ugent.zeus.hydra.cache; - -import android.content.AsyncTaskLoader; -import android.content.Context; - -import be.ugent.zeus.hydra.cache.file.SerializeCache; -import be.ugent.zeus.hydra.loader.ThrowableEither; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; - -import java.io.Serializable; - -/** - * A special version of the loader using the framework classes for the settings. This loader should not be preferred - * over the other one. - * - * Once we have API 23+, we might switch to this, but not before that. - * - * TODO: track fixes to compat preferences so we might use that instead. - * - * @see CachedAsyncTaskLoader - * - * @author Niko Strijbol - */ -public class SystemCachedAsyncTaskLoader extends AsyncTaskLoader> { - - private CacheRequest request; - private ThrowableEither data = null; - private boolean refresh; - private final Cache cache; - - /** - * This loader will honour the cache settings of the request. - * - * @param request The request to execute. - * @param context The context. - */ - public SystemCachedAsyncTaskLoader(CacheRequest request, Context context) { - this(request, context, false); - } - - /** - * This loader has the option to ignore the cache. - * - * @param request The request to execute. - * @param context The context. - * @param freshData If the data should be fresh or maybe cached. - */ - public SystemCachedAsyncTaskLoader(CacheRequest request, Context context, boolean freshData) { - super(context); - this.request = request; - this.refresh = freshData; - this.cache = new SerializeCache(context); - } - - /** - * Sets the refresh flag. This means the next request will get new data, regardless of the cache. - */ - public void setNextRefresh() { - this.refresh = true; - } - - /** - * {@inheritDoc} - * - * The data is loaded and cached by default. - * - * If the refresh flag is set, the existing cache is ignored, a new request is made and the result of that - * request is saved in the cache. - * - * @return The data or the error that occurred while getting the data. - */ - @Override - public ThrowableEither loadInBackground() { - - //Load the data, and set the refresh flag to false. - try { - R content; - if (refresh) { - //Get new data - content = cache.get(request, Cache.NEVER); - } else { - content = cache.get(request); - } - data = new ThrowableEither<>(content); - } catch (RequestFailureException e) { - data = new ThrowableEither<>(e); - } - this.refresh = false; - return data; - } - - /** - * Pass the data to the listener if the loader was not reset and the loader was started. - */ - @Override - public void deliverResult(ThrowableEither data) { - - // The Loader has been reset; ignore the result and invalidate the data. - if (isReset()) { - return; - } - - // Set the data in the loader. - this.data = data; - - // If the Loader is in a started state, deliver the results to the client. - if (isStarted()) { - super.deliverResult(data); - } - } - - /** - * Handles requests to start the loader. - */ - @Override - protected void onStartLoading() { - super.onStartLoading(); - - // If the data is available, deliver it. - if (data != null) { - deliverResult(data); - } - - // When the observer detects a change, it should call onContentChanged() on the Loader, which will - // cause the next call to takeContentChanged() to return true. If this is ever the case - // (or if the current data is null), we force a new load. - if (takeContentChanged() || data == null) { - forceLoad(); - } - } - - /** - * Handles requests to stop the loader. - */ - @Override - protected void onStopLoading() { - super.onStopLoading(); - - // Stop the request. - cancelLoad(); - } - - /** - * Handles a request to completely reset the loader. - */ - @Override - protected void onReset() { - super.onReset(); - - // Ensure the loader has stopped. - onStopLoading(); - - // Reset the data. - data = null; - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/exceptions/CacheException.java b/app/src/main/java/be/ugent/zeus/hydra/cache/exceptions/CacheException.java deleted file mode 100644 index a88ed2318..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/exceptions/CacheException.java +++ /dev/null @@ -1,13 +0,0 @@ -package be.ugent.zeus.hydra.cache.exceptions; - -/** - * Exception thrown when something goes wrong while reading/accessing cache that cannot be ignored. - * - * @author Niko Strijbol - */ -public class CacheException extends Exception { - - public CacheException(Throwable throwable) { - super(throwable); - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/file/CacheObject.java b/app/src/main/java/be/ugent/zeus/hydra/cache/file/CacheObject.java deleted file mode 100644 index 208ff2f61..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/file/CacheObject.java +++ /dev/null @@ -1,46 +0,0 @@ -package be.ugent.zeus.hydra.cache.file; - -import be.ugent.zeus.hydra.BuildConfig; -import org.joda.time.DateTime; -import org.joda.time.Duration; - -import java.io.Serializable; - -/** - * This is the actual object that is cached by the cache. It provides the date an object was cached. - * - * @see FileCache - * - * @author Niko Strijbol - */ -public class CacheObject implements Serializable { - - private DateTime lastUpdated; - private T data; - private int version = BuildConfig.VERSION_CODE; - - public CacheObject(T data) { - this.lastUpdated = DateTime.now(); - this.data = data; - } - - public void setLastUpdated(DateTime lastUpdated) { - this.lastUpdated = lastUpdated; - } - - public DateTime getLastUpdated() { - return lastUpdated; - } - - public boolean isExpired(Duration duration) { - return lastUpdated.plus(duration).isBeforeNow(); - } - - public T getData() { - return data; - } - - public int getVersion() { - return version; - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/file/FileCache.java b/app/src/main/java/be/ugent/zeus/hydra/cache/file/FileCache.java deleted file mode 100644 index 727ecf733..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/file/FileCache.java +++ /dev/null @@ -1,191 +0,0 @@ -package be.ugent.zeus.hydra.cache.file; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; - -import be.ugent.zeus.hydra.BuildConfig; -import be.ugent.zeus.hydra.cache.Cache; -import be.ugent.zeus.hydra.cache.CacheRequest; -import be.ugent.zeus.hydra.cache.exceptions.CacheException; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; -import org.joda.time.Duration; - -import java.io.File; -import java.io.FileFilter; -import java.io.Serializable; - -/** - * Simple cache that uses the file system to cache data. - * - * This does nothing asynchronously, so use your own threads and such. - * - * Note: concurrent access is currently untested. - * - * @author Niko Strijbol - */ -@SuppressWarnings("WeakerAccess") -public abstract class FileCache implements Cache { - - protected static final String TAG = "FileCache"; - - protected File directory; - protected Context context; - - public FileCache(File directory) { - this.directory = directory; - } - - /** - * Use the default cache dir. - */ - public FileCache(Context context) { - this(context.getCacheDir()); - } - - /** - * Write an object as JSON. The built in Gson writer does not work on android. - * - * @param data The data to write. - * - * @throws CacheException If something goes wrong that is not recoverable. - */ - protected abstract void write(String name, CacheObject data) throws CacheException; - - /** - * Read data from the cache. - * - * @param name Name of the file. - * @param The type of the CacheObject. - * @return The CacheObject. - * @throws CacheException If something went wrong, e.g. the file does not exist. - */ - @NonNull - protected abstract CacheObject read(String name) throws CacheException; - - /** - * Read data from the cache. - * - * @see #read(String) The main function. - - * @return The data or null if it does not exist. - */ - @Nullable - protected CacheObject readOrNull(String name) { - try { - return read(name); - } catch (CacheException e) { - return null; - } - } - - @Override - public boolean isExpired(String name, long duration) { - CacheObject cacheObject = readOrNull(name); - return cacheObject == null || duration == Cache.NEVER || cacheObject.isExpired(Duration.millis(duration)); - } - - /** - * @return True if the request should be renewed, for various reasons. - */ - private boolean shouldRenew(CacheObject object, long duration) { - return object == null //No cache - || duration == Cache.NEVER //Never cache - || object.isExpired(Duration.millis(duration)) //Expired cache - || object.getVersion() != BuildConfig.VERSION_CODE; //Old cache version - } - - @NonNull - @Override - public R get(CacheRequest request, long duration) throws RequestFailureException { - - //Else we do the caching. - CacheObject object = readOrNull(request.getCacheKey()); - T data; - - if(shouldRenew(object, duration)) { - Log.i(TAG, "New response for " + request); - data = request.performRequest(); - object = new CacheObject<>(data); - try { - write(request.getCacheKey(), object); - } catch (CacheException e) { - Log.w(TAG, e); - } - } else { - Log.i(TAG, "Cached response for " + request); - data = object.getData(); - } - - //Execute the transformation on the data. - return request.getData(data); - } - - @NonNull - @Override - public R get(CacheRequest request) throws RequestFailureException { - return get(request, request.getCacheDuration()); - } - - @Nullable - @Override - public R getOrNull(CacheRequest request, long duration) { - try { - return get(request, duration); - } catch (RequestFailureException e) { - return null; - } - } - - @Nullable - @Override - public R getOrNull(CacheRequest request) { - return getOrNull(request, request.getCacheDuration()); - } - - /** - * Delete all files starting with a given name. This means 'cache_' matches 'cache_', but also 'cache_other123'. - * Note that this will not scan recursively. - * - * @param start The name with which the files should start. - * @param context The context. The default cache directory will be used. - * - * @return The number of files deleted. - */ - public static int deleteStartingWith(final String start, Context context) { - return deleteStartingWith(start, context.getCacheDir()); - } - - /** - * Delete all files starting with a given name. This means 'cache_' matches 'cache_', but also 'cache_other123'. - * - * @param start The name with which the files should start. - * @param directory The directory to scan. - * - * @return The number of files deleted. - */ - public static int deleteStartingWith(final String start, File directory) { - - //Get files to delete - File[] toDelete = directory.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - Log.v(TAG, "File considered: " + pathname.getName()); - return pathname.getName().startsWith(start); - } - }); - - int counter = 0; - for(File f: toDelete) { - if(f.delete()) { - Log.d(TAG, "Deleted file: " + f.getName()); - counter++; - } - } - - Log.i(TAG, "Deleted " + counter + " files"); - - return counter; - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/cache/file/SerializeCache.java b/app/src/main/java/be/ugent/zeus/hydra/cache/file/SerializeCache.java deleted file mode 100644 index fc2d6060e..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/cache/file/SerializeCache.java +++ /dev/null @@ -1,71 +0,0 @@ -package be.ugent.zeus.hydra.cache.file; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.util.Log; - -import be.ugent.zeus.hydra.cache.exceptions.CacheException; - -import java.io.*; - -/** - * File cache that serializes the data. - * - * This class uses default serialization to save the objects. On Android, the default serializer is not fast. However, - * for the current use in the application (save some 'smaller' data), it is sufficient. It is also executed in a - * background thread, so worst case scenario, the user has to wait a little longer for the data (ns or ms). The - * alternative would be to use an external serializer library (such as fst[1]). This makes the app take up a lot more - * space, so we do not do that currently. If profiling suggests the serialisation here is really the bottleneck, which - * is unlikely since it is about network requests, we can easily switch to fst.- - * - * @author Niko Strijbol - * @see [1] fst - */ -public class SerializeCache extends FileCache { - - public SerializeCache(Context context) { - super(context); - } - - @Override - protected void write(String name, CacheObject data) throws CacheException { - ObjectOutputStream stream = null; - try { - stream = new ObjectOutputStream(new FileOutputStream(new File(directory, name))); - stream.writeObject(data); - } catch (IOException e) { - Log.e(TAG, "Error while writing.", e); - throw new CacheException(e); - } finally { - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - Log.e(TAG, "Error while closing stream", e); - } - } - } - - @NonNull - @Override - @SuppressWarnings("unchecked") - protected CacheObject read(String name) throws CacheException { - ObjectInputStream stream = null; - try { - stream = new ObjectInputStream(new FileInputStream(new File(directory, name))); - return (CacheObject) stream.readObject(); - } catch (ClassNotFoundException | IOException e) { - Log.w(TAG, "Error while reading.", e); - throw new CacheException(e); - } finally { - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - Log.e(TAG, "Error while closing stream", e); - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java b/app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java new file mode 100644 index 000000000..d5946bc4e --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java @@ -0,0 +1,106 @@ +package be.ugent.zeus.hydra.caching; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import be.ugent.zeus.hydra.requests.common.RequestFailureException; + +import java.io.Serializable; + +/** + * A cache. This is a map like data structure that holds keys and objects. While the keys must be strings, + * no restriction is applied on the objects. The objects are thus heterogeneous. + * + * This is a file cache for {@link CacheRequest}s. This is not a cache for a non-determined amount of keys. Use + * something like DiskLruCache for that. + * + * The cache is not thread safe. You should make sure to not write using the same key from different threads at the + * same time. Behavior in that scenario is undefined. + * + * The cache duration of an object is specified at retrieval. This simplifies forcing evicting the cache. + * + * If the cache duration is set to {@link #NEVER}, the request will not be cached at all. The duration of the cache has + * a millisecond precision. + * + * Note: using 0 as duration is undefined behavior. + * + * @author Niko Strijbol + */ +@SuppressWarnings("unused") +public interface Cache { + + /** + * Special value that indicates this request should not be cached. + */ + long NEVER = -1; + long ONE_SECOND = 1000; + long ONE_MINUTE = 60 * ONE_SECOND; + long ONE_HOUR = 60 * ONE_MINUTE; + long ONE_DAY = 24 * ONE_HOUR; + long ONE_WEEK = 7 * ONE_DAY; + + /** + * This method returns {@code true} if the cached value for the given key was saved longer than the given duration + * ago. When using {@link #NEVER} as duration, this methods always returns true. + * + * Keys for which there is no cache will also return true. + * + * @param key The key used to save the cache. + * @param duration Expiration to check against (in ms). + * + * @return True if it is expired, false otherwise. + */ + boolean isExpired(String key, long duration); + + /** + * Delete the cache for a given key. For a key that was not cached, this method does nothing. + * + * @param key The key of the cache. + * + * @return True if the file was deleted (or there was no file). + */ + boolean evict(String key); + + /** + * Get the data. Depending on the cache implementation, this might be cached data or fresh data. If new data is + * acquired from the request, it will be cached. + * + * If {@link #NEVER} is used as duration, existing cache will not be used. The new data will still be cached. + * + * This method will only throw an exception if no new data could be acquired. All other exceptions, such as errors + * while accessing the cache will fail silently and cause the existing cache to be invalidated. + * + * @param request The request to get data from. + * @param duration Expiration of the cache. + * + * @return The data, as if provided by the request. + * + * @throws RequestFailureException If the retrieval of new data fails. + */ + @NonNull + R get(CacheRequest request, long duration) throws RequestFailureException; + + /** + * Same as the other method, but uses the built-in cache duration of the request. + * + * @see #get(CacheRequest, long) + */ + @NonNull + R get(CacheRequest request) throws RequestFailureException; + + /** + * Same as the other get methods, but instead of throwing an exception, these methods return null. + * + * @see #get(CacheRequest, long) + */ + @Nullable + R getOrNull(CacheRequest request, long duration); + + /** + * Same as the other method, but uses the built-in cache duration of the request. + * + * @see #get(CacheRequest) + */ + @Nullable + R getOrNull(CacheRequest request); +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/CacheException.java b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheException.java new file mode 100644 index 000000000..9a5f301af --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheException.java @@ -0,0 +1,13 @@ +package be.ugent.zeus.hydra.caching; + +/** + * Exception thrown when the cache could not be read or saved. + * + * @author Niko Strijbol + */ +class CacheException extends Exception { + + public CacheException(Throwable throwable) { + super(throwable); + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/CacheExecutor.java b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheExecutor.java new file mode 100644 index 000000000..e95255e8b --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheExecutor.java @@ -0,0 +1,36 @@ +package be.ugent.zeus.hydra.caching; + +import android.support.annotation.NonNull; + +import java.io.Serializable; + +/** + * This interface defines the part of the {@link GenericCache} that will serialize the data and save it to disk. + * + * @author Niko Strijbol + */ +public interface CacheExecutor { + + /** + * Save the data to disk. After calling this method, the data should be cached in such a way that it can be read + * again by the same CacheExecutor implementation. + * + * @param key The key for the cache. + * @param data The data to cache. + + * @throws CacheException If the data could not be saved. + */ + void save(String key, CacheObject data) throws CacheException; + + /** + * Read data from disk. + * + * @param key The key for the cache. + * + * @return The data, read from disk. + * + * @throws CacheException If there is no data or the data could not be read. + */ + @NonNull + CacheObject read(String key) throws CacheException; +} diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/CacheManager.java b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheManager.java new file mode 100644 index 000000000..9d10167af --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheManager.java @@ -0,0 +1,28 @@ +package be.ugent.zeus.hydra.caching; + +import android.content.Context; + +/** + * Provide access to the cache instance. + * + * @author Niko Strijbol + */ +public class CacheManager { + + private static Cache cache; + + /** + * Get an instance of the default cache. + * + * @param context A context. + * + * @return The default cache. + */ + public static Cache defaultCache(Context context) { + if(cache == null) { + cache = new GenericCache(context); + } + + return cache; + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/CacheObject.java b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheObject.java new file mode 100644 index 000000000..e2716a2a3 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheObject.java @@ -0,0 +1,69 @@ +package be.ugent.zeus.hydra.caching; + +import be.ugent.zeus.hydra.BuildConfig; +import org.threeten.bp.Duration; +import org.threeten.bp.Instant; + +import java.io.Serializable; + +/** + * Wrapper object for a {@link Cache} to save additional metadata. This object is serializable, to enable use + * in file based caching. A side effect of this is that the encapsulated value also must be serializable. + * + * @author Niko Strijbol + */ +@SuppressWarnings({"WeakerAccess", "unused"}) +class CacheObject implements Serializable { + + private long lastUpdated; + private T data; + private int version; + + /** + * No-args constructor for ser + */ + public CacheObject() {} + + /** + * Create a new object. + * + * @param data The data to save. + */ + public CacheObject(T data) { + this.lastUpdated = Instant.now().toEpochMilli(); + this.data = data; + this.version = BuildConfig.VERSION_CODE; + } + + /** + * @return When the data was cached. + */ + public Instant getLastUpdated() { + return Instant.ofEpochMilli(this.lastUpdated); + } + + /** + * Check if the data is expired. Data is expired when it was cached longer ago than the given duration. + * + * @param duration The duration. + * + * @return True if the data is expired. + */ + public boolean isExpired(Duration duration) { + return getLastUpdated().plus(duration).isBefore(Instant.now()); + } + + /** + * @return The data. + */ + public T getData() { + return data; + } + + /** + * @return The app version this data was cached. + */ + public int getVersion() { + return version; + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/CacheRequest.java b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheRequest.java new file mode 100644 index 000000000..f088e495b --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/CacheRequest.java @@ -0,0 +1,29 @@ +package be.ugent.zeus.hydra.caching; + +import android.support.annotation.NonNull; + +import be.ugent.zeus.hydra.requests.common.Request; + +/** + * Encapsulates the data retrieval from a {@link Request} for a {@link Cache}. + * + * If data retrieval is necessary, the only method that is guaranteed to be called is the + * {@link #performRequest()} method. There is no guarantee any of the other methods will be called. + * + * @param Type of data that is cached. + * + * @author Niko Strijbol + */ +public interface CacheRequest extends Request { + + /** + * @return The key under which the result will be stored by the {@link Cache}. + */ + @NonNull + String getCacheKey(); + + /** + * @return The maximal duration the data should be cached. + */ + long getCacheDuration(); +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java b/app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java new file mode 100644 index 000000000..18b3c7641 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java @@ -0,0 +1,116 @@ +package be.ugent.zeus.hydra.caching; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; + +import be.ugent.zeus.hydra.BuildConfig; +import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import org.threeten.bp.Duration; + +import java.io.File; +import java.io.Serializable; + +/** + * A generic cache that uses a {@link GenericCache} the serialize and deserialize data to disk. If not supplied, the + * cache will use {@link SerializableExecutor} as a default. + * + * @author Niko Strijbol + */ +class GenericCache implements Cache { + + private static final String TAG = "GenericCache"; + + private final CacheExecutor executor; + private final File directory; + + public GenericCache(CacheExecutor executor, File cacheDirectory) { + this.executor = executor; + this.directory = cacheDirectory; + } + + public GenericCache(Context context) { + this.directory = context.getCacheDir(); + this.executor = new SerializableExecutor(this.directory); + } + + @Override + public boolean isExpired(String key, long duration) { + CacheObject cacheObject = readOrNull(key); + return cacheObject == null || duration == Cache.NEVER || cacheObject.isExpired(Duration.ofMillis(duration)); + } + + @Override + public boolean evict(String key) { + File file = new File(directory, key); + return !file.isFile() || file.delete(); + } + + @NonNull + @Override + public D get(CacheRequest request, long duration) throws RequestFailureException { + //Else we do the caching. + CacheObject object = readOrNull(request.getCacheKey()); + D data; + + if(shouldRefresh(object, duration)) { + Log.i(TAG, "New response for request " + request.getCacheKey()); + data = request.performRequest(); + object = new CacheObject<>(data); + try { + executor.save(request.getCacheKey(), object); + } catch (CacheException e) { + Log.w(TAG, "Could not cache request " + request.getCacheKey(), e); + } + } else { + Log.i(TAG, "Cached response for request" + request); + data = object.getData(); + } + + return data; + } + + @NonNull + @Override + public R get(CacheRequest request) throws RequestFailureException { + return get(request, request.getCacheDuration()); + } + + @Nullable + @Override + public R getOrNull(CacheRequest request, long duration) { + try { + return get(request, duration); + } catch (RequestFailureException e) { + Log.w(TAG, "Could not get cache for " + request.getCacheKey(), e); + return null; + } + } + + @Nullable + @Override + public R getOrNull(CacheRequest request) { + return getOrNull(request, request.getCacheDuration()); + } + + @Nullable + private CacheObject readOrNull(String key) { + try { + return executor.read(key); + } catch (CacheException e) { + Log.i(TAG, "Could not read cache for " + key, e); + return null; + } + } + + /** + * @return True if fresh data should be uses, for various reasons. + */ + private boolean shouldRefresh(CacheObject object, long duration) { + return object == null //No cache + || duration == Cache.NEVER //Never cache + || object.isExpired(Duration.ofMillis(duration)) //Expired cache + || object.getVersion() != BuildConfig.VERSION_CODE; //Old cache version + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/SerializableExecutor.java b/app/src/main/java/be/ugent/zeus/hydra/caching/SerializableExecutor.java new file mode 100644 index 000000000..bda6ac0d3 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/SerializableExecutor.java @@ -0,0 +1,69 @@ +package be.ugent.zeus.hydra.caching; + +import android.support.annotation.NonNull; +import android.util.Log; + +import java.io.*; + +/** + * Cache executor that uses default Java serialization to write/read objects. + * + * On Android, the default serializer is not fast. However, for the current use in the application (save some 'smaller' + * data), it is sufficient. It is also executed in a background thread, so worst case scenario, the user has to wait a + * little longer for the data (ns or ms). The alternative would be to use an external serializer library + * (such as fst[1]). This makes the app take up a lot more space, so we do not do that currently. + * If profiling suggests the serialisation here is really the bottleneck, which is unlikely since + * it is about network requests, we can easily switch to fst. + * + * @author Niko Strijbol + */ +class SerializableExecutor implements CacheExecutor { + + private static final String TAG = "SerializableExecutor"; + + private final File directory; + + public SerializableExecutor(File directory) { + this.directory = directory; + } + + @Override + public void save(String key, CacheObject data) throws CacheException { + ObjectOutputStream stream = null; + try { + stream = new ObjectOutputStream(new FileOutputStream(new File(directory, key))); + stream.writeObject(data); + } catch (IOException e) { + throw new CacheException(e); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + Log.w(TAG, "Error while closing stream.", e); + } + } + } + + @NonNull + @Override + @SuppressWarnings("unchecked") + public CacheObject read(String key) throws CacheException { + ObjectInputStream stream = null; + try { + stream = new ObjectInputStream(new FileInputStream(new File(directory, key))); + return (CacheObject) stream.readObject(); + } catch (ClassNotFoundException | IOException e) { + throw new CacheException(e); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + Log.w(TAG, "Error while closing stream.", e); + } + } + } +} diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java index 6ff25758f..fa785baed 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java @@ -12,8 +12,6 @@ import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.InfoSubItemActivity; import be.ugent.zeus.hydra.fragments.common.CachedLoaderFragment; -import be.ugent.zeus.hydra.cache.CacheRequest; -import be.ugent.zeus.hydra.fragments.common.LoaderFragment; import be.ugent.zeus.hydra.models.info.InfoItem; import be.ugent.zeus.hydra.models.info.InfoList; import be.ugent.zeus.hydra.recyclerview.adapters.InfoListAdapter; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java index ae86b33cd..3e22111cf 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java @@ -3,21 +3,22 @@ import android.os.Bundle; import android.support.v4.content.Loader; -import be.ugent.zeus.hydra.cache.CachedAsyncTaskLoader; -import be.ugent.zeus.hydra.loader.ErrorLoaderCallback; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ErrorLoaderCallback; +import be.ugent.zeus.hydra.loaders.RequestAsyncTaskLoader; +import be.ugent.zeus.hydra.loaders.ThrowableEither; +import be.ugent.zeus.hydra.requests.common.SimpleCacheRequest; import java.io.Serializable; /** - * Fragment that uses the {@link CachedAsyncTaskLoader}. + * Fragment for {@link SimpleCacheRequest}. * * The fragment supports a progress bar and refresh. The progress bar is automatically hidden. This fragment is * mostly used in the home screen. * * @author Niko Strijbol */ -public abstract class CachedLoaderFragment extends LoaderFragment implements ErrorLoaderCallback { +public abstract class CachedLoaderFragment extends LoaderFragment implements ErrorLoaderCallback { /** * Instantiate and return a new Loader for the given ID. @@ -29,6 +30,6 @@ public abstract class CachedLoaderFragment extends Loade */ @Override public Loader> onCreateLoader(int id, Bundle args) { - return new CachedAsyncTaskLoader<>(getRequest(), getContext(), shouldRenew); + return new RequestAsyncTaskLoader<>(new SimpleCacheRequest<>(getContext(), getRequest(), shouldRenew), getContext()); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java index 74adccd0a..dc2be7366 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java @@ -13,13 +13,13 @@ import android.widget.Toast; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.requests.executor.RequestCallback; import static be.ugent.zeus.hydra.utils.ViewUtils.$; /** - * Fragment that uses the {@link be.ugent.zeus.hydra.loader.AbstractAsyncLoader}. + * Fragment that loads {@link be.ugent.zeus.hydra.caching.CacheRequest} using a loader. * * The fragment supports a progress bar and refresh. The progress bar is automatically hidden. This fragment is * mostly used in the home screen. diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/CacheHomeLoaderCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/CacheHomeLoaderCallback.java index 4f6798383..4f452f75f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/CacheHomeLoaderCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/CacheHomeLoaderCallback.java @@ -5,12 +5,12 @@ import android.support.annotation.NonNull; import android.support.v4.content.Loader; -import be.ugent.zeus.hydra.cache.CacheRequest; -import be.ugent.zeus.hydra.cache.CachedAsyncTaskLoader; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.caching.CacheRequest; +import be.ugent.zeus.hydra.loaders.RequestAsyncTaskLoader; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.models.cards.HomeCard; import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; -import be.ugent.zeus.hydra.requests.common.ProcessedCacheableRequest; +import be.ugent.zeus.hydra.requests.common.ProcessableCacheRequest; import java.io.Serializable; import java.util.List; @@ -28,15 +28,7 @@ public CacheHomeLoaderCallback(Context context, HomeCardAdapter adapter, Fragmen @Override public Loader>> onCreateLoader(int id, Bundle args) { - return new CachedAsyncTaskLoader<>( - new ProcessedCacheableRequest>(getCacheRequest()) { - @NonNull - @Override - public List getData(@NonNull D data) { - return convertData(data); - } - }, - context, callback.shouldRefresh()); + return new RequestAsyncTaskLoader<>(new HomeRequest(context, getCacheRequest(), callback.shouldRefresh()), context); } /** @@ -50,5 +42,18 @@ public List getData(@NonNull D data) { /** * @return The request to execute. */ - protected abstract CacheRequest getCacheRequest(); + protected abstract CacheRequest getCacheRequest(); + + private class HomeRequest extends ProcessableCacheRequest> { + + private HomeRequest(Context context, CacheRequest request, boolean shouldRefresh) { + super(context, request, shouldRefresh); + } + + @NonNull + @Override + protected List transform(@NonNull D data) { + return convertData(data); + } + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java index af6163dfd..d7ad43abd 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java @@ -8,7 +8,7 @@ import android.support.v7.preference.PreferenceManager; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.models.cards.HomeCard; import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; import be.ugent.zeus.hydra.requests.executor.RequestCallback; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/MinervaCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/MinervaCallback.java index 36fc292c6..62e03b349 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/MinervaCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/MinervaCallback.java @@ -7,9 +7,9 @@ import android.util.Log; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.loader.AbstractAsyncLoader; -import be.ugent.zeus.hydra.loader.LoaderException; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.AbstractAsyncLoader; +import be.ugent.zeus.hydra.loaders.LoaderException; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.minerva.announcement.AnnouncementDao; import be.ugent.zeus.hydra.models.cards.HomeCard; import be.ugent.zeus.hydra.models.cards.MinervaAnnouncementsCard; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java index 09cdda8de..bd51ef3c6 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java @@ -7,9 +7,9 @@ import be.ugent.zeus.hydra.BuildConfig; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.loader.AbstractAsyncLoader; -import be.ugent.zeus.hydra.loader.LoaderException; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.AbstractAsyncLoader; +import be.ugent.zeus.hydra.loaders.LoaderException; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.models.cards.HomeCard; import be.ugent.zeus.hydra.models.cards.SpecialEventCard; import be.ugent.zeus.hydra.models.specialevent.SpecialEvent; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java index 6fb2c8941..ec118a413 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java @@ -12,7 +12,7 @@ import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.fragments.common.LoaderFragment; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.minerva.agenda.AgendaDao; import be.ugent.zeus.hydra.minerva.agenda.AgendaDaoLoader; import be.ugent.zeus.hydra.models.minerva.AgendaItem; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java index 8626b6ac7..5719c3507 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java @@ -16,7 +16,7 @@ import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.minerva.AnnouncementActivity; import be.ugent.zeus.hydra.fragments.common.LoaderFragment; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.minerva.announcement.AnnouncementDao; import be.ugent.zeus.hydra.minerva.announcement.AnnouncementDaoLoader; import be.ugent.zeus.hydra.models.minerva.Announcement; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java index c6594f32a..11c84e1f7 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java @@ -22,7 +22,7 @@ import be.ugent.zeus.hydra.minerva.auth.AccountUtils; import be.ugent.zeus.hydra.minerva.auth.MinervaConfig; import be.ugent.zeus.hydra.fragments.common.LoaderFragment; -import be.ugent.zeus.hydra.loader.ThrowableEither; +import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.minerva.announcement.AnnouncementDao; import be.ugent.zeus.hydra.minerva.course.CourseDao; import be.ugent.zeus.hydra.minerva.course.CourseDaoLoader; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java index a011be5ac..13e969495 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java @@ -17,7 +17,6 @@ import be.ugent.zeus.hydra.activities.resto.MetaActivity; import be.ugent.zeus.hydra.activities.resto.SandwichActivity; import be.ugent.zeus.hydra.fragments.common.CachedLoaderFragment; -import be.ugent.zeus.hydra.cache.CacheRequest; import be.ugent.zeus.hydra.models.resto.RestoMenu; import be.ugent.zeus.hydra.models.resto.RestoOverview; import be.ugent.zeus.hydra.requests.resto.RestoMenuOverviewRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java index b1d0b1b0f..049402337 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java @@ -9,7 +9,6 @@ import android.view.*; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.cache.CacheRequest; import be.ugent.zeus.hydra.fragments.common.CachedLoaderFragment; import be.ugent.zeus.hydra.models.sko.Timeline; import be.ugent.zeus.hydra.recyclerview.adapters.sko.TimelineAdapter; @@ -77,7 +76,7 @@ public void receiveData(@NonNull Timeline data) { } @Override - public CacheRequest getRequest() { + public TimelineRequest getRequest() { return new TimelineRequest(); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java index f15054524..515d704f3 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java @@ -8,7 +8,6 @@ import android.view.*; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.cache.CacheRequest; import be.ugent.zeus.hydra.fragments.common.RecyclerLoaderFragment; import be.ugent.zeus.hydra.models.sko.Exhibitor; import be.ugent.zeus.hydra.models.sko.Exhibitors; @@ -62,7 +61,7 @@ public void receiveData(@NonNull Exhibitors data) { } @Override - public CacheRequest getRequest() { + public StuVilExhibitorRequest getRequest() { return new StuVilExhibitorRequest(); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/loader/ErrorLoaderCallback.java b/app/src/main/java/be/ugent/zeus/hydra/loader/ErrorLoaderCallback.java deleted file mode 100644 index efe341e35..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/loader/ErrorLoaderCallback.java +++ /dev/null @@ -1,25 +0,0 @@ -package be.ugent.zeus.hydra.loader; - -import android.support.v4.app.LoaderManager; - -import be.ugent.zeus.hydra.cache.CacheRequest; -import be.ugent.zeus.hydra.requests.executor.RequestCallback; - -import java.io.Serializable; - -/** - * Defines additional methods a class should implement to work with {@link ThrowableEither} as a response. - * Note that this is not at all necessary, but may be a guide for correct implementation. - * - * When we can finally use default methods, this interface will provide a default implementation for the - * LoaderCallback. - * - * @author Niko Strijbol - */ -public interface ErrorLoaderCallback extends LoaderManager.LoaderCallbacks>, RequestCallback { - - /** - * @return The request that will be executed. - */ - CacheRequest getRequest(); -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loader/LoaderCallback.java b/app/src/main/java/be/ugent/zeus/hydra/loader/LoaderCallback.java deleted file mode 100644 index 7f57bb88e..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/loader/LoaderCallback.java +++ /dev/null @@ -1,54 +0,0 @@ -package be.ugent.zeus.hydra.loader; - -import android.content.Context; -import android.support.v4.content.Loader; -import be.ugent.zeus.hydra.activities.common.LoaderToolbarActivity; -import be.ugent.zeus.hydra.cache.CachedAsyncTaskLoader; -import be.ugent.zeus.hydra.fragments.common.CachedLoaderFragment; - -import java.io.Serializable; - -/** - * Same as {@link CachedLoaderFragment} and {@link LoaderToolbarActivity}, but without any parent. - * - * @author Niko Strijbol - */ -public abstract class LoaderCallback implements ErrorLoaderCallback { - - /** - * Called when a previously created loader has finished its load. - * - * @param loader The Loader that has finished. - * @param data The data generated by the Loader. - */ - @Override - public void onLoadFinished(Loader> loader, ThrowableEither data) { - if (data.hasError()) { - receiveError(data.getError()); - } else { - receiveData(data.getData()); - } - } - - /** - * Called when a previously created loader is being reset, and thus making its data unavailable. The application - * should at this point remove any references it has to the Loader's data. - * - * @param loader The Loader that is being reset. - */ - @Override - public void onLoaderReset(Loader> loader) { - loader.reset(); - } - - /** - * Instantiate and return a new Loader for the given ID. - * - * @param context The context. - * - * @return Return a new Loader instance that is ready to start loading. - */ - protected Loader> onCreateLoader(Context context, boolean shouldRefresh) { - return new CachedAsyncTaskLoader<>(getRequest(), context, shouldRefresh); - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loader/AbstractAsyncLoader.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/AbstractAsyncLoader.java similarity index 89% rename from app/src/main/java/be/ugent/zeus/hydra/loader/AbstractAsyncLoader.java rename to app/src/main/java/be/ugent/zeus/hydra/loaders/AbstractAsyncLoader.java index a5e44843f..44fbac849 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/loader/AbstractAsyncLoader.java +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/AbstractAsyncLoader.java @@ -1,4 +1,4 @@ -package be.ugent.zeus.hydra.loader; +package be.ugent.zeus.hydra.loaders; import android.content.Context; import android.support.annotation.NonNull; @@ -26,16 +26,6 @@ public AbstractAsyncLoader(Context context) { super(context); } - /** - * {@inheritDoc} - * - * The data is loaded and cached by default. - * - * If the refresh flag is set, the existing cache is ignored, a new request is made and the result of that - * request is saved in the cache. - * - * @return The data or the error that occurred while getting the data. - */ @Override public ThrowableEither loadInBackground() { diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java new file mode 100644 index 000000000..12dcd470f --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java @@ -0,0 +1,20 @@ +package be.ugent.zeus.hydra.loaders; + +import android.support.v4.app.LoaderManager; + +import be.ugent.zeus.hydra.caching.CacheRequest; +import be.ugent.zeus.hydra.requests.executor.RequestCallback; + +/** + * Defines additional methods a class should implement to work with {@link ThrowableEither} as a response. + * Note that this is not at all necessary, but may be a guide for correct implementation. + * + * @author Niko Strijbol + */ +public interface ErrorLoaderCallback extends LoaderManager.LoaderCallbacks>, RequestCallback { + + /** + * @return The request that will be executed. + */ + CacheRequest getRequest(); +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loader/LoaderException.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderException.java similarity index 88% rename from app/src/main/java/be/ugent/zeus/hydra/loader/LoaderException.java rename to app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderException.java index c69bc8500..09009a79b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/loader/LoaderException.java +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderException.java @@ -1,4 +1,4 @@ -package be.ugent.zeus.hydra.loader; +package be.ugent.zeus.hydra.loaders; /** * Exception thrown by {@link AbstractAsyncLoader} if the data cannot be loaded. diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java new file mode 100644 index 000000000..c76e4f2c7 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java @@ -0,0 +1,36 @@ +package be.ugent.zeus.hydra.loaders; + +import android.content.Context; +import android.support.annotation.NonNull; + +import be.ugent.zeus.hydra.requests.common.Request; +import be.ugent.zeus.hydra.requests.common.RequestFailureException; + +/** + * Loader to load data from a {@link Request}. + * + * @author Niko Strijbol + */ +public class RequestAsyncTaskLoader extends AbstractAsyncLoader { + + private final Request request; + + /** + * @param context The context. + * @param request The request to get the data from. + */ + public RequestAsyncTaskLoader(Request request, Context context) { + super(context); + this.request = request; + } + + @NonNull + @Override + protected D getData() throws LoaderException { + try { + return request.performRequest(); + } catch (RequestFailureException e) { + throw new LoaderException(e); + } + } +} diff --git a/app/src/main/java/be/ugent/zeus/hydra/loader/ThrowableEither.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/ThrowableEither.java similarity index 97% rename from app/src/main/java/be/ugent/zeus/hydra/loader/ThrowableEither.java rename to app/src/main/java/be/ugent/zeus/hydra/loaders/ThrowableEither.java index ee1205895..76b1b8d29 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/loader/ThrowableEither.java +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/ThrowableEither.java @@ -1,4 +1,4 @@ -package be.ugent.zeus.hydra.loader; +package be.ugent.zeus.hydra.loaders; import android.support.annotation.NonNull; diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDaoLoader.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDaoLoader.java index 51477bf0f..e1792b337 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDaoLoader.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDaoLoader.java @@ -3,8 +3,8 @@ import android.content.Context; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.loader.AbstractAsyncLoader; -import be.ugent.zeus.hydra.loader.LoaderException; +import be.ugent.zeus.hydra.loaders.AbstractAsyncLoader; +import be.ugent.zeus.hydra.loaders.LoaderException; import be.ugent.zeus.hydra.models.minerva.AgendaItem; import be.ugent.zeus.hydra.models.minerva.Course; diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDaoLoader.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDaoLoader.java index 258738c91..228c11382 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDaoLoader.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDaoLoader.java @@ -3,8 +3,8 @@ import android.content.Context; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.loader.AbstractAsyncLoader; -import be.ugent.zeus.hydra.loader.LoaderException; +import be.ugent.zeus.hydra.loaders.AbstractAsyncLoader; +import be.ugent.zeus.hydra.loaders.LoaderException; import be.ugent.zeus.hydra.models.minerva.Announcement; import be.ugent.zeus.hydra.models.minerva.Course; diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/course/CourseDaoLoader.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/course/CourseDaoLoader.java index 26c1ed06d..9d0c3fc1a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/course/CourseDaoLoader.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/course/CourseDaoLoader.java @@ -3,8 +3,8 @@ import android.content.Context; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.loader.AbstractAsyncLoader; -import be.ugent.zeus.hydra.loader.LoaderException; +import be.ugent.zeus.hydra.loaders.AbstractAsyncLoader; +import be.ugent.zeus.hydra.loaders.LoaderException; import be.ugent.zeus.hydra.models.minerva.Course; import java.util.List; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/ActivitiesRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/ActivitiesRequest.java index b511a0fc3..dc8365476 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/ActivitiesRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/ActivitiesRequest.java @@ -1,7 +1,8 @@ package be.ugent.zeus.hydra.requests; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; + +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.association.Activities; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/AssociationsRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/AssociationsRequest.java index ed4ac34e3..fe0384f41 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/AssociationsRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/AssociationsRequest.java @@ -1,7 +1,8 @@ package be.ugent.zeus.hydra.requests; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; + +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.association.Associations; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/InfoRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/InfoRequest.java index d38c2984a..43bbc27a7 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/InfoRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/InfoRequest.java @@ -1,7 +1,8 @@ package be.ugent.zeus.hydra.requests; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; + +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.info.InfoList; import be.ugent.zeus.hydra.requests.common.CacheableRequest; @@ -30,6 +31,6 @@ protected String getAPIUrl() { @Override public long getCacheDuration() { - return Cache.ONE_HOUR * 6; + return Cache.ONE_DAY; } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/NewsRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/NewsRequest.java index fa0c33bbb..1d2ca4999 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/NewsRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/NewsRequest.java @@ -1,7 +1,8 @@ package be.ugent.zeus.hydra.requests; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; + +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.association.News; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/SchamperArticlesRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/SchamperArticlesRequest.java index f5033b579..68e1c5f1e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/SchamperArticlesRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/SchamperArticlesRequest.java @@ -1,7 +1,8 @@ package be.ugent.zeus.hydra.requests; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; + +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.schamper.Articles; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialEventRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialEventRequest.java index 0b847b4d8..fe4264c14 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialEventRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialEventRequest.java @@ -1,7 +1,8 @@ package be.ugent.zeus.hydra.requests; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; + +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.specialevent.SpecialEventWrapper; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/CacheableRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/CacheableRequest.java index 365dabe6b..43ea633c8 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/CacheableRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/CacheableRequest.java @@ -1,8 +1,6 @@ package be.ugent.zeus.hydra.requests.common; -import android.support.annotation.NonNull; - -import be.ugent.zeus.hydra.cache.CacheRequest; +import be.ugent.zeus.hydra.caching.CacheRequest; import java.io.Serializable; @@ -14,7 +12,7 @@ * * @author feliciaan */ -public abstract class CacheableRequest extends AbstractRequest implements CacheRequest { +public abstract class CacheableRequest extends AbstractRequest implements CacheRequest { protected final String DSA_API_URL = "http://student.ugent.be/hydra/api/2.0/"; protected final String ZEUS_API_URL = "https://zeus.UGent.be/hydra/api/"; @@ -22,10 +20,4 @@ public abstract class CacheableRequest extends AbstractR public CacheableRequest(Class clazz) { super(clazz); } - - @NonNull - @Override - public T getData(@NonNull T data) { - return data; - } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java new file mode 100644 index 000000000..f970d9dac --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java @@ -0,0 +1,68 @@ +package be.ugent.zeus.hydra.requests.common; + +import android.content.Context; +import android.support.annotation.NonNull; + +import be.ugent.zeus.hydra.caching.Cache; +import be.ugent.zeus.hydra.caching.CacheManager; +import be.ugent.zeus.hydra.caching.CacheRequest; + +import java.io.Serializable; + +/** + * A request that takes a cache requests, gets the cached data, and then transforms that data. + * + * @author Niko Strijbol + */ +public abstract class ProcessableCacheRequest implements Request { + + private final Context context; + private final CacheRequest cacheRequest; + private boolean shouldRefresh; + + public ProcessableCacheRequest(Context context, CacheRequest request) { + this(context, request, false); + } + + public ProcessableCacheRequest(Context context, CacheRequest request, boolean shouldRefresh) { + this.context = context; + this.cacheRequest = request; + this.shouldRefresh = shouldRefresh; + } + + /** + * If this is set to true, the next call for data will force the cache request to use new data. After this call for + * data, the refresh flag is set to false automatically. + * + * @param shouldRefresh Should the next request for data be fresh. + */ + public void setShouldRefresh(boolean shouldRefresh) { + this.shouldRefresh = shouldRefresh; + } + + @NonNull + @Override + public R performRequest() throws RequestFailureException { + Cache cache = CacheManager.defaultCache(context); + D data; + + if(shouldRefresh) { + data = cache.get(cacheRequest, Cache.NEVER); + shouldRefresh = false; + } else { + data = cache.get(cacheRequest); + } + + return transform(data); + } + + /** + * Convert the cached data to something else. + * + * @param data The cached data. + * + * @return Something else. + */ + @NonNull + protected abstract R transform(@NonNull D data); +} diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessedCacheableRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessedCacheableRequest.java deleted file mode 100644 index a1377d1fe..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessedCacheableRequest.java +++ /dev/null @@ -1,41 +0,0 @@ -package be.ugent.zeus.hydra.requests.common; - -import android.support.annotation.NonNull; - -import be.ugent.zeus.hydra.cache.CacheRequest; - -import java.io.Serializable; - -/** - * Cacheable class that needs additional processing on the cached data. - * - * @param The cached data. - * @param The result of the request, the processed data. - * - * @author Niko Strijbol - */ -public abstract class ProcessedCacheableRequest implements CacheRequest { - - private final CacheRequest simpleRequest; - - protected ProcessedCacheableRequest(CacheRequest simpleRequest) { - this.simpleRequest = simpleRequest; - } - - @NonNull - @Override - public String getCacheKey() { - return simpleRequest.getCacheKey(); - } - - @Override - public long getCacheDuration() { - return simpleRequest.getCacheDuration(); - } - - @NonNull - @Override - public D performRequest() throws RequestFailureException { - return simpleRequest.performRequest(); - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java index e6735bb0c..39dbf234b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java @@ -1,7 +1,6 @@ package be.ugent.zeus.hydra.requests.common; import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; /** * The basis interface for a request. A request is something that returns data, not unlike a AsyncTask, but without @@ -12,8 +11,7 @@ public interface Request { /** - * Perform the request. This method provides the data that may or may not be cached, depending on the implementation - * of the used {@link Cache}. + * Perform the request. * * @return The data. * diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/SimpleCacheRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/SimpleCacheRequest.java new file mode 100644 index 000000000..5ad06282e --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/SimpleCacheRequest.java @@ -0,0 +1,26 @@ +package be.ugent.zeus.hydra.requests.common; + +import android.content.Context; +import android.support.annotation.NonNull; + +import be.ugent.zeus.hydra.caching.CacheRequest; + +import java.io.Serializable; + +/** + * A simple request that returns the data as it gets it. + * + * @author Niko Strijbol + */ +public class SimpleCacheRequest extends ProcessableCacheRequest { + + public SimpleCacheRequest(Context context, CacheRequest request, boolean shouldRefresh) { + super(context, request, shouldRefresh); + } + + @NonNull + @Override + protected D transform(@NonNull D data) { + return data; + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestExecutor.java b/app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestExecutor.java deleted file mode 100644 index 8f1f83a37..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestExecutor.java +++ /dev/null @@ -1,99 +0,0 @@ -package be.ugent.zeus.hydra.requests.executor; - -import android.content.Context; -import android.os.AsyncTask; - -import be.ugent.zeus.hydra.cache.CacheRequest; -import be.ugent.zeus.hydra.cache.file.SerializeCache; -import be.ugent.zeus.hydra.requests.common.Request; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; - -import java.io.Serializable; - -/** - * Utility methods relating to executing {@link Request}s. - * - * @author Niko Strijbol - */ -public class RequestExecutor { - - /** - * Execute a request async. - * - * @param request The request. - * @param callback The callback. - * @param The result. - * @return The task, should you wish to cancel it. - */ - public static AsyncTask executeAsync(final Request request, final RequestCallback callback) { - - RequestExecutorTask task = new RequestExecutorTask(callback) { - @Override - protected T getData() throws RequestFailureException { - return request.performRequest(); - } - }; - - return task.execute(); - } - - /** - * Execute a cached request async. - * - * @param request The request. - * @param callback The callback. - * @param The result. - * @return The task, should you wish to cancel it. - */ - public static AsyncTask executeAsync(Context context, final CacheRequest request, final RequestCallback callback) { - - final SerializeCache cache = new SerializeCache(context); - - RequestExecutorTask task = new RequestExecutorTask(callback) { - @Override - protected R getData() throws RequestFailureException { - return cache.get(request); - } - }; - - return task.execute(); - } - - /** - * Internal AsyncTask used to execute the request. - * @param - */ - private static abstract class RequestExecutorTask extends AsyncTask { - - private final RequestCallback callback; - private Throwable throwable; - - protected RequestExecutorTask(RequestCallback callback) { - super(); - this.callback = callback; - } - - @Override - protected T doInBackground(Void... voids) { - try { - return getData(); - } catch (RequestFailureException e) { - throwable = e; - return null; - } - } - - @Override - protected void onPostExecute(T t) { - if(callback != null) { - if (t != null) { - callback.receiveData(t); - } else { - callback.receiveError(throwable); - } - } - } - - protected abstract T getData() throws RequestFailureException; - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMenuOverviewRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMenuOverviewRequest.java index 29ce54d52..29534dc16 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMenuOverviewRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMenuOverviewRequest.java @@ -2,7 +2,7 @@ import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.resto.RestoOverview; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMetaRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMetaRequest.java index 6fc66c188..7a2793c01 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMetaRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoMetaRequest.java @@ -2,7 +2,7 @@ import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.resto.RestoMeta; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoSandwichesRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoSandwichesRequest.java index a50968904..c58ba796c 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoSandwichesRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/resto/RestoSandwichesRequest.java @@ -2,7 +2,7 @@ import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.resto.Sandwiches; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/sko/LineupRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/sko/LineupRequest.java index 73dafa739..42067dd19 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/sko/LineupRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/sko/LineupRequest.java @@ -2,7 +2,7 @@ import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.sko.Artists; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/sko/StuVilExhibitorRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/sko/StuVilExhibitorRequest.java index 0a7649ce4..6b60f5938 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/sko/StuVilExhibitorRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/sko/StuVilExhibitorRequest.java @@ -2,7 +2,7 @@ import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.sko.Exhibitors; import be.ugent.zeus.hydra.requests.common.CacheableRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/sko/TimelineRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/sko/TimelineRequest.java index b12df8ea0..a890cbbed 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/sko/TimelineRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/sko/TimelineRequest.java @@ -2,7 +2,7 @@ import android.support.annotation.NonNull; -import be.ugent.zeus.hydra.cache.Cache; +import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.models.sko.Timeline; import be.ugent.zeus.hydra.requests.common.CacheableRequest; From 3a4d10b0c3d850368e58780f2ce781802bc9ae43 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Thu, 22 Sep 2016 02:42:06 +0200 Subject: [PATCH 2/5] Switch from Jodat/Java to ThreeTenBP --- app/build.gradle | 1 - .../be/ugent/zeus/hydra/HydraApplication.java | 2 - .../activities/ActivityDetailActivity.java | 22 ++- .../hydra/activities/NewsArticleActivity.java | 2 +- .../activities/SchamperArticleActivity.java | 2 +- .../activities/minerva/AgendaActivity.java | 19 +-- .../minerva/AnnouncementActivity.java | 7 +- .../activities/minerva/AuthActivity.java | 6 +- .../hydra/activities/resto/MenuActivity.java | 21 +-- .../hydra/fragments/home/EventCallback.java | 6 +- .../hydra/fragments/home/NewsCallback.java | 8 +- .../fragments/home/RestoMenuCallback.java | 4 +- .../fragments/home/SpecialEventCallback.java | 6 +- .../hydra/fragments/resto/RestoFragment.java | 5 +- .../zeus/hydra/minerva/agenda/AgendaDao.java | 21 +-- .../minerva/announcement/AnnouncementDao.java | 10 +- .../announcement/AnnouncementExtractor.java | 25 +--- .../zeus/hydra/minerva/auth/AccountUtils.java | 10 +- .../minerva/auth/MinervaAuthenticator.java | 19 ++- .../zeus/hydra/minerva/sync/SyncAdapter.java | 10 +- .../hydra/models/association/Activity.java | 128 ++++++++++-------- .../hydra/models/association/NewsItem.java | 35 ++--- .../models/cards/AssociationActivityCard.java | 8 +- .../cards/MinervaAnnouncementsCard.java | 10 +- .../zeus/hydra/models/cards/NewsItemCard.java | 10 +- .../hydra/models/cards/RestoMenuCard.java | 10 +- .../zeus/hydra/models/cards/SchamperCard.java | 10 +- .../converters/AbstractDateJsonAdapter.java | 55 -------- .../converters/DateThreeTenAdapter.java | 63 +++++++++ .../models/converters/DateTimeAdapter.java | 60 -------- .../converters/ISO8601DateJsonAdapter.java | 10 -- .../converters/MinervaDateJsonAdapter.java | 10 -- .../converters/RestoDateJsonAdapter.java | 11 -- .../converters/TimeStampDateJsonAdapter.java | 11 -- .../zeus/hydra/models/minerva/AgendaItem.java | 46 +++---- .../hydra/models/minerva/Announcement.java | 29 ++-- .../hydra/models/minerva/MinervaDate.java | 44 ------ .../zeus/hydra/models/resto/RestoMenu.java | 20 ++- .../zeus/hydra/models/schamper/Article.java | 53 ++------ .../models/specialevent/SpecialEvent.java | 39 ++---- .../models/specialevent/SpecialEvents.java | 1 - .../adapters/ActivityListAdapter.java | 19 ++- .../adapters/minerva/AgendaAdapter.java | 12 +- .../viewholder/DateHeaderViewHolder.java | 8 +- .../viewholder/NewsItemViewHolder.java | 6 +- .../viewholder/SchamperViewHolder.java | 2 +- .../home/ActivityCardViewHolder.java | 2 +- .../viewholder/home/RestoCardViewHolder.java | 3 +- .../viewholder/home/SchamperViewHolder.java | 2 +- .../viewholder/minerva/AgendaViewHolder.java | 2 +- .../minerva/AnnouncementViewHolder.java | 4 +- .../hydra/requests/minerva/AgendaRequest.java | 15 +- .../be/ugent/zeus/hydra/utils/DateUtils.java | 37 +++-- .../be/ugent/zeus/hydra/utils/TtbUtils.java | 45 ++++++ 54 files changed, 424 insertions(+), 602 deletions(-) delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/converters/AbstractDateJsonAdapter.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/converters/DateThreeTenAdapter.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/converters/DateTimeAdapter.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/converters/ISO8601DateJsonAdapter.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/converters/MinervaDateJsonAdapter.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/converters/RestoDateJsonAdapter.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/converters/TimeStampDateJsonAdapter.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/models/minerva/MinervaDate.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/utils/TtbUtils.java diff --git a/app/build.gradle b/app/build.gradle index 8552fba4c..6b72d02f4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,7 +63,6 @@ dependencies { compile 'org.springframework.android:spring-android-rest-template:1.0.1.RELEASE' compile 'com.google.code.gson:gson:2.6.2' compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar' - compile 'net.danlew:android.joda:2.9.3.1' compile 'com.jakewharton.threetenabp:threetenabp:1.0.4' compile 'com.google.android.gms:play-services-analytics:9.4.0' compile 'com.squareup.picasso:picasso:2.5.2' diff --git a/app/src/main/java/be/ugent/zeus/hydra/HydraApplication.java b/app/src/main/java/be/ugent/zeus/hydra/HydraApplication.java index c0952c829..8cc7fa237 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/HydraApplication.java +++ b/app/src/main/java/be/ugent/zeus/hydra/HydraApplication.java @@ -8,7 +8,6 @@ import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; import com.jakewharton.threetenabp.AndroidThreeTen; -import net.danlew.android.joda.JodaTimeAndroid; /** * The Hydra application. @@ -23,7 +22,6 @@ public class HydraApplication extends Application { @Override public void onCreate() { super.onCreate(); - JodaTimeAndroid.init(this); AndroidThreeTen.init(this); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/ActivityDetailActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/ActivityDetailActivity.java index b37f0b2cd..158c4744a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/ActivityDetailActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/ActivityDetailActivity.java @@ -20,9 +20,8 @@ import be.ugent.zeus.hydra.models.association.Activity; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.format.DateTimeFormatter; /** * Activity to show details of an association's event. @@ -31,6 +30,8 @@ public class ActivityDetailActivity extends ToolbarActivity implements View.OnCl public static final String PARCEL_EVENT = "eventParcelable"; + private static final DateTimeFormatter formatHour = DateTimeFormatter.ofPattern("HH:mm"); + private static final DateTimeFormatter fullFormatter = DateTimeFormatter.ofPattern("E d MMM H:mm"); private static final String GENT = "51.3,3.44"; //The data @@ -75,21 +76,18 @@ protected void onCreate(Bundle savedInstanceState) { } if(event.getStart() != null) { - DateTimeFormatter startTimeFormatter = DateTimeFormat.forPattern("E d MMM H:mm"); - - DateTime start = new DateTime(event.getStart()); + LocalDateTime start = event.getLocalStart(); if (event.getEnd() != null) { - DateTime end = new DateTime(event.getEnd()); - if (start.dayOfYear() == end.dayOfYear() || start.plusHours(12).isAfter(end)) { + LocalDateTime end = event.getLocalEnd(); + if (start.getDayOfYear() == end.getDayOfYear() || start.plusHours(12).isAfter(end)) { // Use format day month start time - end time - DateTimeFormatter endTimeFormatter = DateTimeFormat.forPattern("H:mm"); - date.setText(String.format("%s - %s", startTimeFormatter.print(start), endTimeFormatter.print(end))); + date.setText(String.format("%s - %s", start.format(formatHour), end.format(formatHour))); } else { // Use format with two dates - date.setText(String.format("%s - %s",startTimeFormatter.print(start), startTimeFormatter.print(end))); + date.setText(String.format("%s - %s", start.format(fullFormatter), end.format(fullFormatter))); } } else { - date.setText(startTimeFormatter.print(start)); + date.setText(start.format(fullFormatter)); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/NewsArticleActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/NewsArticleActivity.java index 247f41a02..2cfdac783 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/NewsArticleActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/NewsArticleActivity.java @@ -39,7 +39,7 @@ protected void onCreate(Bundle savedInstanceState) { } if(article.getDate() != null) { - date.setText(DateUtils.relativeDateString(article.getDate(), date.getContext())); + date.setText(DateUtils.relativeDateTimeString(article.getDate(), date.getContext())); } if(article.getContent() != null) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/SchamperArticleActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/SchamperArticleActivity.java index 2324d05d5..17d8606c3 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/SchamperArticleActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/SchamperArticleActivity.java @@ -69,7 +69,7 @@ protected void onCreate(Bundle savedInstanceState) { String category = StringUtils.capitaliseFirst(article.getCategory()); if(article.getPubDate() != null) { - date.setText(DateUtils.relativeDateString(article.getPubDate(), date.getContext()) + " - " + category); + date.setText(DateUtils.relativeDateTimeString(article.getPubDate(), date.getContext()) + " - " + category); } else { date.setText(category); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AgendaActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AgendaActivity.java index 8487821b5..fcc7f6f85 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AgendaActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AgendaActivity.java @@ -14,10 +14,7 @@ import be.ugent.zeus.hydra.activities.common.ToolbarActivity; import be.ugent.zeus.hydra.models.minerva.AgendaItem; import be.ugent.zeus.hydra.utils.html.Utils; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Locale; +import org.threeten.bp.format.DateTimeFormatter; /** * @author Niko Strijbol @@ -27,7 +24,7 @@ public class AgendaActivity extends ToolbarActivity { public static final String ARG_AGENDA_ITEM = "argAgendaItem"; private AgendaItem agendaItem; - private static final DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm", new Locale("nl")); + private static final DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -56,13 +53,11 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { location.setText(agendaItem.getLocation()); } - String start = format.format(agendaItem.getStartDate()); - String end = format.format(agendaItem.getEndDate()); TextView startTime = $(R.id.agenda_time_start); - //TODO: deta - startTime.setText(start); TextView endTime = $(R.id.agenda_time_end); - endTime.setText(end); + + startTime.setText(agendaItem.getStartDate().format(format)); + endTime.setText(agendaItem.getEndDate().format(format)); TextView course = $(R.id.agenda_course); if(TextUtils.isEmpty(agendaItem.getCourse().getTitle())) { @@ -96,8 +91,8 @@ public boolean onCreateOptionsMenu(Menu menu) { private void addToCalendar() { Intent intent = new Intent(Intent.ACTION_INSERT) .setData(CalendarContract.Events.CONTENT_URI) - .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, agendaItem.getStartDate().getTime()) - .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, agendaItem.getEndDate().getTime()) + .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, agendaItem.getStartDate().toInstant().toEpochMilli()) + .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, agendaItem.getEndDate().toInstant().toEpochMilli()) .putExtra(CalendarContract.Events.TITLE, agendaItem.getTitle()) .putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY); diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AnnouncementActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AnnouncementActivity.java index 5a2f68ab3..e3cd36612 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AnnouncementActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AnnouncementActivity.java @@ -16,8 +16,7 @@ import be.ugent.zeus.hydra.utils.DateUtils; import be.ugent.zeus.hydra.utils.html.PicassoImageGetter; import be.ugent.zeus.hydra.utils.html.Utils; - -import java.util.Date; +import org.threeten.bp.ZonedDateTime; /** * Show a Minerva announcement. @@ -59,7 +58,7 @@ protected void onCreate(Bundle savedInstanceState) { } if(announcement.getDate() != null) { - date.setText(DateUtils.relativeDateString(announcement.getDate(), date.getContext())); + date.setText(DateUtils.relativeDateTimeString(announcement.getDate(), date.getContext())); } if(announcement.getContent() != null) { @@ -101,7 +100,7 @@ protected void onStart() { //Set the read date if needed if(!announcement.isRead()) { read = true; - announcement.setRead(new Date()); + announcement.setRead(ZonedDateTime.now()); } setResult(); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java index 8f5c3cab3..a1933429c 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java @@ -21,7 +21,7 @@ import be.ugent.zeus.hydra.requests.minerva.UserInfoRequest; import be.ugent.zeus.hydra.utils.customtabs.ActivityHelper; import be.ugent.zeus.hydra.utils.customtabs.CustomTabsHelper; -import org.joda.time.DateTime; +import org.threeten.bp.LocalDateTime; /** * An activity to prompt the user to authorise our access to the account. @@ -175,8 +175,8 @@ protected Intent doInBackground(String... strings) { manager.setPassword(account, result.getRefreshToken()); } - DateTime expiration = DateTime.now().plusSeconds(result.getExpiresIn()); - manager.setUserData(account, MinervaAuthenticator.EXP_DATE, MinervaAuthenticator.formatter.print(expiration)); + LocalDateTime expiration = LocalDateTime.now().plusSeconds(result.getExpiresIn()); + manager.setUserData(account, MinervaAuthenticator.EXP_DATE, expiration.format(MinervaAuthenticator.formatter)); manager.setAuthToken(account, authType, result.getAccessToken()); //Make intent for return value diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java index 37de9dc1d..7a2fbc08f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java @@ -17,11 +17,10 @@ import be.ugent.zeus.hydra.models.resto.RestoOverview; import be.ugent.zeus.hydra.requests.resto.RestoMenuOverviewRequest; import be.ugent.zeus.hydra.viewpager.MenuPagerAdapter; -import org.joda.time.DateTime; -import org.joda.time.DateTimeComparator; +import org.threeten.bp.LocalDate; +import org.threeten.bp.ZonedDateTime; import java.util.Collections; -import java.util.Date; /** * Display the menu of the resto in a separate view, similar to the old app. @@ -36,7 +35,7 @@ public class MenuActivity extends RestoWebsiteActivity { private MenuPagerAdapter pageAdapter; private ViewPager mViewPager; - private Date startDate; + private LocalDate startDate; @Override protected void onCreate(Bundle savedInstanceState) { @@ -67,11 +66,15 @@ public void onPageSelected(int position) { Intent intent = getIntent(); //Get the default start date - Date start = new Date(); - if(DateTime.now().isAfter(DateTime.now().withHourOfDay(RestoFragment.CLOSING_HOUR))) { - start = DateTime.now().plusDays(1).toDate(); + ZonedDateTime start = ZonedDateTime.now(); + if(start.isAfter(start.withHour(RestoFragment.CLOSING_HOUR))) { + start = start.plusDays(1); + } + if(intent.hasExtra(ARG_DATE)) { + startDate = (LocalDate) intent.getSerializableExtra(ARG_DATE); + } else { + startDate = start.toLocalDate(); } - startDate = new Date(intent.getLongExtra(ARG_DATE, start.getTime())); startLoader(); } @@ -95,7 +98,7 @@ public void receiveData(@NonNull RestoOverview data) { for (int i = 0; i < data.size(); i++) { RestoMenu menu = data.get(i); //Set the tab to this day! - if(DateTimeComparator.getDateOnlyInstance().compare(menu.getDate(), startDate) >= 0) { + if(menu.getDate().isEqual(startDate)) { mViewPager.setCurrentItem(i, false); break; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/EventCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/EventCallback.java index 3c2ba732d..f24e6700d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/EventCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/EventCallback.java @@ -10,9 +10,9 @@ import be.ugent.zeus.hydra.models.cards.HomeCard; import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; import be.ugent.zeus.hydra.requests.ActivitiesRequest; +import org.threeten.bp.ZonedDateTime; import java.util.ArrayList; -import java.util.Date; import java.util.List; /** @@ -39,11 +39,11 @@ protected int getErrorName() { @Override protected List convertData(@NonNull Activities data) { Activities.filterActivities(data, context); - Date date = new Date(); + ZonedDateTime now = ZonedDateTime.now(); List list = new ArrayList<>(); for (Activity activity: data) { AssociationActivityCard activityCard = new AssociationActivityCard(activity); - if (activityCard.getPriority() > 0 && activity.getEndDate().after(date)) { + if (activityCard.getPriority() > 0 && activity.getStart().isAfter(now)) { list.add(activityCard); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/NewsCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/NewsCallback.java index bc7b461f1..87b0426fa 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/NewsCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/NewsCallback.java @@ -10,7 +10,7 @@ import be.ugent.zeus.hydra.models.cards.NewsItemCard; import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; import be.ugent.zeus.hydra.requests.NewsRequest; -import org.joda.time.DateTime; +import org.threeten.bp.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -29,11 +29,11 @@ public NewsCallback(Context context, HomeCardAdapter adapter, FragmentCallback c @Override protected List convertData(@NonNull News data) { List newsItemCardList = new ArrayList<>(); - DateTime now = DateTime.now(); - DateTime sixMonthsAgo = now.minusMonths(6); + LocalDateTime now = LocalDateTime.now(); + LocalDateTime sixMonthsAgo = now.minusMonths(6); for (NewsItem item : data) { - if (sixMonthsAgo.isBefore(item.getDate().getTime())) { + if (sixMonthsAgo.isBefore(item.getLocalDate())) { newsItemCardList.add(new NewsItemCard(item)); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/RestoMenuCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/RestoMenuCallback.java index 8f9e4d36a..0a48ff200 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/RestoMenuCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/RestoMenuCallback.java @@ -10,7 +10,7 @@ import be.ugent.zeus.hydra.models.resto.RestoOverview; import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; import be.ugent.zeus.hydra.requests.resto.RestoMenuOverviewRequest; -import org.joda.time.DateTime; +import org.threeten.bp.LocalDate; import java.util.ArrayList; import java.util.List; @@ -30,7 +30,7 @@ public RestoMenuCallback(Context context, HomeCardAdapter adapter, FragmentCallb protected List convertData(@NonNull RestoOverview data) { List menuCardList = new ArrayList<>(); for (RestoMenu menu : data) { - if (new DateTime(menu.getDate()).withTimeAtStartOfDay().isAfterNow()) { + if (menu.getDate().isAfter(LocalDate.now())) { menuCardList.add(new RestoMenuCard(menu)); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java index bd51ef3c6..14c16b427 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java @@ -17,9 +17,9 @@ import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; import be.ugent.zeus.hydra.requests.SpecialRemoteEventRequest; import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import org.threeten.bp.ZonedDateTime; import java.util.ArrayList; -import java.util.Date; import java.util.List; /** @@ -68,14 +68,14 @@ protected List getData() throws LoaderException { private List convertData(@NonNull SpecialEventWrapper data) { List list = new ArrayList<>(); - Date now = new Date(); + ZonedDateTime now = ZonedDateTime.now(); for (SpecialEvent event: data.getSpecialEvents()) { //Events without date are always shown. if(event.getStart() == null && event.getEnd() == null) { list.add(new SpecialEventCard(event)); } else { - if ((event.getStart().before(now) && event.getEnd().after(now)) || (DEVELOPMENT && event.isDevelopment())) { + if ((event.getStart().isBefore(now) && event.getEnd().isAfter(now)) || (DEVELOPMENT && event.isDevelopment())) { list.add(new SpecialEventCard(event)); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java index 13e969495..275843cde 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java @@ -23,7 +23,7 @@ import be.ugent.zeus.hydra.utils.DateUtils; import be.ugent.zeus.hydra.utils.ViewUtils; import be.ugent.zeus.hydra.views.MenuTable; -import org.joda.time.DateTime; +import org.threeten.bp.LocalDateTime; import static be.ugent.zeus.hydra.utils.ViewUtils.$; @@ -125,7 +125,8 @@ public void receiveData(@NonNull RestoOverview data) { } RestoMenu menu = data.get(0); - if(DateTime.now().isAfter(DateTime.now().withHourOfDay(CLOSING_HOUR)) || DateTime.now().isAfter(new DateTime(menu.getDate()))) { + LocalDateTime now = LocalDateTime.now(); + if(now.isAfter(now.withHour(CLOSING_HOUR)) || now.isAfter(menu.getDate().atStartOfDay())) { menu = data.get(1); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java index 65ff7d1ec..859b9177a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java @@ -10,6 +10,7 @@ import be.ugent.zeus.hydra.minerva.database.Dao; import be.ugent.zeus.hydra.models.minerva.AgendaItem; import be.ugent.zeus.hydra.models.minerva.Course; +import be.ugent.zeus.hydra.utils.TtbUtils; import java.util.*; @@ -118,25 +119,17 @@ private static ContentValues getValues(AgendaItem a) { values.put(AgendaTable.COLUMN_COURSE, a.getCourseId()); values.put(AgendaTable.COLUMN_TITLE, a.getTitle()); values.put(AgendaTable.COLUMN_CONTENT, a.getContent()); - values.put(AgendaTable.COLUMN_START_DATE, a.getStartDate().getTime()); - values.put(AgendaTable.COLUMN_END_DATE, a.getEndDate().getTime()); + values.put(AgendaTable.COLUMN_START_DATE, TtbUtils.serialize(a.getStartDate())); + values.put(AgendaTable.COLUMN_END_DATE, TtbUtils.serialize(a.getEndDate())); values.put(AgendaTable.COLUMN_LOCATION, a.getLocation()); values.put(AgendaTable.COLUMN_TYPE, a.getType()); values.put(AgendaTable.COLUMN_LAST_EDIT_USER, a.getLastEditUser()); - values.put(AgendaTable.COLUMN_LAST_EDIT, a.getLastEdited().getTime()); + values.put(AgendaTable.COLUMN_LAST_EDIT, TtbUtils.serialize(a.getLastEdited())); values.put(AgendaTable.COLUMN_LAST_EDIT_TYPE, a.getLastEditType()); return values; } - private static boolean intToBool(int integer) { - return integer == 1; - } - - private static int boolToInt(boolean bool) { - return bool ? 1 : 0; - } - /** * A set of ids that are not in the course. * @@ -242,12 +235,12 @@ public List getAgendaForCourse(Course course, boolean reverse) { a.setItemId(cursor.getInt(columnIndex)); a.setTitle(cursor.getString(columnTitle)); a.setContent(cursor.getString(columnContent)); - a.setStartDate(new Date(cursor.getLong(columnStartDate))); - a.setEndDate(new Date(cursor.getLong(columnEndDate))); + a.setStartDate(TtbUtils.unserialize(cursor.getLong(columnStartDate))); + a.setEndDate(TtbUtils.unserialize(cursor.getLong(columnEndDate))); a.setLocation(cursor.getString(columnLocation)); a.setType(cursor.getString(columnType)); a.setLastEditUser(cursor.getString(columnLastEditUser)); - a.setLastEdited(new Date(cursor.getLong(columnLastEdit))); + a.setLastEdited(TtbUtils.unserialize(cursor.getLong(columnLastEdit))); a.setLastEditType(cursor.getString(columnLastEditType)); result.add(a); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDao.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDao.java index 7eaa95973..120f5faed 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDao.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementDao.java @@ -16,6 +16,8 @@ import be.ugent.zeus.hydra.minerva.database.Utils; import be.ugent.zeus.hydra.models.minerva.Announcement; import be.ugent.zeus.hydra.models.minerva.Course; +import be.ugent.zeus.hydra.utils.TtbUtils; +import org.threeten.bp.ZonedDateTime; import java.util.*; @@ -78,7 +80,7 @@ public List synchronisePartial(Collection announceme Log.d(TAG, "Removed " + rows + " stale announcements."); //If we are doing the first sync, we want to set everything to read. - Date now = new Date(); + ZonedDateTime now = ZonedDateTime.now(); final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context); final boolean showEmail = pref.getBoolean(MinervaFragment.PREF_ANNOUNCEMENT_NOTIFICATION_EMAIL, MinervaFragment.PREF_DEFAULT_ANNOUNCEMENT_NOTIFICATION_EMAIL); @@ -103,7 +105,7 @@ public List synchronisePartial(Collection announceme //If this is the first sync or it has an email and is set to email, add the read date. if(first || (!showEmail && announcement.isEmailSent())) { announcement.setRead(now); - value.put(AnnouncementTable.COLUMN_READ_DATE, now.getTime()); + value.put(AnnouncementTable.COLUMN_READ_DATE, TtbUtils.serialize(now)); } //If the announcement is unread, add it to the new announcements @@ -141,8 +143,8 @@ private static ContentValues getValues(Announcement a) { values.put(AnnouncementTable.COLUMN_EMAIL_SENT, boolToInt(a.isEmailSent())); values.put(AnnouncementTable.COLUMN_STICKY_UNTIL, 0); values.put(AnnouncementTable.COLUMN_LECTURER, a.getLecturer()); - values.put(AnnouncementTable.COLUMN_DATE, a.getDate().getTime()); - values.put(AnnouncementTable.COLUMN_READ_DATE, a.isRead() ? a.getDate().getTime() : 0); + values.put(AnnouncementTable.COLUMN_DATE, TtbUtils.serialize(a.getDate())); + values.put(AnnouncementTable.COLUMN_READ_DATE, a.isRead() ? TtbUtils.serialize(a.getDate()) : -1); return values; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementExtractor.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementExtractor.java index 9b2a5c1ea..f456efad5 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementExtractor.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementExtractor.java @@ -5,8 +5,7 @@ import be.ugent.zeus.hydra.models.minerva.Announcement; import be.ugent.zeus.hydra.models.minerva.Course; - -import java.util.Date; +import be.ugent.zeus.hydra.utils.TtbUtils; /** * Class to extract a {@link be.ugent.zeus.hydra.models.minerva.Announcement} from a {@link android.database.Cursor}. @@ -47,8 +46,8 @@ public Announcement getAnnouncement(Course course) { a.setContent(cursor.getString(columnContent)); a.setEmailSent(intToBool(cursor.getInt(columnEmailSent))); a.setLecturer(cursor.getString(columnLecturer)); - a.setDate(longToDate(cursor.getLong(columnDate))); - a.setRead(longToDate(cursor.getLong(columnReadDate))); + a.setDate(TtbUtils.unserialize(cursor.getLong(columnDate))); + a.setRead(TtbUtils.unserialize(cursor.getLong(columnReadDate))); return a; } @@ -167,22 +166,4 @@ public AnnouncementExtractor build() { public static boolean intToBool(int integer) { return integer == 1; } - - /** - * @return 1 if {@code bool} is true, else 0. - */ - public static int boolToInt(boolean bool) { - return bool ? 1 : 0; - } - - /** - * @return Null if {@code date} is 0, else the date represented by this long. - */ - public static Date longToDate(long date) { - if(date == 0) { - return null; - } else { - return new Date(date); - } - } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/AccountUtils.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/AccountUtils.java index f57d2e18c..f2c7393b7 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/AccountUtils.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/AccountUtils.java @@ -16,7 +16,7 @@ import org.apache.oltu.oauth2.client.request.OAuthClientRequest; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.types.ResponseType; -import org.joda.time.DateTime; +import org.threeten.bp.LocalDateTime; import java.io.IOException; @@ -129,8 +129,8 @@ public static Bundle syncAuthCode(Context context, Account account) { //If the bundle contains an authorisation code. if(result.containsKey(AccountManager.KEY_AUTHTOKEN)) { //Check the expiration date - DateTime expires = getExpirationDate(manager, account); - DateTime now = DateTime.now(); + LocalDateTime expires = getExpirationDate(manager, account); + LocalDateTime now = LocalDateTime.now(); String token = result.getString(AccountManager.KEY_AUTHTOKEN); @@ -168,8 +168,8 @@ public static Account getAccount(Context context) { * @param account The account to get the date for. * @return The date. */ - public static DateTime getExpirationDate(AccountManager manager, Account account) { + public static LocalDateTime getExpirationDate(AccountManager manager, Account account) { String exp = manager.getUserData(account, EXP_DATE); - return MinervaAuthenticator.formatter.parseDateTime(exp); + return LocalDateTime.parse(exp, MinervaAuthenticator.formatter); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java index e24b6eeea..785472a2e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java @@ -8,13 +8,12 @@ import android.util.Log; import be.ugent.zeus.hydra.activities.common.ToolbarAccountAuthenticatorActivity; -import be.ugent.zeus.hydra.minerva.auth.models.BearerToken; import be.ugent.zeus.hydra.activities.minerva.AuthActivity; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.minerva.auth.models.BearerToken; import be.ugent.zeus.hydra.requests.common.Request; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; +import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.format.DateTimeFormatter; /** * Authenticator to save Minerva account details in the AccountManager. Minerva uses OAuth2 authentication with @@ -51,7 +50,7 @@ public class MinervaAuthenticator extends AbstractAccountAuthenticator { public static final String EXP_DATE = "expDate"; private static final String EXP_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; - public static final DateTimeFormatter formatter = DateTimeFormat.forPattern(EXP_DATE_FORMAT); + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(EXP_DATE_FORMAT); private Context mContext; private AccountManager manager; @@ -100,8 +99,8 @@ public Bundle getAuthToken(AccountAuthenticatorResponse response, Account accoun //Check the expiration date if(!TextUtils.isEmpty(accessToken)) { - DateTime expires = formatter.parseDateTime(manager.getUserData(account, EXP_DATE)); - DateTime now = DateTime.now(); + LocalDateTime expires = LocalDateTime.parse(manager.getUserData(account, EXP_DATE), formatter); + LocalDateTime now = LocalDateTime.now(); //The token is invalid, so get get new one. if(now.isAfter(expires)) { @@ -164,8 +163,8 @@ private String getRefreshAccessToken(Account account, String refreshToken) { } - DateTime expiration = DateTime.now().plusSeconds(token.getExpiresIn()); - manager.setUserData(account, EXP_DATE, formatter.print(expiration)); + LocalDateTime expiration = LocalDateTime.now().plusSeconds(token.getExpiresIn()); + manager.setUserData(account, EXP_DATE, expiration.format(formatter)); return token.getAccessToken(); } catch (RequestFailureException e) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java index 3128e0157..d0bf7d475 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java @@ -23,8 +23,10 @@ import be.ugent.zeus.hydra.requests.minerva.AgendaRequest; import be.ugent.zeus.hydra.requests.minerva.CoursesMinervaRequest; import be.ugent.zeus.hydra.requests.minerva.WhatsNewRequest; -import org.joda.time.DateTime; import org.springframework.http.converter.HttpMessageNotReadableException; +import org.threeten.bp.LocalDate; +import org.threeten.bp.ZoneId; +import org.threeten.bp.ZonedDateTime; import java.util.Collection; @@ -87,11 +89,11 @@ public void onPerformSync(Account account, Bundle extras, String authority, Cont //Synchronise agenda AgendaRequest agendaRequest = new AgendaRequest(getContext(), account, null); - DateTime now = DateTime.now(); + ZonedDateTime now = LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()); //Start time - agendaRequest.setStart(now.withTimeAtStartOfDay().toDate()); + agendaRequest.setStart(now); //End time. We take 1 month (+1 day for the start time). - agendaRequest.setEnd(now.plusMonths(1).plusDays(1).withTimeAtStartOfDay().toDate()); + agendaRequest.setEnd(now.plusMonths(1).plusDays(1)); agendaDao.replace(agendaRequest.performRequest().getItems()); diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/association/Activity.java b/app/src/main/java/be/ugent/zeus/hydra/models/association/Activity.java index 50a53a621..08da19cd9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/association/Activity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/association/Activity.java @@ -2,13 +2,17 @@ import android.os.Parcel; import android.os.Parcelable; + import be.ugent.zeus.hydra.models.converters.BooleanJsonAdapter; -import be.ugent.zeus.hydra.models.converters.TimeStampDateJsonAdapter; +import be.ugent.zeus.hydra.models.converters.ZonedThreeTenAdapter; +import be.ugent.zeus.hydra.utils.DateUtils; +import be.ugent.zeus.hydra.utils.TtbUtils; import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.ZonedDateTime; import java.io.Serializable; -import java.util.Date; /** * Created by feliciaan on 27/01/16. @@ -16,10 +20,10 @@ public class Activity implements Parcelable, Serializable { private String title; - @JsonAdapter(TimeStampDateJsonAdapter.class) - private Date start; - @JsonAdapter(TimeStampDateJsonAdapter.class) - private Date end; + @JsonAdapter(ZonedThreeTenAdapter.class) + private ZonedDateTime start; + @JsonAdapter(ZonedThreeTenAdapter.class) + private ZonedDateTime end; private String location; private double latitude; private double longitude; @@ -31,38 +35,28 @@ public class Activity implements Parcelable, Serializable { private boolean highlighted; private Association association; - protected Activity(Parcel in) { - title = in.readString(); - start = new Date(in.readLong()); - end = new Date(in.readLong()); - location = in.readString(); - latitude = in.readDouble(); - longitude = in.readDouble(); - description = in.readString(); - url = in.readString(); - facebookId = in.readString(); - highlighted = in.readByte() == 1; - association = in.readParcelable(Association.class.getClassLoader()); - } - - public static final Creator CREATOR = new Creator() { - @Override - public Activity createFromParcel(Parcel in) { - return new Activity(in); - } - - @Override - public Activity[] newArray(int size) { - return new Activity[size]; - } - }; - - public Date getStartDate() { - return start; - } - - public Date getEndDate() { - return end; + /** + * Get the start date, converted to the local time zone. The resulting DateTime is the time as it is used + * in the current time zone. + * + * This value is calculated every time, so if you need it a lot, cache it in a local variable. + * + * @return The converted start date. + */ + public LocalDateTime getLocalStart() { + return DateUtils.toLocalDateTime(getStart()); + } + + /** + * Get the end date, converted to the local time zone. The resulting DateTime is the time as it is used + * in the current time zone. + * + * This value is calculated every time, so if you need it a lot, cache it in a local variable. + * + * @return The converted end date. + */ + public LocalDateTime getLocalEnd() { + return DateUtils.toLocalDateTime(getEnd()); } public String getTitle() { @@ -73,19 +67,19 @@ public void setTitle(String title) { this.title = title; } - public Date getStart() { + public ZonedDateTime getStart() { return start; } - public void setStart(Date start) { + public void setStart(ZonedDateTime start) { this.start = start; } - public Date getEnd() { + public ZonedDateTime getEnd() { return end; } - public void setEnd(Date end) { + public void setEnd(ZonedDateTime end) { this.end = end; } @@ -172,17 +166,45 @@ public int describeContents() { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(title); - dest.writeLong(start != null ? start.getTime() : 0); - dest.writeLong(end != null ? end.getTime() : 0); - dest.writeString(location); - dest.writeDouble(latitude); - dest.writeDouble(longitude); - dest.writeString(description); - dest.writeString(url); - dest.writeString(facebookId); - dest.writeByte((byte) (highlighted ? 1 : 0)); - dest.writeParcelable(association, flags); + dest.writeString(this.title); + dest.writeLong(TtbUtils.serialize(this.start)); + dest.writeLong(TtbUtils.serialize(this.end)); + dest.writeString(this.location); + dest.writeDouble(this.latitude); + dest.writeDouble(this.longitude); + dest.writeString(this.description); + dest.writeString(this.url); + dest.writeString(this.facebookId); + dest.writeByte(this.highlighted ? (byte) 1 : (byte) 0); + dest.writeParcelable(this.association, flags); + } + + public Activity() { + } + protected Activity(Parcel in) { + this.title = in.readString(); + this.start = TtbUtils.unserialize(in.readLong()); + this.end = TtbUtils.unserialize(in.readLong()); + this.location = in.readString(); + this.latitude = in.readDouble(); + this.longitude = in.readDouble(); + this.description = in.readString(); + this.url = in.readString(); + this.facebookId = in.readString(); + this.highlighted = in.readByte() != 0; + this.association = in.readParcelable(Association.class.getClassLoader()); } + + public static final Creator CREATOR = new Creator() { + @Override + public Activity createFromParcel(Parcel source) { + return new Activity(source); + } + + @Override + public Activity[] newArray(int size) { + return new Activity[size]; + } + }; } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/association/NewsItem.java b/app/src/main/java/be/ugent/zeus/hydra/models/association/NewsItem.java index d6d2fa6b6..4b4fa7554 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/association/NewsItem.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/association/NewsItem.java @@ -2,23 +2,28 @@ import android.os.Parcel; import android.os.Parcelable; + import be.ugent.zeus.hydra.models.converters.BooleanJsonAdapter; -import be.ugent.zeus.hydra.models.converters.TimeStampDateJsonAdapter; +import be.ugent.zeus.hydra.models.converters.ZonedThreeTenAdapter; +import be.ugent.zeus.hydra.utils.DateUtils; +import be.ugent.zeus.hydra.utils.TtbUtils; import com.google.gson.annotations.JsonAdapter; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.ZonedDateTime; import java.io.Serializable; -import java.util.Date; /** * Created by feliciaan on 04/02/16. */ public class NewsItem implements Serializable, Parcelable { + private int id; private String title; private String content; private Association association; - @JsonAdapter(TimeStampDateJsonAdapter.class) - private Date date; + @JsonAdapter(ZonedThreeTenAdapter.class) + private ZonedDateTime date; @JsonAdapter(BooleanJsonAdapter.class) private boolean highlighted; @@ -54,20 +59,20 @@ public void setAssociation(Association association) { this.association = association; } - public Date getDate() { + public ZonedDateTime getDate() { return date; } - public void setDate(Date date) { + public void setDate(ZonedDateTime date) { this.date = date; } - public boolean isHighlighted() { - return highlighted; + public LocalDateTime getLocalDate() { + return DateUtils.toLocalDateTime(getDate()); } - public void setHighlighted(boolean highlighted) { - this.highlighted = highlighted; + public boolean isHighlighted() { + return highlighted; } @Override @@ -81,20 +86,16 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.title); dest.writeString(this.content); dest.writeParcelable(this.association, flags); - dest.writeLong(this.date != null ? this.date.getTime() : -1); + dest.writeLong(TtbUtils.serialize(this.date)); dest.writeByte(this.highlighted ? (byte) 1 : (byte) 0); } - public NewsItem() { - } - protected NewsItem(Parcel in) { this.id = in.readInt(); this.title = in.readString(); this.content = in.readString(); this.association = in.readParcelable(Association.class.getClassLoader()); - long tmpDate = in.readLong(); - this.date = tmpDate == -1 ? null : new Date(tmpDate); + this.date = TtbUtils.unserialize(in.readLong()); this.highlighted = in.readByte() != 0; } @@ -109,4 +110,4 @@ public NewsItem[] newArray(int size) { return new NewsItem[size]; } }; -} +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/cards/AssociationActivityCard.java b/app/src/main/java/be/ugent/zeus/hydra/models/cards/AssociationActivityCard.java index 0a599d31f..7100b56c3 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/cards/AssociationActivityCard.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/cards/AssociationActivityCard.java @@ -1,8 +1,8 @@ package be.ugent.zeus.hydra.models.cards; import be.ugent.zeus.hydra.models.association.Activity; -import org.joda.time.DateTime; -import org.joda.time.Duration; +import org.threeten.bp.Duration; +import org.threeten.bp.ZonedDateTime; /** * Created by silox on 18/04/16. @@ -17,8 +17,8 @@ public AssociationActivityCard(Activity activity) { @Override public int getPriority() { - Duration duration = new Duration(new DateTime(), new DateTime(getActivity().getStartDate())); - return 950 - Math.max(0, (int)duration.getStandardHours()) * 4; //see 10 days in to the future + Duration duration = Duration.between(ZonedDateTime.now(), activity.getStart()); + return 950 - Math.max(0, (int) duration.toHours()) * 4; //see 10 days in to the future } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/cards/MinervaAnnouncementsCard.java b/app/src/main/java/be/ugent/zeus/hydra/models/cards/MinervaAnnouncementsCard.java index 57bbccc55..a19d9e2ee 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/cards/MinervaAnnouncementsCard.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/cards/MinervaAnnouncementsCard.java @@ -2,8 +2,8 @@ import be.ugent.zeus.hydra.models.minerva.Announcement; import be.ugent.zeus.hydra.models.minerva.Course; -import org.joda.time.DateTime; -import org.joda.time.Duration; +import org.threeten.bp.Duration; +import org.threeten.bp.ZonedDateTime; import java.util.List; @@ -22,9 +22,9 @@ public MinervaAnnouncementsCard(List announcement, Course course) @Override public int getPriority() { - DateTime date = new DateTime(this.getAnnouncements().get(0).getDate()); - Duration duration = new Duration(date, new DateTime()); - return (int) (1000 - (duration.getStandardDays() * 100)); + ZonedDateTime date = this.getAnnouncements().get(0).getDate(); + Duration duration = Duration.between(date, ZonedDateTime.now()); + return (int) (1000 - (duration.toDays() * 100)); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/cards/NewsItemCard.java b/app/src/main/java/be/ugent/zeus/hydra/models/cards/NewsItemCard.java index 56816210d..739ea5102 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/cards/NewsItemCard.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/cards/NewsItemCard.java @@ -1,8 +1,8 @@ package be.ugent.zeus.hydra.models.cards; import be.ugent.zeus.hydra.models.association.NewsItem; -import org.joda.time.DateTime; -import org.joda.time.Duration; +import org.threeten.bp.Duration; +import org.threeten.bp.ZonedDateTime; /** * Created by feliciaan on 18/06/16. @@ -23,9 +23,9 @@ public int getPriority() { } else { multiplier = 75; } - DateTime jodaDate = new DateTime(this.getNewsItem().getDate()); - Duration duration = new Duration(new DateTime(), jodaDate); - return (int) (1000 - (duration.getStandardDays() * multiplier)); + ZonedDateTime date = getNewsItem().getDate(); + Duration duration = Duration.between(ZonedDateTime.now(), date); + return (int) (1000 - (duration.toDays() * multiplier)); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/cards/RestoMenuCard.java b/app/src/main/java/be/ugent/zeus/hydra/models/cards/RestoMenuCard.java index 9a323cb14..08e67e25d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/cards/RestoMenuCard.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/cards/RestoMenuCard.java @@ -1,8 +1,8 @@ package be.ugent.zeus.hydra.models.cards; import be.ugent.zeus.hydra.models.resto.RestoMenu; -import org.joda.time.DateTime; -import org.joda.time.Duration; +import org.threeten.bp.LocalDate; +import org.threeten.bp.Period; /** * Created by silox on 18/04/16. @@ -17,9 +17,9 @@ public RestoMenuCard(RestoMenu restoMenu) { @Override public int getPriority() { - DateTime jodaDate = new DateTime(this.getRestoMenu().getDate()); - Duration duration = new Duration(new DateTime(), jodaDate); - return (int) (1000 - (duration.getStandardDays()*100)); + LocalDate date = getRestoMenu().getDate(); + Period duration = Period.between(LocalDate.now(), date); + return 1000 - (duration.getDays() * 100); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/cards/SchamperCard.java b/app/src/main/java/be/ugent/zeus/hydra/models/cards/SchamperCard.java index 0b98774ab..e2afcd14c 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/cards/SchamperCard.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/cards/SchamperCard.java @@ -1,8 +1,8 @@ package be.ugent.zeus.hydra.models.cards; import be.ugent.zeus.hydra.models.schamper.Article; -import org.joda.time.DateTime; -import org.joda.time.Duration; +import org.threeten.bp.Duration; +import org.threeten.bp.ZonedDateTime; import static be.ugent.zeus.hydra.models.cards.HomeCard.CardType.SCHAMPER; @@ -18,9 +18,9 @@ public SchamperCard(Article article) { @Override public int getPriority() { - DateTime jodadate = new DateTime(this.getArticle().getPubDate()); - Duration duration = new Duration(jodadate, new DateTime()); - return (int) (1000 - (duration.getStandardDays()*100)); + ZonedDateTime date = getArticle().getPubDate(); + Duration duration = Duration.between(date, ZonedDateTime.now()); + return (int) (1000 - (duration.toDays() * 100)); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/converters/AbstractDateJsonAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/models/converters/AbstractDateJsonAdapter.java deleted file mode 100644 index 082829b16..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/models/converters/AbstractDateJsonAdapter.java +++ /dev/null @@ -1,55 +0,0 @@ -package be.ugent.zeus.hydra.models.converters; - -import android.util.Log; - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; - -import java.io.IOException; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * Created by feliciaan on 17/02/16. - */ -public class AbstractDateJsonAdapter extends TypeAdapter { - - private static final String TAG = "AbstractDateParser"; - - private DateFormat format; - - public AbstractDateJsonAdapter(String dateFormat) { - format = new SimpleDateFormat(dateFormat, new Locale("nl")); - } - - @Override - public void write(JsonWriter out, Date value) throws IOException { - if (value == null) { - out.nullValue(); - return; - } - - out.value(format.format(value)); - } - - @Override - public Date read(JsonReader in) throws IOException { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } - String dateString = in.nextString(); - Date date = null; - try { - date = format.parse(dateString); - } catch (ParseException e) { - Log.e(TAG, "Parsing failed!", e); - } - return date; - } -} diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/converters/DateThreeTenAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/models/converters/DateThreeTenAdapter.java new file mode 100644 index 000000000..4f00c7315 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/models/converters/DateThreeTenAdapter.java @@ -0,0 +1,63 @@ +package be.ugent.zeus.hydra.models.converters; + +import android.support.annotation.Nullable; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import org.threeten.bp.LocalDate; +import org.threeten.bp.ZonedDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +import java.io.IOException; + +/** + * @author Niko Strijbol + */ +public class DateThreeTenAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if(date == null) { + out.nullValue(); + return; + } + + if(getFormatter() == null) { + out.value(date.toString()); + } else { + out.value(date.format(getFormatter())); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + if(getFormatter() == null) { + return LocalDate.parse(in.nextString()); + } else { + return LocalDate.parse(in.nextString(), getFormatter()); + } + } + + /** + * Provide the formatter to use to parse and write the date. + * + * If null is returned, the {@link org.threeten.bp.format.DateTimeFormatter#ISO_ZONED_DATE_TIME} format will + * be used. + * + * @see ZonedDateTime#parse(CharSequence, DateTimeFormatter) + * + * @return The formatter to use. + */ + @Nullable + protected DateTimeFormatter getFormatter() { + return null; + } +} + diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/converters/DateTimeAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/models/converters/DateTimeAdapter.java deleted file mode 100644 index bd5dc0776..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/models/converters/DateTimeAdapter.java +++ /dev/null @@ -1,60 +0,0 @@ -package be.ugent.zeus.hydra.models.converters; - -/** - * @author Niko Strijbol - * @version 1/06/2016 - */ - -import com.google.gson.TypeAdapter; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.ISODateTimeFormat; - -import java.io.IOException; - -/** - * GSON serialiser/deserialiser for converting Joda {@link DateTime} objects. - * - * @author Niko Strijbol - * @version 1/06/2016 - */ -public class DateTimeAdapter extends TypeAdapter { - - private static final DateTimeFormatter fmt = ISODateTimeFormat.dateTime(); - - /** - * Writes one JSON value (an array, object, string, number, boolean or null) for {@code value}. - * - * @param out - * @param value the Java object to write. May be null. - */ - @Override - public void write(JsonWriter out, DateTime value) throws IOException { - if (value == null) { - out.nullValue(); - return; - } - - out.value(fmt.print(value)); - } - - /** - * Reads one JSON value (an array, object, string, number, boolean or null) and converts it to a Java object. - * Returns the converted object. - * - * @param in - * - * @return the converted Java object. May be null. - */ - @Override - public DateTime read(JsonReader in) throws IOException { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } - return fmt.parseDateTime(in.nextString()); - } -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/converters/ISO8601DateJsonAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/models/converters/ISO8601DateJsonAdapter.java deleted file mode 100644 index a8afd1851..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/models/converters/ISO8601DateJsonAdapter.java +++ /dev/null @@ -1,10 +0,0 @@ -package be.ugent.zeus.hydra.models.converters; - -/** - * Created by feliciaan on 17/06/16. - */ -public class ISO8601DateJsonAdapter extends AbstractDateJsonAdapter { - public ISO8601DateJsonAdapter() { - super("yyyy-MM-dd'T'HH:mm:ssZ"); - } -} diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/converters/MinervaDateJsonAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/models/converters/MinervaDateJsonAdapter.java deleted file mode 100644 index f2c34691d..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/models/converters/MinervaDateJsonAdapter.java +++ /dev/null @@ -1,10 +0,0 @@ -package be.ugent.zeus.hydra.models.converters; - -/** - * Created by feliciaan on 03/07/16. - */ -public class MinervaDateJsonAdapter extends AbstractDateJsonAdapter { - public MinervaDateJsonAdapter() { - super("yyyy-MM-dd HH:mm:ss.SSSSSS"); - } -} diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/converters/RestoDateJsonAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/models/converters/RestoDateJsonAdapter.java deleted file mode 100644 index ae4333a7e..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/models/converters/RestoDateJsonAdapter.java +++ /dev/null @@ -1,11 +0,0 @@ -package be.ugent.zeus.hydra.models.converters; - -/** - * Created by feliciaan on 17/02/16. - */ -public class RestoDateJsonAdapter extends AbstractDateJsonAdapter { - - public RestoDateJsonAdapter() { - super("yyyy-MM-dd"); - } -} diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/converters/TimeStampDateJsonAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/models/converters/TimeStampDateJsonAdapter.java deleted file mode 100644 index 73830e0bf..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/models/converters/TimeStampDateJsonAdapter.java +++ /dev/null @@ -1,11 +0,0 @@ -package be.ugent.zeus.hydra.models.converters; - -/** - * Created by feliciaan on 17/02/16. - */ -public class TimeStampDateJsonAdapter extends AbstractDateJsonAdapter { - - public TimeStampDateJsonAdapter() { - super("yyyy-MM-dd'T'HH:mm:ss"); - } -} diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/minerva/AgendaItem.java b/app/src/main/java/be/ugent/zeus/hydra/models/minerva/AgendaItem.java index df3f4be3e..280de01c1 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/minerva/AgendaItem.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/minerva/AgendaItem.java @@ -2,14 +2,14 @@ import android.os.Parcel; import android.os.Parcelable; -import android.support.annotation.Nullable; -import be.ugent.zeus.hydra.models.converters.ISO8601DateJsonAdapter; +import be.ugent.zeus.hydra.models.converters.ZonedThreeTenAdapter; +import be.ugent.zeus.hydra.utils.TtbUtils; import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import org.threeten.bp.ZonedDateTime; import java.io.Serializable; -import java.util.Date; /** * @author Niko Strijbol @@ -21,18 +21,18 @@ public class AgendaItem implements Serializable, Parcelable { private String title; private String content; @SerializedName("start_date") - @JsonAdapter(ISO8601DateJsonAdapter.class) - private Date startDate; + @JsonAdapter(ZonedThreeTenAdapter.class) + private ZonedDateTime startDate; @SerializedName("end_date") - @JsonAdapter(ISO8601DateJsonAdapter.class) - private Date endDate; + @JsonAdapter(ZonedThreeTenAdapter.class) + private ZonedDateTime endDate; private String location; private String type; @SerializedName("last_edit_user") private String lastEditUser; - @JsonAdapter(ISO8601DateJsonAdapter.class) + @JsonAdapter(ZonedThreeTenAdapter.class) @SerializedName("last_edit_time") - private Date lastEdited; + private ZonedDateTime lastEdited; @SerializedName("last_edit_type") private String lastEditType; private Course course; @@ -48,7 +48,6 @@ public void setItemId(int itemId) { this.itemId = itemId; } - @Nullable public Course getCourse() { return course; } @@ -85,19 +84,19 @@ public void setContent(String content) { this.content = content; } - public Date getStartDate() { + public ZonedDateTime getStartDate() { return startDate; } - public void setStartDate(Date startDate) { + public void setStartDate(ZonedDateTime startDate) { this.startDate = startDate; } - public Date getEndDate() { + public ZonedDateTime getEndDate() { return endDate; } - public void setEndDate(Date endDate) { + public void setEndDate(ZonedDateTime endDate) { this.endDate = endDate; } @@ -125,11 +124,11 @@ public void setLastEditUser(String lastEditUser) { this.lastEditUser = lastEditUser; } - public Date getLastEdited() { + public ZonedDateTime getLastEdited() { return lastEdited; } - public void setLastEdited(Date lastEdited) { + public void setLastEdited(ZonedDateTime lastEdited) { this.lastEdited = lastEdited; } @@ -151,12 +150,12 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(this.itemId); dest.writeString(this.title); dest.writeString(this.content); - dest.writeLong(this.startDate != null ? this.startDate.getTime() : -1); - dest.writeLong(this.endDate != null ? this.endDate.getTime() : -1); + dest.writeSerializable(this.startDate); + dest.writeSerializable(this.endDate); dest.writeString(this.location); dest.writeString(this.type); dest.writeString(this.lastEditUser); - dest.writeLong(this.lastEdited != null ? this.lastEdited.getTime() : -1); + dest.writeLong(TtbUtils.serialize(this.lastEdited)); dest.writeString(this.lastEditType); dest.writeParcelable(this.course, flags); } @@ -168,15 +167,12 @@ private AgendaItem(Parcel in) { this.itemId = in.readInt(); this.title = in.readString(); this.content = in.readString(); - long tmpStartDate = in.readLong(); - this.startDate = tmpStartDate == -1 ? null : new Date(tmpStartDate); - long tmpEndDate = in.readLong(); - this.endDate = tmpEndDate == -1 ? null : new Date(tmpEndDate); + this.startDate = (ZonedDateTime) in.readSerializable(); + this.endDate = (ZonedDateTime) in.readSerializable(); this.location = in.readString(); this.type = in.readString(); this.lastEditUser = in.readString(); - long tmpLastEdited = in.readLong(); - this.lastEdited = tmpLastEdited == -1 ? null : new Date(tmpLastEdited); + this.lastEdited = TtbUtils.unserialize(in.readLong()); this.lastEditType = in.readString(); this.course = in.readParcelable(Course.class.getClassLoader()); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/minerva/Announcement.java b/app/src/main/java/be/ugent/zeus/hydra/models/minerva/Announcement.java index 64fe8c281..f88592d1e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/minerva/Announcement.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/minerva/Announcement.java @@ -2,12 +2,14 @@ import android.os.Parcel; import android.os.Parcelable; -import be.ugent.zeus.hydra.models.converters.ISO8601DateJsonAdapter; + +import be.ugent.zeus.hydra.models.converters.ZonedThreeTenAdapter; +import be.ugent.zeus.hydra.utils.TtbUtils; import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import org.threeten.bp.ZonedDateTime; import java.io.Serializable; -import java.util.Date; /** * Created by feliciaan on 29/06/16. @@ -22,19 +24,18 @@ public class Announcement implements Serializable, Parcelable { private int itemId; @SerializedName("last_edit_user") private String lecturer; - //TODO: this ignores the timezone for now, because parsing it as MinervaDate is a lot of work; we could also switch to ThreeTenABP - @JsonAdapter(ISO8601DateJsonAdapter.class) + @JsonAdapter(ZonedThreeTenAdapter.class) @SerializedName("last_edit_time") - private Date minervaDate; + private ZonedDateTime minervaDate; - private Date read; + private ZonedDateTime read; private Course course; public boolean isRead() { return read != null; } - public void setRead(Date read) { + public void setRead(ZonedDateTime read) { this.read = read; } @@ -78,11 +79,11 @@ public void setLecturer(String lecturer) { this.lecturer = lecturer; } - public Date getDate() { + public ZonedDateTime getDate() { return this.minervaDate; } - public void setDate(Date date) { + public void setDate(ZonedDateTime date) { this.minervaDate = date; } @@ -106,8 +107,8 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeByte(this.emailSent ? (byte) 1 : (byte) 0); dest.writeInt(this.itemId); dest.writeString(this.lecturer); - dest.writeLong(this.minervaDate != null ? this.minervaDate.getTime() : -1); - dest.writeLong(this.read != null ? this.read.getTime() : -1); + dest.writeLong(TtbUtils.serialize(this.minervaDate)); + dest.writeLong(TtbUtils.serialize(this.read)); dest.writeSerializable(this.course); } @@ -120,10 +121,10 @@ protected Announcement(Parcel in) { this.emailSent = in.readByte() != 0; this.itemId = in.readInt(); this.lecturer = in.readString(); - long tmpMinervaDate = in.readLong(); - this.minervaDate = tmpMinervaDate == -1 ? null : new Date(tmpMinervaDate); + long tmp = in.readLong(); + this.minervaDate = TtbUtils.unserialize(tmp); long tmpRead = in.readLong(); - this.read = tmpRead == -1 ? null : new Date(tmpRead); + this.read = TtbUtils.unserialize(tmpRead); this.course = (Course) in.readSerializable(); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/minerva/MinervaDate.java b/app/src/main/java/be/ugent/zeus/hydra/models/minerva/MinervaDate.java deleted file mode 100644 index 68d641ccf..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/models/minerva/MinervaDate.java +++ /dev/null @@ -1,44 +0,0 @@ -package be.ugent.zeus.hydra.models.minerva; - -import be.ugent.zeus.hydra.models.converters.MinervaDateJsonAdapter; -import com.google.gson.annotations.JsonAdapter; -import com.google.gson.annotations.SerializedName; - -import java.io.Serializable; -import java.util.Date; - -/** - * Created by feliciaan on 30/06/16. - */ -public class MinervaDate implements Serializable { - - @JsonAdapter(MinervaDateJsonAdapter.class) - private Date date; - @SerializedName("timezone_type") - private int timezoneType; - private String timezone; - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public int getTimezoneType() { - return timezoneType; - } - - public void setTimezoneType(int timezone_type) { - this.timezoneType = timezone_type; - } - - public String getTimezone() { - return timezone; - } - - public void setTimezone(String timezone) { - this.timezone = timezone; - } -} diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/resto/RestoMenu.java b/app/src/main/java/be/ugent/zeus/hydra/models/resto/RestoMenu.java index c01363817..d77281437 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/resto/RestoMenu.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/resto/RestoMenu.java @@ -2,12 +2,13 @@ import android.os.Parcel; import android.os.Parcelable; -import be.ugent.zeus.hydra.models.converters.RestoDateJsonAdapter; + +import be.ugent.zeus.hydra.models.converters.DateThreeTenAdapter; import com.google.gson.annotations.JsonAdapter; +import org.threeten.bp.LocalDate; import java.io.Serializable; import java.util.ArrayList; -import java.util.Date; import java.util.List; @@ -20,16 +21,13 @@ public class RestoMenu implements Parcelable, Serializable { private boolean open; - @JsonAdapter(RestoDateJsonAdapter.class) - private Date date; + @JsonAdapter(DateThreeTenAdapter.class) + private LocalDate date; private List meals; private List sideDishes; private List mainDishes; private List vegetables; - public RestoMenu() { - } - /** * Sort the meals available in the menu. */ @@ -80,11 +78,11 @@ public void setVegetables(List vegetables) { this.vegetables = vegetables; } - public Date getDate() { + public LocalDate getDate() { return date; } - public void setDate(Date date) { + public void setDate(LocalDate date) { this.date = date; } @@ -110,7 +108,7 @@ public int describeContents() { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeByte(this.open ? (byte) 1 : (byte) 0); - dest.writeLong(this.date != null ? this.date.getTime() : -1); + dest.writeLong(this.date != null ? this.date.toEpochDay() : -1); dest.writeList(this.meals); dest.writeStringList(this.vegetables); } @@ -118,7 +116,7 @@ public void writeToParcel(Parcel dest, int flags) { protected RestoMenu(Parcel in) { this.open = in.readByte() != 0; long tmpDate = in.readLong(); - this.date = tmpDate == -1 ? null : new Date(tmpDate); + this.date = tmpDate == -1 ? null : LocalDate.ofEpochDay(tmpDate); this.meals = new ArrayList<>(); in.readList(this.meals,RestoMeal.class.getClassLoader()); this.vegetables = in.createStringArrayList(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/schamper/Article.java b/app/src/main/java/be/ugent/zeus/hydra/models/schamper/Article.java index 267100e6b..9363d4acd 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/schamper/Article.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/schamper/Article.java @@ -3,13 +3,14 @@ import android.os.Parcel; import android.os.Parcelable; -import be.ugent.zeus.hydra.models.converters.ISO8601DateJsonAdapter; +import be.ugent.zeus.hydra.models.converters.ZonedThreeTenAdapter; +import be.ugent.zeus.hydra.utils.TtbUtils; import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import org.threeten.bp.ZonedDateTime; import java.io.Serializable; import java.util.ArrayList; -import java.util.Date; import java.util.List; /** @@ -19,9 +20,9 @@ public class Article implements Serializable, Parcelable { private String title; private String link; - @JsonAdapter(ISO8601DateJsonAdapter.class) + @JsonAdapter(ZonedThreeTenAdapter.class) @SerializedName("pub_date") - private Date pubDate; + private ZonedDateTime pubDate; private String author; private String body; private String image; @@ -33,66 +34,34 @@ public String getTitle() { return title; } - public void setTitle(String title) { - this.title = title; - } - public String getLink() { return link; } - public void setLink(String link) { - this.link = link; - } - - public Date getPubDate() { + public ZonedDateTime getPubDate() { return pubDate; } - public void setPubDate(Date pubDate) { - this.pubDate = pubDate; - } - public String getAuthor() { return author; } - public void setAuthor(String author) { - this.author = author; - } - public String getBody() { return body; } - public void setBody(String body) { - this.body = body; - } - public String getCategory() { return category; } - public void setCategory(String category) { - this.category = category; - } - public String getIntro() { return intro; } - public void setIntro(String intro) { - this.intro = intro; - } - public List getImages() { return images; } - public void setImages(ArrayList images) { - this.images = images; - } - public String getImage() { return image; } @@ -109,11 +78,6 @@ public static String getLargeImage(String url) { return url.replace("/regulier/", "/preview/"); } - public void setImage(String image) { - this.image = image; - } - - @Override public int describeContents() { return 0; @@ -123,7 +87,7 @@ public int describeContents() { public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.title); dest.writeString(this.link); - dest.writeLong(this.pubDate != null ? this.pubDate.getTime() : -1); + dest.writeLong(TtbUtils.serialize(this.pubDate)); dest.writeString(this.author); dest.writeString(this.body); dest.writeString(this.image); @@ -138,8 +102,7 @@ public Article() { protected Article(Parcel in) { this.title = in.readString(); this.link = in.readString(); - long tmpPubDate = in.readLong(); - this.pubDate = tmpPubDate == -1 ? null : new Date(tmpPubDate); + this.pubDate = TtbUtils.unserialize(in.readLong()); this.author = in.readString(); this.body = in.readString(); this.image = in.readString(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvent.java b/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvent.java index 6b8967a61..7675ee717 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvent.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvent.java @@ -1,15 +1,16 @@ package be.ugent.zeus.hydra.models.specialevent; -import be.ugent.zeus.hydra.models.converters.TimeStampDateJsonAdapter; +import be.ugent.zeus.hydra.models.converters.ZonedThreeTenAdapter; import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; +import org.threeten.bp.ZonedDateTime; import java.io.Serializable; -import java.util.Date; /** * Created by feliciaan on 06/04/16. */ +@SuppressWarnings("unused") public class SpecialEvent implements Serializable { private String name; @@ -19,10 +20,10 @@ public class SpecialEvent implements Serializable { private String image; private String html; private int priority; - @JsonAdapter(TimeStampDateJsonAdapter.class) - private Date start; - @JsonAdapter(TimeStampDateJsonAdapter.class) - private Date end; + @JsonAdapter(ZonedThreeTenAdapter.class) + private ZonedDateTime start; + @JsonAdapter(ZonedThreeTenAdapter.class) + private ZonedDateTime end; private boolean development; private boolean sko = false; @@ -39,10 +40,6 @@ public String getLink() { return link; } - public void setLink(String link) { - this.link = link; - } - public String getSimpleText() { return simpleText; } @@ -63,10 +60,6 @@ public String getHtml() { return html; } - public void setHtml(String html) { - this.html = html; - } - public int getPriority() { return priority; } @@ -75,30 +68,18 @@ public void setPriority(int priority) { this.priority = priority; } - public Date getStart() { + public ZonedDateTime getStart() { return start; } - public void setStart(Date start) { - this.start = start; - } - - public Date getEnd() { + public ZonedDateTime getEnd() { return end; } - public void setEnd(Date end) { - this.end = end; - } - public boolean isDevelopment() { return development; } - public void setDevelopment(boolean development) { - this.development = development; - } - public boolean isSko() { return sko; } @@ -106,4 +87,4 @@ public boolean isSko() { public void setSko(boolean sko) { this.sko = sko; } -} +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvents.java b/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvents.java index 2a9eabf3b..687324395 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvents.java +++ b/app/src/main/java/be/ugent/zeus/hydra/models/specialevent/SpecialEvents.java @@ -6,5 +6,4 @@ * Created by feliciaan on 06/04/16. */ public class SpecialEvents extends ArrayList { - private static final long serialVersionUID = 324325524254254623L; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/ActivityListAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/ActivityListAdapter.java index 6e49859cc..6e42a7d28 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/ActivityListAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/ActivityListAdapter.java @@ -7,19 +7,17 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; + import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.ActivityDetailActivity; import be.ugent.zeus.hydra.models.association.Activity; import be.ugent.zeus.hydra.recyclerview.viewholder.DateHeaderViewHolder; import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersAdapter; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.format.DateTimeFormatter; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Collections; -import java.util.Date; import java.util.List; -import java.util.Locale; - import static be.ugent.zeus.hydra.utils.ViewUtils.$; @@ -30,9 +28,8 @@ */ public class ActivityListAdapter extends RecyclerView.Adapter implements StickyRecyclerHeadersAdapter { - private static final Locale locale = new Locale("nl"); - private static final DateFormat INT_FORMATTER = new SimpleDateFormat("ddMMyyyy", locale); - private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("HH:mm", locale); + private static final DateTimeFormatter INTEGER_FORMATTER = DateTimeFormatter.ofPattern("ddMMyyyy"); + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); public static class CardViewHolder extends RecyclerView.ViewHolder { @@ -50,7 +47,7 @@ private CardViewHolder(View v) { private void populate(final Activity activity) { title.setText(activity.getTitle()); association.setText(activity.getAssociation().getDisplayName()); - start.setText(FORMATTER.format(activity.getStart())); + start.setText(activity.getLocalStart().format(FORMATTER)); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -84,8 +81,8 @@ public void onBindViewHolder(CardViewHolder holder, int position) { */ @Override public long getHeaderId(int position) { - Date date = data.get(position).getStart(); - return Integer.parseInt(INT_FORMATTER.format(date)); + LocalDateTime date = data.get(position).getLocalStart(); + return Integer.parseInt(date.format(INTEGER_FORMATTER)); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/minerva/AgendaAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/minerva/AgendaAdapter.java index 726c40d20..3257d13cd 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/minerva/AgendaAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/adapters/minerva/AgendaAdapter.java @@ -10,19 +10,14 @@ import be.ugent.zeus.hydra.recyclerview.viewholder.DateHeaderViewHolder; import be.ugent.zeus.hydra.recyclerview.viewholder.minerva.AgendaViewHolder; import com.timehop.stickyheadersrecyclerview.StickyRecyclerHeadersAdapter; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; +import org.threeten.bp.format.DateTimeFormatter; /** * @author Niko Strijbol */ public class AgendaAdapter extends EmptyItemLoader implements StickyRecyclerHeadersAdapter { - private static final Locale locale = new Locale("nl"); - private static final DateFormat INT_FORMATTER = new SimpleDateFormat("ddMMyyyy", locale); + private static final DateTimeFormatter INT_FORMATTER = DateTimeFormatter.ofPattern("ddMMyyyy"); public AgendaAdapter() { super(R.layout.item_no_data); @@ -43,8 +38,7 @@ public long getHeaderId(int position) { if(getItemViewType(position) == EMPTY_VIEW) { return -1; //No header } else { - Date date = items.get(position).getStartDate(); - return Integer.parseInt(INT_FORMATTER.format(date)); + return Integer.parseInt(items.get(position).getStartDate().format(INT_FORMATTER)); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/DateHeaderViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/DateHeaderViewHolder.java index cc13ddb8e..1f12382de 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/DateHeaderViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/DateHeaderViewHolder.java @@ -3,10 +3,10 @@ import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.TextView; + import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.utils.DateUtils; - -import java.util.Date; +import org.threeten.bp.ZonedDateTime; import static be.ugent.zeus.hydra.utils.ViewUtils.$; @@ -25,7 +25,7 @@ public DateHeaderViewHolder(View v) { headerText = $(v, R.id.date_header); } - public void populate(Date date) { - headerText.setText(DateUtils.getFriendlyDate(date)); + public void populate(ZonedDateTime date) { + headerText.setText(DateUtils.getFriendlyDate(date.toLocalDate())); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/NewsItemViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/NewsItemViewHolder.java index 5d63a4e04..c72e8f36d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/NewsItemViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/NewsItemViewHolder.java @@ -1,7 +1,5 @@ package be.ugent.zeus.hydra.recyclerview.viewholder; -import java.util.Locale; - import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Parcelable; @@ -14,6 +12,8 @@ import be.ugent.zeus.hydra.utils.DateUtils; import be.ugent.zeus.hydra.utils.ViewUtils; +import java.util.Locale; + import static be.ugent.zeus.hydra.utils.ViewUtils.$; /** @@ -38,7 +38,7 @@ public void populate(final NewsItem newsItem) { title.setText(newsItem.getTitle()); String infoText = String.format(new Locale("nl"), "%s door %s", - DateUtils.relativeDateString(newsItem.getDate(), itemView.getContext()), + DateUtils.relativeDateTimeString(newsItem.getDate(), itemView.getContext()), newsItem.getAssociation().getName()); info.setText(infoText); if (newsItem.isHighlighted()) { diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/SchamperViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/SchamperViewHolder.java index 37a48955c..d19b5bbe1 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/SchamperViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/SchamperViewHolder.java @@ -35,7 +35,7 @@ public SchamperViewHolder(View itemView) { public void populate(final Article article) { title.setText(article.getTitle()); - date.setText(DateUtils.relativeDateString(article.getPubDate(), itemView.getContext())); + date.setText(DateUtils.relativeDateTimeString(article.getPubDate(), itemView.getContext())); author.setText(article.getAuthor()); category.setText(article.getCategory()); diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/ActivityCardViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/ActivityCardViewHolder.java index d0231a7c6..ecf00b187 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/ActivityCardViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/ActivityCardViewHolder.java @@ -43,7 +43,7 @@ public void populate(final HomeCard card) { title.setText(activity.getTitle()); association.setText(activity.getLocation()); - start.setText(DateUtils.relativeDateString(activity.getStartDate(), itemView.getContext())); + start.setText(DateUtils.relativeDateTimeString(activity.getStart(), itemView.getContext(), false)); String description = itemView.getResources().getString(R.string.home_card_description); toolbar.setTitle(String.format(description, activity.getAssociation().getDisplayName())); diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/RestoCardViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/RestoCardViewHolder.java index 07a2f557e..6ad2707c6 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/RestoCardViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/RestoCardViewHolder.java @@ -2,6 +2,7 @@ import android.content.Intent; import android.view.View; + import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.resto.MenuActivity; import be.ugent.zeus.hydra.models.cards.HomeCard; @@ -39,7 +40,7 @@ public void populate(HomeCard card) { @Override public void onClick(View v) { Intent intent = new Intent(itemView.getContext(), MenuActivity.class); - intent.putExtra(MenuActivity.ARG_DATE, menu.getDate().getTime()); + intent.putExtra(MenuActivity.ARG_DATE, menu.getDate()); itemView.getContext().startActivity(intent); } }); diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/SchamperViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/SchamperViewHolder.java index d56c56956..bbc9757e9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/SchamperViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/home/SchamperViewHolder.java @@ -40,7 +40,7 @@ public void populate(HomeCard card) { final Article article = card.checkCard(HomeCard.CardType.SCHAMPER).getArticle(); title.setText(article.getTitle()); - date.setText(DateUtils.relativeDateString(article.getPubDate(), itemView.getContext())); + date.setText(DateUtils.relativeDateTimeString(article.getPubDate(), itemView.getContext())); author.setText(article.getAuthor()); Picasso.with(this.itemView.getContext()).load(article.getImage()).fit().centerInside().into(image); diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AgendaViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AgendaViewHolder.java index 6c6abb145..4c02538cc 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AgendaViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AgendaViewHolder.java @@ -35,7 +35,7 @@ public AgendaViewHolder(View itemView) { public void populate(final AgendaItem data) { title.setText(data.getTitle()); String infoText = String.format(new Locale("nl"), "%s door %s", - DateUtils.relativeDateString(data.getStartDate(), itemView.getContext()), + DateUtils.relativeDateTimeString(data.getStartDate(), itemView.getContext()), data.getLastEditUser()); subtitle.setText(infoText); diff --git a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AnnouncementViewHolder.java b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AnnouncementViewHolder.java index 12c80c03c..5f03392de 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AnnouncementViewHolder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/recyclerview/viewholder/minerva/AnnouncementViewHolder.java @@ -24,7 +24,6 @@ public class AnnouncementViewHolder extends DataViewHolder { private TextView title; private TextView subtitle; - private View parent; private Fragment fragment; public AnnouncementViewHolder(View itemView) { @@ -34,7 +33,6 @@ public AnnouncementViewHolder(View itemView) { public AnnouncementViewHolder(View itemView, @Nullable Fragment fragment) { super(itemView); title = $(itemView, R.id.title); - parent = $(itemView, R.id.parent_layout); subtitle = $(itemView, R.id.subtitle); this.fragment = fragment; } @@ -43,7 +41,7 @@ public AnnouncementViewHolder(View itemView, @Nullable Fragment fragment) { public void populate(final Announcement data) { title.setText(data.getTitle()); String infoText = String.format(new Locale("nl"), "%s door %s", - DateUtils.relativeDateString(data.getDate(), itemView.getContext()), + DateUtils.relativeDateTimeString(data.getDate(), itemView.getContext(), false), data.getLecturer()); subtitle.setText(infoText); diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/AgendaRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/AgendaRequest.java index 4721bf45a..54c7f6b2d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/AgendaRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/AgendaRequest.java @@ -8,8 +8,7 @@ import be.ugent.zeus.hydra.models.minerva.Agenda; import org.springframework.web.util.UriComponentsBuilder; - -import java.util.Date; +import org.threeten.bp.ZonedDateTime; /** * Request agenda items, optionally in a time range. @@ -18,8 +17,8 @@ */ public class AgendaRequest extends MinervaRequest { - private Date start; - private Date end; + private ZonedDateTime start; + private ZonedDateTime end; public AgendaRequest(Context context, @Nullable Activity activity) { super(Agenda.class, context, activity); @@ -29,11 +28,11 @@ public AgendaRequest(Context context, @Nullable Account account, @Nullable Activ super(Agenda.class, context, account, activity); } - public void setStart(Date start) { + public void setStart(ZonedDateTime start) { this.start = start; } - public void setEnd(Date end) { + public void setEnd(ZonedDateTime end) { this.end = end; } @@ -49,11 +48,11 @@ protected String getAPIUrl() { UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url); if(start != null) { - builder.queryParam("start", start.getTime()); + builder.queryParam("start", start.toInstant().toEpochMilli()); } if(end != null) { - builder.queryParam("end", end.getTime()); + builder.queryParam("end", end.toInstant().toEpochMilli()); } return builder.build().toUriString(); diff --git a/app/src/main/java/be/ugent/zeus/hydra/utils/DateUtils.java b/app/src/main/java/be/ugent/zeus/hydra/utils/DateUtils.java index 46592cdfe..80d2079bb 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/utils/DateUtils.java +++ b/app/src/main/java/be/ugent/zeus/hydra/utils/DateUtils.java @@ -2,15 +2,11 @@ import android.content.Context; -import org.joda.time.DateTime; -import org.joda.time.Days; -import org.threeten.bp.LocalDateTime; -import org.threeten.bp.ZoneId; -import org.threeten.bp.ZonedDateTime; +import org.threeten.bp.*; +import org.threeten.bp.format.DateTimeFormatter; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.Date; import java.util.Locale; /** @@ -21,20 +17,19 @@ public class DateUtils { private static Locale locale = new Locale("nl"); - private static SimpleDateFormat WEEK_FORMATTER = new SimpleDateFormat("w", locale); - private static SimpleDateFormat DAY_FORMATTER = new SimpleDateFormat("cccc", locale); - private static DateFormat DATE_FORMATTER = SimpleDateFormat.getDateInstance(); + private static DateTimeFormatter WEEK_FORMATTER = DateTimeFormatter.ofPattern("w", locale); + private static DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("cccc", locale); + private static DateFormat DATE_FORMATTER = SimpleDateFormat.getDateInstance(DateFormat.DEFAULT, locale); /** * Get the date in friendly format. */ - public static String getFriendlyDate(Date date) { - DateTime today = new DateTime(); - DateTime dateTime = new DateTime(date); - int thisWeek = Integer.parseInt(WEEK_FORMATTER.format(today.toDate())); - int week = Integer.parseInt(WEEK_FORMATTER.format(date)); + public static String getFriendlyDate(LocalDate date) { + LocalDate today = LocalDate.now(); - int daysBetween = Days.daysBetween(today.toLocalDate(), dateTime.toLocalDate()).getDays(); + int thisWeek = Integer.parseInt(today.format(WEEK_FORMATTER)); + int week = Integer.parseInt(date.format(WEEK_FORMATTER)); + int daysBetween = Period.between(today, date).getDays(); if (daysBetween == 0) { return "vandaag"; @@ -43,20 +38,16 @@ public static String getFriendlyDate(Date date) { } else if (daysBetween == 2) { return "overmorgen"; } else if (daysBetween < 0) { - return DATE_FORMATTER.format(date); + return DATE_FORMATTER.format(DateTimeUtils.toDate(date.atStartOfDay(ZoneId.systemDefault()).toInstant())); } else if (daysBetween <= 7) { return DAY_FORMATTER.format(date).toLowerCase(); } else if (week == thisWeek + 1) { return "volgende " + DAY_FORMATTER.format(date).toLowerCase(); } else { - return DATE_FORMATTER.format(date); + return DATE_FORMATTER.format(DateTimeUtils.toDate(date.atStartOfDay(ZoneId.systemDefault()).toInstant())); } } - public static CharSequence relativeDateString(Date date, Context context) { - return android.text.format.DateUtils.getRelativeDateTimeString(context, date.getTime(), android.text.format.DateUtils.MINUTE_IN_MILLIS, android.text.format.DateUtils.WEEK_IN_MILLIS, 0); - } - /** * Convert a date time to a relative string. The precision is one minute, and the resulting string is * abbreviated. @@ -83,6 +74,10 @@ public static CharSequence relativeDateTimeString(ZonedDateTime dateTime, Contex ); } + public static CharSequence relativeDateTimeString(ZonedDateTime dateTime, Context context) { + return relativeDateTimeString(dateTime, context, false); + } + /** * Get the date, converted to the local time zone. The resulting DateTime is the time as it is used * in the current time zone. diff --git a/app/src/main/java/be/ugent/zeus/hydra/utils/TtbUtils.java b/app/src/main/java/be/ugent/zeus/hydra/utils/TtbUtils.java new file mode 100644 index 000000000..11137bd12 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/utils/TtbUtils.java @@ -0,0 +1,45 @@ +package be.ugent.zeus.hydra.utils; + +import android.support.annotation.Nullable; + +import org.threeten.bp.*; + +/** + * When we save to the database/parcel/..., we often save in epoch milli seconds. + * + * Then our time zone data is lost. That's why we first convert to a LocalDateTime using a fixed timezone. + * + * @author Niko Strijbol + */ +public class TtbUtils { + + private static final ZoneId zone = ZoneOffset.UTC.normalized(); + + public static long serialize(@Nullable ZonedDateTime dateTime) { + if(dateTime == null) { + return -1; + } + return dateTime.withZoneSameInstant(zone).toInstant().toEpochMilli(); + } + + public static ZonedDateTime unserialize(long epochMilli) { + if(epochMilli == -1) { + return null; + } + return Instant.ofEpochMilli(epochMilli).atZone(zone); + } + + public static long serialize(@Nullable LocalDateTime dateTime) { + if(dateTime == null) { + return -1; + } + return dateTime.atZone(zone).toInstant().toEpochMilli(); + } + + public static LocalDateTime unserializeLocal(long epochMilli) { + if(epochMilli == -1) { + return null; + } + return Instant.ofEpochMilli(epochMilli).atZone(zone).toLocalDateTime(); + } +} From 560c156b0eaa1016a762168f955fd4ea0edd1362 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Thu, 22 Sep 2016 23:51:28 +0200 Subject: [PATCH 3/5] Fix HTML in notifications --- .../announcement/AnnouncementNotificationBuilder.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementNotificationBuilder.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementNotificationBuilder.java index d477e5450..e18b885f4 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementNotificationBuilder.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/announcement/AnnouncementNotificationBuilder.java @@ -10,6 +10,7 @@ import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.models.minerva.Announcement; import be.ugent.zeus.hydra.models.minerva.Course; +import be.ugent.zeus.hydra.utils.html.Utils; import java.util.Collection; import java.util.Iterator; @@ -70,7 +71,6 @@ public void publish() { Log.d(TAG, "Publishing notification"); - NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setSmallIcon(smallIcon) .setCategory(CATEGORY_EMAIL); @@ -93,7 +93,7 @@ private NotificationCompat.Builder publishOne(NotificationCompat.Builder builder NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); bigTextStyle.setBigContentTitle(announcement.getTitle()); - bigTextStyle.bigText(announcement.getContent()); + bigTextStyle.bigText(stripHtml(announcement.getContent())); bigTextStyle.setSummaryText(announcement.getLecturer()); if(TextUtils.isEmpty(announcement.getTitle())) { @@ -135,4 +135,8 @@ private void setTitle(NotificationCompat.Builder builder) { builder.setContentTitle(course.getTitle()); } } + + private String stripHtml(String containingHtml) { + return Utils.fromHtml(containingHtml).toString(); + } } \ No newline at end of file From e9533dd797f09308264729e27de5e62f834ad780 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Fri, 23 Sep 2016 00:27:59 +0200 Subject: [PATCH 4/5] Improve sync code a bit --- .../zeus/hydra/minerva/agenda/AgendaDao.java | 110 ----------------- .../zeus/hydra/minerva/sync/StubProvider.java | 2 +- .../zeus/hydra/minerva/sync/SyncAdapter.java | 41 ++++--- .../hydra/minerva/sync/SyncBroadcast.java | 2 +- .../minerva/sync/SyncErrorNotification.java | 113 ++++++++++++++++++ .../minerva/sync/SyncNotificationBuilder.java | 65 ---------- 6 files changed, 137 insertions(+), 196 deletions(-) create mode 100644 app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncErrorNotification.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncNotificationBuilder.java diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java index 859b9177a..a680eb9d8 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/agenda/AgendaDao.java @@ -4,8 +4,6 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import android.text.TextUtils; -import android.util.Log; import be.ugent.zeus.hydra.minerva.database.Dao; import be.ugent.zeus.hydra.models.minerva.AgendaItem; @@ -21,8 +19,6 @@ */ public class AgendaDao extends Dao { - private static final String TAG = "AgendaDao"; - /** * @param context The application context. */ @@ -37,56 +33,6 @@ public void deleteAll() { helper.getWritableDatabase().delete(AgendaTable.TABLE_NAME, null, null); } - /** - * Synchronise agenda for one course. - * - * @param agenda The agenda. - */ - public void synchronisePartial(Collection agenda, Course course) { - - //Get existing courses. - Set present = getIdsForCourse(course); - - SQLiteDatabase db = helper.getWritableDatabase(); - - int counter = 0; - try { - db.beginTransaction(); - - //Delete old courses - String ids = TextUtils.join(", ", getRemovable(present, agenda)); - db.delete(AgendaTable.TABLE_NAME, AgendaTable.COLUMN_ID + " IN (?)", new String[]{ids}); - - Date date = new Date(); - for (AgendaItem agendaItem: agenda ) { - - agendaItem.setCourse(course); - ContentValues value = getValues(agendaItem); - - //Update the announcement - if(present.contains(agendaItem.getItemId())) { - value.remove(AgendaTable.COLUMN_ID); - db.update( - AgendaTable.TABLE_NAME, - value, - AgendaTable.COLUMN_ID + " = ?", - new String[]{String.valueOf(agendaItem.getItemId())} - ); - } - //Add new announcement - else { - db.insertOrThrow(AgendaTable.TABLE_NAME, null, value); - counter++; - } - } - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - - Log.d(TAG, "New agenda for " + course.getTitle() + ": " + counter); - } - /** * Delete all agenda items, and add the given ones. * @@ -130,62 +76,6 @@ private static ContentValues getValues(AgendaItem a) { return values; } - /** - * A set of ids that are not in the course. - * - * @param ids Ids of local courses. - * @param agendaItems Remote agenda. - * @return Local courses that can be deleted. - */ - private static Set getRemovable(final Set ids, final Collection agendaItems) { - Set removable = new HashSet<>(ids); - //Iterate the course to prevent O(n^2) - for (AgendaItem announcement: agendaItems) { - if(removable.contains(announcement.getItemId())) { - removable.remove(announcement.getItemId()); - } - } - - return removable; - } - - /** - * Get a list of ids of the announcements for a course in the database. - * - * @param course The course. - * - * @return List of ids in the database. - */ - private Set getIdsForCourse(Course course) { - - SQLiteDatabase db = helper.getReadableDatabase(); - - Cursor cursor = db.query( - AgendaTable.TABLE_NAME, - new String[] {AgendaTable.COLUMN_ID}, - AgendaTable.COLUMN_COURSE + " = ?", - new String[]{course.getId()}, - null, null, null); - - Set result = new HashSet<>(); - - if(cursor == null) { - return result; - } - - try { - int columnIndex = cursor.getColumnIndex(AgendaTable.COLUMN_ID); - - while (cursor.moveToNext()) { - result.add(cursor.getInt(columnIndex)); - } - } finally { - cursor.close(); - } - - return result; - } - /** * Get a list of ids of the agenda items for a course in the database. * diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/StubProvider.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/StubProvider.java index 225d2c12b..3dd5713a2 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/StubProvider.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/StubProvider.java @@ -6,7 +6,7 @@ import android.net.Uri; import android.support.annotation.NonNull; -/* +/** * Define an implementation of ContentProvider that stubs out all methods. * * @author Niko Strijbol diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java index d0bf7d475..1ffaaea01 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java @@ -76,7 +76,6 @@ public void onPerformSync(Account account, Bundle extras, String authority, Cont final AgendaDao agendaDao = new AgendaDao(getContext()); try { - //If this is the first request, clean everything. if(first) { agendaDao.deleteAll(); @@ -133,33 +132,38 @@ public void onPerformSync(Account account, Bundle extras, String authority, Cont if(e.getCause() instanceof RestTemplateException && request.getAccountBundle() != null) { syncResult.stats.numAuthExceptions++; Intent intent = request.getAccountBundle().getParcelable(AccountManager.KEY_INTENT); - SyncNotificationBuilder.showError(getContext(), intent); - } else { //It was something else. + SyncErrorNotification.Builder.init(getContext()).authError(intent).build().show(); + broadcast.publishIntent(SyncBroadcast.SYNC_ERROR); + } + //It was something else. + else { //Adjust stats - if(e.getCause() != null) { - if(e.getCause() instanceof RequestFailureException) { - syncResult.stats.numIoExceptions++; - } else { - syncResult.stats.numParseExceptions++; - } + if(e.getCause() != null && e.getCause() instanceof RequestFailureException) { + syncResult.stats.numIoExceptions++; + } else { + syncResult.stats.numParseExceptions++; } - SyncNotificationBuilder.showError(getContext()); + syncErrorNotification(); } - - broadcast.publishIntent(SyncBroadcast.SYNC_ERROR); } catch (SQLException e) { syncResult.databaseError = true; - Log.w(TAG, "Sync error.", e); - SyncNotificationBuilder.showError(getContext()); - broadcast.publishIntent(SyncBroadcast.SYNC_ERROR); - } catch (HttpMessageNotReadableException e) { Log.e(TAG, "Sync error.", e); - SyncNotificationBuilder.showError(getContext()); - broadcast.publishIntent(SyncBroadcast.SYNC_ERROR); + syncErrorNotification(); + } catch (HttpMessageNotReadableException e) { syncResult.stats.numParseExceptions++; + Log.e(TAG, "Sync error.", e); + syncErrorNotification(); } } + /** + * Show an error notification. This will also broadcast the error intent. + */ + private void syncErrorNotification() { + broadcast.publishIntent(SyncBroadcast.SYNC_ERROR); + SyncErrorNotification.Builder.init(getContext()).genericError().build().show(); + } + @Override public void onSyncCanceled() { super.onSyncCanceled(); @@ -186,7 +190,6 @@ private void notifyUser(@NonNull Collection newAnnouncements) { AnnouncementNotificationBuilder builder = new AnnouncementNotificationBuilder(getContext().getApplicationContext()); builder.setAnnouncements(newAnnouncements); builder.setCourse(newAnnouncements.iterator().next().getCourse()); - //TODO: limit to not every course! builder.publish(); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncBroadcast.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncBroadcast.java index 63b23722d..207debba8 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncBroadcast.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncBroadcast.java @@ -7,7 +7,7 @@ import android.support.v4.content.LocalBroadcastManager; /** - * Class to manage sending broadcasts from the sync adapter. + * Class to manage sending broadcasts from the sync adapter. These are local broadcasts. * * @author Niko Strijbol */ diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncErrorNotification.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncErrorNotification.java new file mode 100644 index 000000000..659b292b2 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncErrorNotification.java @@ -0,0 +1,113 @@ +package be.ugent.zeus.hydra.minerva.sync; + +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.support.v7.app.NotificationCompat; + +import be.ugent.zeus.hydra.R; + +import static android.support.v4.app.NotificationCompat.CATEGORY_ERROR; + +/** + * Helper methods to display notifications relating to the Minerva sync. + * + * @author Niko Strijbol + */ +public class SyncErrorNotification { + + private static final int NOTIFICATION_ID = 600; + + private final NotificationManager notificationManager; + private NotificationCompat.Builder builder; + private Context context; + + private SyncErrorNotification(Context context) { + this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + this.builder = new NotificationCompat.Builder(context); + this.context = context; + } + + /** + * Show the notification. + */ + public void show() { + notificationManager.notify(NOTIFICATION_ID, builder.build()); + } + + /** + * Hide the notification. + */ + public void remove() { + notificationManager.cancel(NOTIFICATION_ID); + } + + public static class Builder { + + private SyncErrorNotification notification; + + public Builder(Context context) { + notification = new SyncErrorNotification(context); + notification.builder.setSmallIcon(R.drawable.ic_notification_warning) + .setCategory(CATEGORY_ERROR); + } + + /** + * Same as the constructor, but enables better chaining of methods. + * + * @see #Builder(Context) + */ + public static Builder init(Context context) { + return new Builder(context); + } + + /** + * Show a notification for an auth error that requires the user to enter their credentials. + * + * @param authIntent The intent produced by the authentication manager. + * + * @return This builder. + */ + public Builder authError(Intent authIntent) { + PendingIntent pendingIntent = PendingIntent.getActivity(notification.context, 0, authIntent, 0); + notification.builder.setAutoCancel(true) + .setContentTitle("Minerva: opnieuw aanmelden") + .setContentText("Druk om opnieuw aan te melden") + .setContentIntent(pendingIntent) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText("Je moet opnieuw aanmelden bij Minerva, want de inloggegevens zijn verouderd.") + ); + return this; + } + + /** + * Show a generic error. + * + * @return This builder. + */ + public Builder genericError() { + notification.builder.setContentTitle("Minerva-fout") + .setContentText("Synchronisatiefout") + .setStyle(new NotificationCompat.BigTextStyle() + .bigText("Er trad een fout op bij het synchroniseren met Minerva. Gegevens kunnen verouderd zijn.") + ); + return this; + } + + /** + * @return The notification. + */ + public SyncErrorNotification build() { + return notification; + } + } + + /** + * Show general error notification. + * + * @param context The context. + */ + public static void showError(Context context) { + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncNotificationBuilder.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncNotificationBuilder.java deleted file mode 100644 index 62c35a3a1..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncNotificationBuilder.java +++ /dev/null @@ -1,65 +0,0 @@ -package be.ugent.zeus.hydra.minerva.sync; - -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.support.v7.app.NotificationCompat; - -import be.ugent.zeus.hydra.R; - -import static android.support.v4.app.NotificationCompat.CATEGORY_ERROR; - -/** - * Helper methods to display notifications relating to the Minerva sync. - * - * @author Niko Strijbol - */ -public class SyncNotificationBuilder { - - private static final int NOTIFICATION_ID = 600; - - /** - * Show a notification prompting the user to renew their credentials. - * - * @param context A context. - * @param intent The intent to launch a new activity. - */ - public static void showError(Context context, Intent intent) { - - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); - - NotificationCompat.Builder builder = new NotificationCompat.Builder(context); - builder.setSmallIcon(R.drawable.ic_notification_warning) - .setAutoCancel(true) - .setCategory(CATEGORY_ERROR) - .setContentTitle("Minerva: opnieuw aanmelden") - .setContentText("Druk om opnieuw aan te melden") - .setContentIntent(pendingIntent) - .setStyle(new android.support.v4.app.NotificationCompat.BigTextStyle() - .bigText("Je moet opnieuw aanmelden bij Minerva, want de inloggegevens zijn verouderd.") - ); - - NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - manager.notify(NOTIFICATION_ID, builder.build()); - } - - /** - * Show general error notification. - * - * @param context The context. - */ - public static void showError(Context context) { - NotificationCompat.Builder builder = new NotificationCompat.Builder(context); - builder.setSmallIcon(R.drawable.ic_notification_warning) - .setCategory(CATEGORY_ERROR) - .setContentTitle("Minerva-fout") - .setContentText("Synchronisatiefout") - .setStyle(new android.support.v4.app.NotificationCompat.BigTextStyle() - .bigText("Er trad een fout op bij het synchroniseren met Minerva. Gegevens kunnen verouderd zijn.") - ); - - NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - manager.notify(NOTIFICATION_ID, builder.build()); - } -} \ No newline at end of file From 522a94289ec4768188679d22046b07592f0202dd Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Fri, 23 Sep 2016 02:01:43 +0200 Subject: [PATCH 5/5] Refactor/rewrite some loader logic -> less complicated inheritances --- .../common/LoaderToolbarActivity.java | 77 +++-------- .../activities/minerva/AuthActivity.java | 2 +- .../AssociationSelectPrefActivity.java | 2 +- .../hydra/activities/resto/MenuActivity.java | 26 ++-- .../hydra/activities/resto/MetaActivity.java | 3 +- .../activities/resto/SandwichActivity.java | 3 +- .../be/ugent/zeus/hydra/caching/Cache.java | 2 +- .../zeus/hydra/caching/GenericCache.java | 2 +- .../hydra/fragments/ActivitiesFragment.java | 2 +- .../zeus/hydra/fragments/InfoFragment.java | 3 +- .../zeus/hydra/fragments/NewsFragment.java | 2 +- .../hydra/fragments/SchamperFragment.java | 10 +- .../common/CachedLoaderFragment.java | 20 ++- .../common/ItemAdapterLoaderFragment.java | 12 -- .../fragments/common/LoaderFragment.java | 80 ++--------- .../fragments/home/HomeLoaderCallback.java | 40 ++---- .../fragments/home/SpecialEventCallback.java | 2 +- .../minerva/CourseAgendaFragment.java | 19 +-- .../minerva/CourseAnnouncementFragment.java | 18 +-- .../fragments/minerva/MinervaFragment.java | 22 ++- .../hydra/fragments/resto/RestoFragment.java | 4 +- .../hydra/fragments/sko/LineupFragment.java | 4 +- .../hydra/fragments/sko/TimelineFragment.java | 4 +- .../hydra/fragments/sko/VillageFragment.java | 4 +- .../hydra/loaders/AbstractAsyncLoader.java | 7 +- .../hydra/loaders/ErrorLoaderCallback.java | 20 --- .../hydra/loaders/LoaderCallbackHandler.java | 125 ++++++++++++++++++ .../zeus/hydra/loaders/LoaderException.java | 5 - .../hydra/loaders/RequestAsyncTaskLoader.java | 4 +- .../zeus/hydra/loaders/ThrowableEither.java | 1 + .../minerva/auth/MinervaAuthenticator.java | 2 +- .../auth/requests/AccessTokenRequest.java | 2 +- .../zeus/hydra/minerva/sync/SyncAdapter.java | 4 +- .../requests/SpecialRemoteEventRequest.java | 2 +- .../requests/common/AbstractRequest.java | 2 + .../common/ProcessableCacheRequest.java | 10 +- .../zeus/hydra/requests/common/Request.java | 2 + .../hydra/requests/common/TokenRequest.java | 2 + .../RequestFailureException.java | 4 +- .../RestTemplateException.java | 2 +- .../TokenException.java | 5 +- .../requests/executor/RequestCallback.java | 27 ---- .../requests/minerva/MinervaRequest.java | 4 +- 43 files changed, 263 insertions(+), 330 deletions(-) delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/fragments/common/ItemAdapterLoaderFragment.java delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java create mode 100644 app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderCallbackHandler.java rename app/src/main/java/be/ugent/zeus/hydra/requests/{common => exceptions}/RequestFailureException.java (76%) rename app/src/main/java/be/ugent/zeus/hydra/requests/{common => exceptions}/RestTemplateException.java (85%) rename app/src/main/java/be/ugent/zeus/hydra/requests/{common => exceptions}/TokenException.java (64%) delete mode 100644 app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestCallback.java diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java index 1a4448487..917e75c67 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/common/LoaderToolbarActivity.java @@ -1,10 +1,9 @@ package be.ugent.zeus.hydra.activities.common; -import android.content.Context; -import android.os.Bundle; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; +import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.util.Log; import android.view.View; @@ -12,7 +11,8 @@ import android.widget.Toast; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.loaders.ErrorLoaderCallback; +import be.ugent.zeus.hydra.caching.CacheRequest; +import be.ugent.zeus.hydra.loaders.LoaderCallbackHandler; import be.ugent.zeus.hydra.loaders.RequestAsyncTaskLoader; import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.requests.common.SimpleCacheRequest; @@ -24,12 +24,12 @@ * * @author Niko Strijbol */ -public abstract class LoaderToolbarActivity extends ToolbarActivity implements ErrorLoaderCallback { +public abstract class LoaderToolbarActivity extends ToolbarActivity implements LoaderCallbackHandler.LoaderCallback, LoaderCallbackHandler.ProgressbarListener { private static final String TAG = "LoaderToolbarActivity"; + protected LoaderCallbackHandler loaderHandler = new LoaderCallbackHandler<>(this, this); // ID of the loader. - private static final int LOADER = 0; protected boolean shouldRenew = false; //The progress bar. Is used if not null. protected ProgressBar progressBar; @@ -43,72 +43,27 @@ public abstract class LoaderToolbarActivity extends Tool public void setContentView(@LayoutRes int layoutResID) { super.setContentView(layoutResID); progressBar = $(R.id.progress_bar); - } - /** - * Hide the progress bar. - */ - private void hideProgressBar() { - progressBar.setVisibility(View.GONE); - } - - /** - * Called when a previously created loader is being reset, and thus making its data unavailable. The application - * should at this point remove any references it has to the Loader's data. - * - * @param loader The Loader that is being reset. - */ @Override - public void onLoaderReset(Loader> loader) { - loader.reset(); + public LoaderManager getTheLoaderManager() { + return getSupportLoaderManager(); } - /** - * Called when a previously created loader has finished its load. - * - * @param loader The Loader that has finished. - * @param data The data generated by the Loader. - */ - @Override - public void onLoadFinished(Loader> loader, ThrowableEither data) { - if(data.hasError()) { - receiveError(data.getError()); - } else { - receiveData(data.getData()); - } - hideProgressBar(); + public void hideProgressBar() { + progressBar.setVisibility(View.GONE); } - /** - * Instantiate and return a new Loader for the given ID. - * - * @param id The ID whose loader is to be created. - * @param args Any arguments supplied by the caller. - * - * @return Return a new Loader instance that is ready to start loading. - */ - @Override - public Loader> onCreateLoader(int id, Bundle args) { - Context c = getApplicationContext(); - return new RequestAsyncTaskLoader<>(new SimpleCacheRequest<>(c, getRequest(), shouldRenew), c); + public void showProgressBar() { + progressBar.setVisibility(View.VISIBLE); } - /** - * Start the loader. - */ - protected void startLoader() { - // Start the data loader. - getSupportLoaderManager().initLoader(LOADER, null, this); + @Override + public Loader> getLoader() { + return new RequestAsyncTaskLoader<>(new SimpleCacheRequest<>(this, getRequest(), shouldRenew), this); } - /** - * Restart the loader. - */ - protected void restartLoader() { - // Start the data loader. - getSupportLoaderManager().restartLoader(LOADER, null, this); - } + protected abstract CacheRequest getRequest(); /** * When the request has failed. @@ -132,7 +87,7 @@ public void onClick(View v) { protected void refresh() { Toast.makeText(getApplicationContext(), R.string.begin_refresh, Toast.LENGTH_SHORT).show(); shouldRenew = true; - restartLoader(); + loaderHandler.restartLoader(); shouldRenew = false; } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java index a1933429c..6a9f31e04 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/minerva/AuthActivity.java @@ -17,7 +17,7 @@ import be.ugent.zeus.hydra.minerva.auth.models.BearerToken; import be.ugent.zeus.hydra.minerva.auth.models.GrantInformation; import be.ugent.zeus.hydra.requests.common.Request; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import be.ugent.zeus.hydra.requests.minerva.UserInfoRequest; import be.ugent.zeus.hydra.utils.customtabs.ActivityHelper; import be.ugent.zeus.hydra.utils.customtabs.CustomTabsHelper; diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java index 6085c286f..e5e0a96d2 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/preferences/AssociationSelectPrefActivity.java @@ -61,7 +61,7 @@ public String getDisplayValue(Association element) { scroller.setRecyclerView(recyclerView); searchView.setOnQueryTextListener(adapter); - startLoader(); + loaderHandler.startLoader(); } @Override diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java index 7a2fbc08f..fdc4c4f99 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MenuActivity.java @@ -5,14 +5,13 @@ import android.support.annotation.NonNull; import android.support.design.widget.AppBarLayout; import android.support.design.widget.TabLayout; -import android.support.v4.content.Loader; import android.support.v4.view.ViewPager; import be.ugent.zeus.hydra.HydraApplication; import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.resto.common.RestoWebsiteActivity; import be.ugent.zeus.hydra.fragments.resto.RestoFragment; -import be.ugent.zeus.hydra.loaders.ThrowableEither; +import be.ugent.zeus.hydra.loaders.LoaderCallbackHandler; import be.ugent.zeus.hydra.models.resto.RestoMenu; import be.ugent.zeus.hydra.models.resto.RestoOverview; import be.ugent.zeus.hydra.requests.resto.RestoMenuOverviewRequest; @@ -27,7 +26,7 @@ * * @author Niko Strijbol */ -public class MenuActivity extends RestoWebsiteActivity { +public class MenuActivity extends RestoWebsiteActivity implements LoaderCallbackHandler.ResetListener { public static final String ARG_DATE = "start_date"; @@ -37,6 +36,10 @@ public class MenuActivity extends RestoWebsiteActivity { private ViewPager mViewPager; private LocalDate startDate; + public MenuActivity() { + this.loaderHandler.setResetListener(this); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -76,7 +79,7 @@ public void onPageSelected(int position) { startDate = start.toLocalDate(); } - startLoader(); + loaderHandler.startLoader(); } /** @@ -105,20 +108,13 @@ public void receiveData(@NonNull RestoOverview data) { } } - /** - * Called when a previously created loader is being reset, and thus making its data unavailable. The application - * should at this point remove any references it has to the Loader's data. - * - * @param loader The Loader that is being reset. - */ @Override - public void onLoaderReset(Loader> loader) { - super.onLoaderReset(loader); - pageAdapter.setData(Collections.emptyList()); + public RestoMenuOverviewRequest getRequest() { + return new RestoMenuOverviewRequest(); } @Override - public RestoMenuOverviewRequest getRequest() { - return new RestoMenuOverviewRequest(); + public void onLoaderReset() { + pageAdapter.setData(Collections.emptyList()); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MetaActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MetaActivity.java index 68af77a94..9c006da32 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MetaActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/MetaActivity.java @@ -4,7 +4,6 @@ import android.support.annotation.NonNull; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.view.View; import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.resto.common.RestoActivity; @@ -45,7 +44,7 @@ protected void onCreate(Bundle savedInstanceState) { recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(adapter); - startLoader(); + loaderHandler.startLoader(); } /** diff --git a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/SandwichActivity.java b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/SandwichActivity.java index 80654cf1c..5238aac61 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/activities/resto/SandwichActivity.java +++ b/app/src/main/java/be/ugent/zeus/hydra/activities/resto/SandwichActivity.java @@ -4,7 +4,6 @@ import android.support.annotation.NonNull; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.view.View; import be.ugent.zeus.hydra.R; import be.ugent.zeus.hydra.activities.resto.common.RestoWebsiteActivity; @@ -47,7 +46,7 @@ public void onCreate(Bundle savedInstanceState) { RecyclerFastScroller s = $(R.id.fast_scroller); s.attachRecyclerView(recyclerView); - startLoader(); + loaderHandler.startLoader(); } /** diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java b/app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java index d5946bc4e..8f5584daf 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/Cache.java @@ -3,7 +3,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import java.io.Serializable; diff --git a/app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java b/app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java index 18b3c7641..b19f51c0d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java +++ b/app/src/main/java/be/ugent/zeus/hydra/caching/GenericCache.java @@ -6,7 +6,7 @@ import android.util.Log; import be.ugent.zeus.hydra.BuildConfig; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import org.threeten.bp.Duration; import java.io.File; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/ActivitiesFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/ActivitiesFragment.java index d593d3270..ae524ba79 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/ActivitiesFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/ActivitiesFragment.java @@ -146,7 +146,7 @@ public void receiveData(@NonNull Activities data) { * @return The request that will be executed. */ @Override - public ActivitiesRequest getRequest() { + protected ActivitiesRequest getRequest() { return new ActivitiesRequest(); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java index fa785baed..43a89076a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/InfoFragment.java @@ -59,14 +59,13 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { @Override public void receiveData(@NonNull InfoList data) { adapter.setItems(data); - hideProgressBar(); } /** * @return The request that will be executed. */ @Override - public InfoRequest getRequest() { + protected InfoRequest getRequest() { return new InfoRequest(); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/NewsFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/NewsFragment.java index a1361ff80..60c234975 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/NewsFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/NewsFragment.java @@ -34,7 +34,7 @@ protected NewsAdapter getAdapter() { * @return The request that will be executed. */ @Override - public NewsRequest getRequest() { + protected NewsRequest getRequest() { return new NewsRequest(); } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/SchamperFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/SchamperFragment.java index b85a4bfb8..747a7c7f5 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/SchamperFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/SchamperFragment.java @@ -6,17 +6,17 @@ import android.view.ViewGroup; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.fragments.common.ItemAdapterLoaderFragment; +import be.ugent.zeus.hydra.fragments.common.RecyclerLoaderFragment; import be.ugent.zeus.hydra.models.schamper.Article; import be.ugent.zeus.hydra.models.schamper.Articles; -import be.ugent.zeus.hydra.recyclerview.adapters.common.ItemAdapter; import be.ugent.zeus.hydra.recyclerview.adapters.SchamperListAdapter; +import be.ugent.zeus.hydra.recyclerview.adapters.common.ItemAdapter; import be.ugent.zeus.hydra.requests.SchamperArticlesRequest; /** * Created by feliciaan on 17/06/16. */ -public class SchamperFragment extends ItemAdapterLoaderFragment { +public class SchamperFragment extends RecyclerLoaderFragment> { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_recycler_view, container, false); @@ -34,7 +34,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa * @return The request that will be executed. */ @Override - public SchamperArticlesRequest getRequest() { + protected SchamperArticlesRequest getRequest() { return new SchamperArticlesRequest(); } -} +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java index 3e22111cf..36223cb0f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/CachedLoaderFragment.java @@ -1,9 +1,8 @@ package be.ugent.zeus.hydra.fragments.common; -import android.os.Bundle; import android.support.v4.content.Loader; -import be.ugent.zeus.hydra.loaders.ErrorLoaderCallback; +import be.ugent.zeus.hydra.caching.CacheRequest; import be.ugent.zeus.hydra.loaders.RequestAsyncTaskLoader; import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.requests.common.SimpleCacheRequest; @@ -18,18 +17,15 @@ * * @author Niko Strijbol */ -public abstract class CachedLoaderFragment extends LoaderFragment implements ErrorLoaderCallback { +public abstract class CachedLoaderFragment extends LoaderFragment { - /** - * Instantiate and return a new Loader for the given ID. - * - * @param id The ID whose loader is to be created. - * @param args Any arguments supplied by the caller. - * - * @return Return a new Loader instance that is ready to start loading. - */ @Override - public Loader> onCreateLoader(int id, Bundle args) { + public Loader> getLoader() { return new RequestAsyncTaskLoader<>(new SimpleCacheRequest<>(getContext(), getRequest(), shouldRenew), getContext()); } + + /** + * @return The request that will be executed. + */ + protected abstract CacheRequest getRequest(); } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/ItemAdapterLoaderFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/ItemAdapterLoaderFragment.java deleted file mode 100644 index 753b54b45..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/ItemAdapterLoaderFragment.java +++ /dev/null @@ -1,12 +0,0 @@ -package be.ugent.zeus.hydra.fragments.common; - -import java.io.Serializable; -import java.util.List; - -import be.ugent.zeus.hydra.recyclerview.adapters.common.ItemAdapter; - -/** - * @author Niko Strijbol - */ -public abstract class ItemAdapterLoaderFragment> extends RecyclerLoaderFragment> { -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java index dc2be7366..4dc004a30 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/common/LoaderFragment.java @@ -6,37 +6,26 @@ import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; import android.util.Log; import android.view.View; import android.widget.ProgressBar; import android.widget.Toast; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.loaders.ThrowableEither; -import be.ugent.zeus.hydra.requests.executor.RequestCallback; +import be.ugent.zeus.hydra.loaders.LoaderCallbackHandler; import static be.ugent.zeus.hydra.utils.ViewUtils.$; /** - * Fragment that loads {@link be.ugent.zeus.hydra.caching.CacheRequest} using a loader. - * - * The fragment supports a progress bar and refresh. The progress bar is automatically hidden. This fragment is - * mostly used in the home screen. - * * @author Niko Strijbol */ -public abstract class LoaderFragment extends Fragment implements LoaderManager.LoaderCallbacks>, RequestCallback { +public abstract class LoaderFragment extends Fragment implements LoaderCallbackHandler.LoaderCallback, LoaderCallbackHandler.ProgressbarListener { private static final String TAG = "CachedLoaderFragment"; - // ID of the loader. - private static final int LOADER = 0; - + protected LoaderCallbackHandler loaderHandler = new LoaderCallbackHandler<>(this, this); protected boolean shouldRenew = false; - protected ProgressBar progressBar; - protected boolean autoStart = true; @Override @@ -48,14 +37,14 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { /** * Hide the progress bar. */ - protected void hideProgressBar() { + public void hideProgressBar() { progressBar.setVisibility(View.GONE); } /** * Show the progress bar. */ - protected void showProgressBar() { + public void showProgressBar() { progressBar.setVisibility(View.VISIBLE); } @@ -65,65 +54,18 @@ protected void showProgressBar() { protected void refresh() { Toast.makeText(getContext(), R.string.begin_refresh, Toast.LENGTH_SHORT).show(); this.shouldRenew = true; - restartLoader(); + loaderHandler.restartLoader(); this.shouldRenew = false; } - /** - * Called when a previously created loader has finished its load. - * - * @param loader The Loader that has finished. - * @param data The data generated by the Loader. - */ - @Override - public void onLoadFinished(Loader> loader, ThrowableEither data) { - if(data.hasError()) { - receiveError(data.getError()); - } else { - receiveData(data.getData()); - } - hideProgressBar(); - } - - /** - * Called when a previously created loader is being reset, and thus making its data unavailable. The application - * should at this point remove any references it has to the Loader's data. - * - * @param loader The Loader that is being reset. - */ - @Override - public void onLoaderReset(Loader> loader) { - loader.reset(); - } - @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if(autoStart) { - startLoader(); + loaderHandler.startLoader(); } } - /** - * Start the loader. - */ - protected void startLoader() { - // Start the data loader. - getLoaderManager().initLoader(LOADER, null, this); - } - - /** - * Restart the loader. - */ - protected void restartLoader() { - // Start the data loader. - getLoaderManager().restartLoader(LOADER, null, this); - } - - protected void destroyLoader() { - getLoaderManager().destroyLoader(LOADER); - } - /** * This must be called when an error occurred. * @@ -134,16 +76,22 @@ protected void destroyLoader() { @Override public void receiveError(@NonNull Throwable error) { assert getView() != null; + hideProgressBar(); Log.e(TAG, "Error while getting data.", error); Snackbar.make(getView(), getString(R.string.failure), Snackbar.LENGTH_LONG) .setAction(getString(R.string.again), new View.OnClickListener() { @Override public void onClick(View v) { shouldRenew = true; - restartLoader(); + loaderHandler.restartLoader(); shouldRenew = false; } }) .show(); } + + @Override + public LoaderManager getTheLoaderManager() { + return getLoaderManager(); + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java index d7ad43abd..328646a3c 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/HomeLoaderCallback.java @@ -1,7 +1,6 @@ package be.ugent.zeus.hydra.fragments.home; import android.content.Context; -import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; @@ -11,7 +10,6 @@ import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.models.cards.HomeCard; import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; -import be.ugent.zeus.hydra.requests.executor.RequestCallback; import java.util.Collections; import java.util.List; @@ -22,7 +20,7 @@ * * @author Niko Strijbol */ -abstract class HomeLoaderCallback implements LoaderManager.LoaderCallbacks>>, RequestCallback> { +abstract class HomeLoaderCallback implements LoaderManager.LoaderCallbacks>> { protected final Context context; protected final HomeCardAdapter adapter; @@ -34,29 +32,6 @@ public HomeLoaderCallback(Context context, HomeCardAdapter adapter, FragmentCall this.callback = callback; } - @Override - public void receiveData(@NonNull List data) { - - if(!isTypeActive()) { - return; - } - - adapter.updateCardItems(data, getCardType()); - callback.onCompleted(); - } - - @Override - public void receiveError(@NonNull Throwable error) { - if(!isTypeActive()) { - return; - } - - String e = this.context.getString(R.string.fragment_home_error); - String name = this.context.getString(getErrorName()); - - callback.onError(String.format(e, name)); - } - /** * @return The card type of the cards that are produced here. */ @@ -87,10 +62,17 @@ protected boolean isTypeActive() { */ @Override public void onLoadFinished(Loader>> loader, ThrowableEither> data) { + + if(!isTypeActive()) { + return; + } + if (data.hasError()) { - receiveError(data.getError()); + String errorName = context.getString(getErrorName()); + callback.onError(String.format(context.getString(R.string.fragment_home_error), errorName)); } else { - receiveData(data.getData()); + adapter.updateCardItems(data.getData(), getCardType()); + callback.onCompleted(); } } @@ -102,6 +84,6 @@ public void onLoadFinished(Loader>> loader, Throw */ @Override public void onLoaderReset(Loader>> loader) { - loader.reset(); + // } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java index 14c16b427..125880124 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/home/SpecialEventCallback.java @@ -16,7 +16,7 @@ import be.ugent.zeus.hydra.models.specialevent.SpecialEventWrapper; import be.ugent.zeus.hydra.recyclerview.adapters.HomeCardAdapter; import be.ugent.zeus.hydra.requests.SpecialRemoteEventRequest; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import org.threeten.bp.ZonedDateTime; import java.util.ArrayList; diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java index ec118a413..6bdc71cf6 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAgendaFragment.java @@ -69,19 +69,6 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { recyclerView.setAdapter(adapter); } - /** - * Instantiate and return a new Loader for the given ID. - * - * @param id The ID whose loader is to be created. - * @param args Any arguments supplied by the caller. - * - * @return Return a new Loader instance that is ready to start loading. - */ - @Override - public Loader>> onCreateLoader(int id, Bundle args) { - return new AgendaDaoLoader(getContext(), dao, course); - } - /** * Receive the data if the request was completed successfully. * @@ -90,5 +77,11 @@ public Loader>> onCreateLoader(int id, Bundle a @Override public void receiveData(@NonNull List data) { adapter.setItems(data); + hideProgressBar(); + } + + @Override + public Loader>> getLoader() { + return new AgendaDaoLoader(getContext(), dao, course); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java index 5719c3507..0f941828d 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/CourseAnnouncementFragment.java @@ -84,19 +84,6 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { recyclerView.setAdapter(joiner.getAdapter()); } - /** - * Instantiate and return a new Loader for the given ID. - * - * @param id The ID whose loader is to be created. - * @param args Any arguments supplied by the caller. - * - * @return Return a new Loader instance that is ready to start loading. - */ - @Override - public Loader>> onCreateLoader(int id, Bundle args) { - return new AnnouncementDaoLoader(getContext(), dao, course); - } - /** * Receive the data if the request was completed successfully. * @@ -134,4 +121,9 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } } } + + @Override + public Loader>> getLoader() { + return new AnnouncementDaoLoader(getContext(), dao, course); + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java index 11c84e1f7..42c746c65 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/minerva/MinervaFragment.java @@ -19,11 +19,11 @@ import android.widget.Toast; import be.ugent.zeus.hydra.R; -import be.ugent.zeus.hydra.minerva.auth.AccountUtils; -import be.ugent.zeus.hydra.minerva.auth.MinervaConfig; import be.ugent.zeus.hydra.fragments.common.LoaderFragment; import be.ugent.zeus.hydra.loaders.ThrowableEither; import be.ugent.zeus.hydra.minerva.announcement.AnnouncementDao; +import be.ugent.zeus.hydra.minerva.auth.AccountUtils; +import be.ugent.zeus.hydra.minerva.auth.MinervaConfig; import be.ugent.zeus.hydra.minerva.course.CourseDao; import be.ugent.zeus.hydra.minerva.course.CourseDaoLoader; import be.ugent.zeus.hydra.minerva.sync.SyncAdapter; @@ -171,7 +171,7 @@ private void maybeLoadData() { if(isLoggedIn()) { authWrapper.setVisibility(View.GONE); showProgressBar(); - startLoader(); + loaderHandler.startLoader(); } } @@ -187,11 +187,6 @@ public void receiveData(@NonNull List data) { getActivity().invalidateOptionsMenu(); } - @Override - public Loader>> onCreateLoader(int id, Bundle args) { - return new CourseDaoLoader(getContext(), courseDao); - } - @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if(isLoggedIn()) { @@ -232,7 +227,7 @@ public void run(AccountManagerFuture accountManagerFuture) { //Show login prompt authWrapper.setVisibility(View.VISIBLE); //Destroy loaders - destroyLoader(); + loaderHandler.destroyLoader(); //Delete database clearDatabase(); //Reload options @@ -252,7 +247,6 @@ public void onResume() { super.onResume(); LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getContext()); manager.registerReceiver(syncReceiver, SyncBroadcast.getBroadcastFilter()); - //getContext().registerReceiver(syncReceiver, SyncBroadcast.getBroadcastFilter()); } @Override @@ -260,7 +254,6 @@ public void onPause() { super.onPause(); LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getContext()); manager.unregisterReceiver(syncReceiver); - //getContext().unregisterReceiver(syncReceiver); } //This will only be called if manually set to send broadcasts. @@ -279,7 +272,7 @@ public void onReceive(Context context, Intent intent) { syncBar.dismiss(); syncBar = null; recyclerView.setVisibility(View.VISIBLE); - restartLoader(); + loaderHandler.restartLoader(); return; case SyncBroadcast.SYNC_ERROR: Log.d(TAG, "Error"); @@ -318,4 +311,9 @@ private void ensureSyncStatus(String text) { syncBar.setText(text); } } + + @Override + public Loader>> getLoader() { + return new CourseDaoLoader(getContext(), courseDao); + } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java index 275843cde..5d283d2ca 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/resto/RestoFragment.java @@ -117,8 +117,6 @@ private void setIcons() { @Override public void receiveData(@NonNull RestoOverview data) { - //FragmentManager m = getChildFragmentManager(); - //We can't do anything without data. if(data.size() < 2) { return; @@ -139,7 +137,7 @@ public void receiveData(@NonNull RestoOverview data) { * @return The request that will be executed. */ @Override - public RestoMenuOverviewRequest getRequest() { + protected RestoMenuOverviewRequest getRequest() { return new RestoMenuOverviewRequest(); } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/LineupFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/LineupFragment.java index fd1726d4c..15a674659 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/LineupFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/LineupFragment.java @@ -95,7 +95,7 @@ public void receiveData(@NonNull Artists data) { @Override public void onRefresh() { shouldRenew = true; - restartLoader(); + loaderHandler.restartLoader(); shouldRenew = false; } @@ -116,7 +116,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } @Override - public LineupRequest getRequest() { + protected LineupRequest getRequest() { return new LineupRequest(); } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java index 049402337..3ac34ae1a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/TimelineFragment.java @@ -76,14 +76,14 @@ public void receiveData(@NonNull Timeline data) { } @Override - public TimelineRequest getRequest() { + protected TimelineRequest getRequest() { return new TimelineRequest(); } @Override public void onRefresh() { shouldRenew = true; - restartLoader(); + loaderHandler.restartLoader(); shouldRenew = false; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java index 515d704f3..b356cc5a9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java +++ b/app/src/main/java/be/ugent/zeus/hydra/fragments/sko/VillageFragment.java @@ -61,7 +61,7 @@ public void receiveData(@NonNull Exhibitors data) { } @Override - public StuVilExhibitorRequest getRequest() { + protected StuVilExhibitorRequest getRequest() { return new StuVilExhibitorRequest(); } @@ -85,7 +85,7 @@ public boolean onOptionsItemSelected(MenuItem item) { public void onRefresh() { shouldRenew = true; searchView.setQuery("", false); - restartLoader(); + loaderHandler.restartLoader(); shouldRenew = false; } } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/AbstractAsyncLoader.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/AbstractAsyncLoader.java index 44fbac849..6187e0370 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/loaders/AbstractAsyncLoader.java +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/AbstractAsyncLoader.java @@ -6,12 +6,15 @@ import android.support.v4.os.OperationCanceledException; /** - * Abstract background loader. + * Abstract background loader. This loader loads data into a {@link ThrowableEither}, to be able to communicate errors + * to the requester. + * + * Why a class like this is not already in the API is beyond me, as this class is, for the most part, copying code from + * Google's tutorials. * * @param The result of the request. * * @author Niko Strijbol - * @see Implementing loaders */ public abstract class AbstractAsyncLoader extends AsyncTaskLoader> { diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java deleted file mode 100644 index 12dcd470f..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/loaders/ErrorLoaderCallback.java +++ /dev/null @@ -1,20 +0,0 @@ -package be.ugent.zeus.hydra.loaders; - -import android.support.v4.app.LoaderManager; - -import be.ugent.zeus.hydra.caching.CacheRequest; -import be.ugent.zeus.hydra.requests.executor.RequestCallback; - -/** - * Defines additional methods a class should implement to work with {@link ThrowableEither} as a response. - * Note that this is not at all necessary, but may be a guide for correct implementation. - * - * @author Niko Strijbol - */ -public interface ErrorLoaderCallback extends LoaderManager.LoaderCallbacks>, RequestCallback { - - /** - * @return The request that will be executed. - */ - CacheRequest getRequest(); -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderCallbackHandler.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderCallbackHandler.java new file mode 100644 index 000000000..e4ae8a0a7 --- /dev/null +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderCallbackHandler.java @@ -0,0 +1,125 @@ +package be.ugent.zeus.hydra.loaders; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; + +/** + * Class that simplifies and abstracts a lot of the working with loaders in a portable way. While this functionality + * could be implemented in a super class of Activity or Fragment, there is no way to re-use the code for both, which + * is way this class exists. + * + * @author Niko Strijbol + */ +public class LoaderCallbackHandler implements LoaderManager.LoaderCallbacks> { + + private static int LOADER_ID = 0; + + private final LoaderCallback callback; + private final ProgressbarListener listener; + private ResetListener resetListener; + + public LoaderCallbackHandler(LoaderCallback callback) { + this(callback, null); + } + + public LoaderCallbackHandler(LoaderCallback callback, ProgressbarListener listener) { + this.callback = callback; + this.listener = listener; + } + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return callback.getLoader(); + } + + @Override + public void onLoadFinished(Loader> loader, ThrowableEither data) { + if(data.hasError()) { + callback.receiveError(data.getError()); + } else { + callback.receiveData(data.getData()); + } + if(listener != null) { + listener.hideProgressBar(); + } + } + + @Override + public void onLoaderReset(Loader> loader) { + if(resetListener != null) { + resetListener.onLoaderReset(); + } + } + + public void setResetListener(ResetListener listener) { + this.resetListener = listener; + } + + /** + * Start the loader. + */ + public void startLoader() { + // Start the data loader. + callback.getTheLoaderManager().initLoader(LOADER_ID, null, this); + } + + /** + * Restart the loader. + */ + public void restartLoader() { + // Start the data loader. + callback.getTheLoaderManager().restartLoader(LOADER_ID, null, this); + } + + public void destroyLoader() { + callback.getTheLoaderManager().destroyLoader(LOADER_ID); + } + + /** + * Provides a simple interface to implement to work with loaders. + * + * @author Niko Strijbol + */ + public interface LoaderCallback { + + /** + * You will probably not implement this method yourself. The activity or fragment implementing this interface + * should already have this method. + * + * @return The loader manager. + */ + LoaderManager getTheLoaderManager(); + + /** + * Receive the data if the request was completed successfully. + * + * @param data The data. + */ + void receiveData(@NonNull T data); + + /** + * Receive an error if the request failed for some reason. + * + * @param e The occurred exception. + */ + void receiveError(@NonNull Throwable e); + + /** + * Provide the loader to use. + * + * @return The loader to use. + */ + Loader> getLoader(); + } + + public interface ProgressbarListener { + void hideProgressBar(); + void showProgressBar(); + } + + public interface ResetListener { + void onLoaderReset(); + } +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderException.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderException.java index 09009a79b..9d42aee98 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderException.java +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/LoaderException.java @@ -7,12 +7,7 @@ */ public class LoaderException extends Exception { - public LoaderException() { - super(); - } - public LoaderException(Throwable cause) { super(cause); } - } \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java index c76e4f2c7..202d7b33b 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/RequestAsyncTaskLoader.java @@ -4,7 +4,7 @@ import android.support.annotation.NonNull; import be.ugent.zeus.hydra.requests.common.Request; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; /** * Loader to load data from a {@link Request}. @@ -33,4 +33,4 @@ protected D getData() throws LoaderException { throw new LoaderException(e); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/loaders/ThrowableEither.java b/app/src/main/java/be/ugent/zeus/hydra/loaders/ThrowableEither.java index 76b1b8d29..b49c55f5f 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/loaders/ThrowableEither.java +++ b/app/src/main/java/be/ugent/zeus/hydra/loaders/ThrowableEither.java @@ -13,6 +13,7 @@ * * @author Niko Strijbol */ +@SuppressWarnings("unused") public final class ThrowableEither { private final D data; diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java index 785472a2e..3bbc61389 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/MinervaAuthenticator.java @@ -11,7 +11,7 @@ import be.ugent.zeus.hydra.activities.minerva.AuthActivity; import be.ugent.zeus.hydra.minerva.auth.models.BearerToken; import be.ugent.zeus.hydra.requests.common.Request; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import org.threeten.bp.LocalDateTime; import org.threeten.bp.format.DateTimeFormatter; diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/requests/AccessTokenRequest.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/requests/AccessTokenRequest.java index ae2624b8e..7a25fdc65 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/requests/AccessTokenRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/auth/requests/AccessTokenRequest.java @@ -4,7 +4,7 @@ import be.ugent.zeus.hydra.minerva.auth.OAuthConfiguration; import be.ugent.zeus.hydra.minerva.auth.models.BearerToken; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import be.ugent.zeus.hydra.requests.common.Request; import com.google.gson.Gson; import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse; diff --git a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java index 1ffaaea01..1d0a0281a 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java +++ b/app/src/main/java/be/ugent/zeus/hydra/minerva/sync/SyncAdapter.java @@ -18,8 +18,8 @@ import be.ugent.zeus.hydra.models.minerva.Course; import be.ugent.zeus.hydra.models.minerva.Courses; import be.ugent.zeus.hydra.models.minerva.WhatsNew; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; -import be.ugent.zeus.hydra.requests.common.RestTemplateException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RestTemplateException; import be.ugent.zeus.hydra.requests.minerva.AgendaRequest; import be.ugent.zeus.hydra.requests.minerva.CoursesMinervaRequest; import be.ugent.zeus.hydra.requests.minerva.WhatsNewRequest; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialRemoteEventRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialRemoteEventRequest.java index 5373ee208..0ead2ff2e 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialRemoteEventRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/SpecialRemoteEventRequest.java @@ -9,7 +9,7 @@ import be.ugent.zeus.hydra.models.specialevent.SpecialEventWrapper; import be.ugent.zeus.hydra.models.specialevent.SpecialEvents; import be.ugent.zeus.hydra.requests.common.Request; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import com.google.android.gms.tasks.Tasks; import com.google.firebase.remoteconfig.FirebaseRemoteConfig; import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/AbstractRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/AbstractRequest.java index 5fbe4ac88..e7bc5ee76 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/AbstractRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/AbstractRequest.java @@ -2,6 +2,8 @@ import android.support.annotation.NonNull; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.RestTemplateException; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.json.GsonHttpMessageConverter; import org.springframework.web.client.RestClientException; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java index f970d9dac..ff470b390 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/ProcessableCacheRequest.java @@ -6,6 +6,7 @@ import be.ugent.zeus.hydra.caching.Cache; import be.ugent.zeus.hydra.caching.CacheManager; import be.ugent.zeus.hydra.caching.CacheRequest; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; import java.io.Serializable; @@ -24,8 +25,15 @@ public ProcessableCacheRequest(Context context, CacheRequest request) { this(context, request, false); } + /** + * Create a request. + * + * @param context A context. Can be any context, as the application context is taken. + * @param request The request. + * @param shouldRefresh Should fresh data be used or not. + */ public ProcessableCacheRequest(Context context, CacheRequest request, boolean shouldRefresh) { - this.context = context; + this.context = context.getApplicationContext(); this.cacheRequest = request; this.shouldRefresh = shouldRefresh; } diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java index 39dbf234b..34e6ff994 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/Request.java @@ -2,6 +2,8 @@ import android.support.annotation.NonNull; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; + /** * The basis interface for a request. A request is something that returns data, not unlike a AsyncTask, but without * any constraints. It is basically a replacement for Supplier in Java 8. diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/TokenRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/common/TokenRequest.java index 71f680869..e5fce58c5 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/TokenRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/common/TokenRequest.java @@ -1,6 +1,8 @@ package be.ugent.zeus.hydra.requests.common; import be.ugent.zeus.hydra.minerva.auth.requests.TokenRequestInterceptor; +import be.ugent.zeus.hydra.requests.exceptions.RestTemplateException; +import be.ugent.zeus.hydra.requests.exceptions.TokenException; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.web.client.RestTemplate; diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/RequestFailureException.java b/app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/RequestFailureException.java similarity index 76% rename from app/src/main/java/be/ugent/zeus/hydra/requests/common/RequestFailureException.java rename to app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/RequestFailureException.java index d89c4578f..e57bf1502 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/RequestFailureException.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/RequestFailureException.java @@ -1,4 +1,6 @@ -package be.ugent.zeus.hydra.requests.common; +package be.ugent.zeus.hydra.requests.exceptions; + +import be.ugent.zeus.hydra.requests.common.Request; /** * Exception thrown by a {@link Request} when something goes wrong while producing the data. diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/RestTemplateException.java b/app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/RestTemplateException.java similarity index 85% rename from app/src/main/java/be/ugent/zeus/hydra/requests/common/RestTemplateException.java rename to app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/RestTemplateException.java index 66eab7505..be8d0d8b9 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/RestTemplateException.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/RestTemplateException.java @@ -1,4 +1,4 @@ -package be.ugent.zeus.hydra.requests.common; +package be.ugent.zeus.hydra.requests.exceptions; /** * Exception thrown when the rest template could not be made. diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/common/TokenException.java b/app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/TokenException.java similarity index 64% rename from app/src/main/java/be/ugent/zeus/hydra/requests/common/TokenException.java rename to app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/TokenException.java index 0f98294ca..6734a6313 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/common/TokenException.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/exceptions/TokenException.java @@ -1,4 +1,4 @@ -package be.ugent.zeus.hydra.requests.common; +package be.ugent.zeus.hydra.requests.exceptions; /** * Exception thrown when something went wrong while getting a token. @@ -11,7 +11,4 @@ public TokenException() { super(); } - public TokenException(Throwable cause) { - super(cause); - } } diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestCallback.java b/app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestCallback.java deleted file mode 100644 index 42a1f304d..000000000 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/executor/RequestCallback.java +++ /dev/null @@ -1,27 +0,0 @@ -package be.ugent.zeus.hydra.requests.executor; - -import android.support.annotation.NonNull; - -/** - * Callback for the requests. This callback will be called - * - * @param The result. - * - * @author Niko Strijbol - */ -public interface RequestCallback { - - /** - * Receive the data if the request was completed successfully. - * - * @param data The data. - */ - void receiveData(@NonNull T data); - - /** - * Receive an error if the request failed for some reason. - * - * @param e The occurred exception. - */ - void receiveError(@NonNull Throwable e); -} \ No newline at end of file diff --git a/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/MinervaRequest.java b/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/MinervaRequest.java index 9e0ce4309..28628c969 100644 --- a/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/MinervaRequest.java +++ b/app/src/main/java/be/ugent/zeus/hydra/requests/minerva/MinervaRequest.java @@ -11,8 +11,8 @@ import be.ugent.zeus.hydra.minerva.auth.AccountUtils; import be.ugent.zeus.hydra.minerva.auth.MinervaConfig; -import be.ugent.zeus.hydra.requests.common.RequestFailureException; -import be.ugent.zeus.hydra.requests.common.TokenException; +import be.ugent.zeus.hydra.requests.exceptions.RequestFailureException; +import be.ugent.zeus.hydra.requests.exceptions.TokenException; import be.ugent.zeus.hydra.requests.common.TokenRequest; import org.springframework.http.HttpStatus; import org.springframework.web.client.HttpServerErrorException;