summaryrefslogtreecommitdiff
path: root/net/sync/service-interface
diff options
context:
space:
mode:
Diffstat (limited to 'net/sync/service-interface')
-rw-r--r--net/sync/service-interface/build.gradle2
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeAction.java293
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeActionChanges.java34
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/ISyncService.java20
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SubscriptionChanges.java39
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SyncServiceException.java13
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProvider.java25
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProviderViewData.java45
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java1
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueStorage.java1
-rw-r--r--net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/UploadChangesResponse.java13
-rw-r--r--net/sync/service-interface/src/main/res/drawable-nodpi/gpodder_icon.pngbin32098 -> 0 bytes
-rw-r--r--net/sync/service-interface/src/main/res/drawable-nodpi/nextcloud_logo.pngbin3432 -> 0 bytes
-rw-r--r--net/sync/service-interface/src/main/res/values/ids.xml5
14 files changed, 437 insertions, 54 deletions
diff --git a/net/sync/service-interface/build.gradle b/net/sync/service-interface/build.gradle
index c1a559da3..fd170b36a 100644
--- a/net/sync/service-interface/build.gradle
+++ b/net/sync/service-interface/build.gradle
@@ -9,9 +9,7 @@ android {
dependencies {
implementation project(':model')
- implementation project(':net:sync:model')
implementation project(':storage:preferences')
- implementation project(':ui:i18n')
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeAction.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeAction.java
new file mode 100644
index 000000000..3c3bd1418
--- /dev/null
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeAction.java
@@ -0,0 +1,293 @@
+package de.danoeh.antennapod.net.sync.serviceinterface;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.TimeZone;
+
+import de.danoeh.antennapod.model.feed.FeedItem;
+
+public class EpisodeAction {
+ private static final String TAG = "EpisodeAction";
+ private static final String PATTERN_ISO_DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss";
+ public static final Action NEW = Action.NEW;
+ public static final Action DOWNLOAD = Action.DOWNLOAD;
+ public static final Action PLAY = Action.PLAY;
+ public static final Action DELETE = Action.DELETE;
+
+ private final String podcast;
+ private final String episode;
+ private final String guid;
+ private final Action action;
+ private final Date timestamp;
+ private final int started;
+ private final int position;
+ private final int total;
+
+ private EpisodeAction(Builder builder) {
+ this.podcast = builder.podcast;
+ this.episode = builder.episode;
+ this.guid = builder.guid;
+ this.action = builder.action;
+ this.timestamp = builder.timestamp;
+ this.started = builder.started;
+ this.position = builder.position;
+ this.total = builder.total;
+ }
+
+ /**
+ * Create an episode action object from JSON representation. Mandatory fields are "podcast",
+ * "episode" and "action".
+ *
+ * @param object JSON representation
+ * @return episode action object, or null if mandatory values are missing
+ */
+ public static EpisodeAction readFromJsonObject(JSONObject object) {
+ String podcast = object.optString("podcast", null);
+ String episode = object.optString("episode", null);
+ String actionString = object.optString("action", null);
+ if (TextUtils.isEmpty(podcast) || TextUtils.isEmpty(episode) || TextUtils.isEmpty(actionString)) {
+ return null;
+ }
+ EpisodeAction.Action action;
+ try {
+ action = EpisodeAction.Action.valueOf(actionString.toUpperCase(Locale.US));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ EpisodeAction.Builder builder = new EpisodeAction.Builder(podcast, episode, action);
+ String utcTimestamp = object.optString("timestamp", null);
+ if (!TextUtils.isEmpty(utcTimestamp)) {
+ try {
+ SimpleDateFormat parser = new SimpleDateFormat(PATTERN_ISO_DATEFORMAT, Locale.US);
+ parser.setTimeZone(TimeZone.getTimeZone("UTC"));
+ builder.timestamp(parser.parse(utcTimestamp));
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ String guid = object.optString("guid", null);
+ if (!TextUtils.isEmpty(guid)) {
+ builder.guid(guid);
+ }
+ if (action == EpisodeAction.Action.PLAY) {
+ int started = object.optInt("started", -1);
+ int position = object.optInt("position", -1);
+ int total = object.optInt("total", -1);
+ if (started >= 0 && position > 0 && total > 0) {
+ builder
+ .started(started)
+ .position(position)
+ .total(total);
+ }
+ }
+ return builder.build();
+ }
+
+ public String getPodcast() {
+ return this.podcast;
+ }
+
+ public String getEpisode() {
+ return this.episode;
+ }
+
+ public String getGuid() {
+ return this.guid;
+ }
+
+ public Action getAction() {
+ return this.action;
+ }
+
+ private String getActionString() {
+ return this.action.name().toLowerCase(Locale.US);
+ }
+
+ public Date getTimestamp() {
+ return this.timestamp;
+ }
+
+ /**
+ * Returns the position (in seconds) at which the client started playback.
+ *
+ * @return start position (in seconds)
+ */
+ public int getStarted() {
+ return this.started;
+ }
+
+ /**
+ * Returns the position (in seconds) at which the client stopped playback.
+ *
+ * @return stop position (in seconds)
+ */
+ public int getPosition() {
+ return this.position;
+ }
+
+ /**
+ * Returns the total length of the file in seconds.
+ *
+ * @return total length in seconds
+ */
+ public int getTotal() {
+ return this.total;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof EpisodeAction)) {
+ return false;
+ }
+
+ EpisodeAction that = (EpisodeAction) o;
+ return started == that.started
+ && position == that.position
+ && total == that.total
+ && action != that.action
+ && Objects.equals(podcast, that.podcast)
+ && Objects.equals(episode, that.episode)
+ && Objects.equals(timestamp, that.timestamp)
+ && Objects.equals(guid, that.guid);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = podcast != null ? podcast.hashCode() : 0;
+ result = 31 * result + (episode != null ? episode.hashCode() : 0);
+ result = 31 * result + (guid != null ? guid.hashCode() : 0);
+ result = 31 * result + (action != null ? action.hashCode() : 0);
+ result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
+ result = 31 * result + started;
+ result = 31 * result + position;
+ result = 31 * result + total;
+ return result;
+ }
+
+ /**
+ * Returns a JSON object representation of this object.
+ *
+ * @return JSON object representation, or null if the object is invalid
+ */
+ public JSONObject writeToJsonObject() {
+ JSONObject obj = new JSONObject();
+ try {
+ obj.putOpt("podcast", this.podcast);
+ obj.putOpt("episode", this.episode);
+ obj.putOpt("guid", this.guid);
+ obj.put("action", this.getActionString());
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
+ formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+ obj.put("timestamp", formatter.format(this.timestamp));
+ if (this.getAction() == Action.PLAY) {
+ obj.put("started", this.started);
+ obj.put("position", this.position);
+ obj.put("total", this.total);
+ }
+ } catch (JSONException e) {
+ Log.e(TAG, "writeToJSONObject(): " + e.getMessage());
+ return null;
+ }
+ return obj;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "EpisodeAction{"
+ + "podcast='" + podcast + '\''
+ + ", episode='" + episode + '\''
+ + ", guid='" + guid + '\''
+ + ", action=" + action
+ + ", timestamp=" + timestamp
+ + ", started=" + started
+ + ", position=" + position
+ + ", total=" + total
+ + '}';
+ }
+
+ public enum Action {
+ NEW, DOWNLOAD, PLAY, DELETE
+ }
+
+ public static class Builder {
+
+ // mandatory
+ private final String podcast;
+ private final String episode;
+ private final Action action;
+
+ // optional
+ private Date timestamp;
+ private int started = -1;
+ private int position = -1;
+ private int total = -1;
+ private String guid;
+
+ public Builder(FeedItem item, Action action) {
+ this(item.getFeed().getDownloadUrl(), item.getMedia().getDownloadUrl(), action);
+ this.guid(item.getItemIdentifier());
+ }
+
+ public Builder(String podcast, String episode, Action action) {
+ this.podcast = podcast;
+ this.episode = episode;
+ this.action = action;
+ }
+
+ public Builder timestamp(Date timestamp) {
+ this.timestamp = timestamp;
+ return this;
+ }
+
+ public Builder guid(String guid) {
+ this.guid = guid;
+ return this;
+ }
+
+ public Builder currentTimestamp() {
+ return timestamp(new Date());
+ }
+
+ public Builder started(int seconds) {
+ if (action == Action.PLAY) {
+ this.started = seconds;
+ }
+ return this;
+ }
+
+ public Builder position(int seconds) {
+ if (action == Action.PLAY) {
+ this.position = seconds;
+ }
+ return this;
+ }
+
+ public Builder total(int seconds) {
+ if (action == Action.PLAY) {
+ this.total = seconds;
+ }
+ return this;
+ }
+
+ public EpisodeAction build() {
+ return new EpisodeAction(this);
+ }
+
+ }
+
+}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeActionChanges.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeActionChanges.java
new file mode 100644
index 000000000..d2b17b492
--- /dev/null
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/EpisodeActionChanges.java
@@ -0,0 +1,34 @@
+package de.danoeh.antennapod.net.sync.serviceinterface;
+
+
+import androidx.annotation.NonNull;
+
+import java.util.List;
+
+public class EpisodeActionChanges {
+
+ private final List<EpisodeAction> episodeActions;
+ private final long timestamp;
+
+ public EpisodeActionChanges(@NonNull List<EpisodeAction> episodeActions, long timestamp) {
+ this.episodeActions = episodeActions;
+ this.timestamp = timestamp;
+ }
+
+ public List<EpisodeAction> getEpisodeActions() {
+ return this.episodeActions;
+ }
+
+ public long getTimestamp() {
+ return this.timestamp;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "EpisodeActionGetResponse{"
+ + "episodeActions=" + episodeActions
+ + ", timestamp=" + timestamp
+ + '}';
+ }
+}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/ISyncService.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/ISyncService.java
new file mode 100644
index 000000000..29632ed1e
--- /dev/null
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/ISyncService.java
@@ -0,0 +1,20 @@
+package de.danoeh.antennapod.net.sync.serviceinterface;
+
+import java.util.List;
+
+public interface ISyncService {
+
+ void login() throws SyncServiceException;
+
+ SubscriptionChanges getSubscriptionChanges(long lastSync) throws SyncServiceException;
+
+ UploadChangesResponse uploadSubscriptionChanges(
+ List<String> addedFeeds, List<String> removedFeeds) throws SyncServiceException;
+
+ EpisodeActionChanges getEpisodeActionChanges(long lastSync) throws SyncServiceException;
+
+ UploadChangesResponse uploadEpisodeActions(List<EpisodeAction> queuedEpisodeActions)
+ throws SyncServiceException;
+
+ void logout() throws SyncServiceException;
+}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SubscriptionChanges.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SubscriptionChanges.java
new file mode 100644
index 000000000..c0c9f131d
--- /dev/null
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SubscriptionChanges.java
@@ -0,0 +1,39 @@
+package de.danoeh.antennapod.net.sync.serviceinterface;
+
+import androidx.annotation.NonNull;
+
+import java.util.List;
+
+public class SubscriptionChanges {
+ private final List<String> added;
+ private final List<String> removed;
+ private final long timestamp;
+
+ public SubscriptionChanges(@NonNull List<String> added,
+ @NonNull List<String> removed,
+ long timestamp) {
+ this.added = added;
+ this.removed = removed;
+ this.timestamp = timestamp;
+ }
+
+ @Override
+ public String toString() {
+ return "SubscriptionChange [added=" + added.toString()
+ + ", removed=" + removed.toString() + ", timestamp="
+ + timestamp + "]";
+ }
+
+ public List<String> getAdded() {
+ return added;
+ }
+
+ public List<String> getRemoved() {
+ return removed;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SyncServiceException.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SyncServiceException.java
new file mode 100644
index 000000000..5ccedd785
--- /dev/null
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SyncServiceException.java
@@ -0,0 +1,13 @@
+package de.danoeh.antennapod.net.sync.serviceinterface;
+
+public class SyncServiceException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public SyncServiceException(String message) {
+ super(message);
+ }
+
+ public SyncServiceException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProvider.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProvider.java
new file mode 100644
index 000000000..8c4047b6c
--- /dev/null
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProvider.java
@@ -0,0 +1,25 @@
+package de.danoeh.antennapod.net.sync.serviceinterface;
+
+public enum SynchronizationProvider {
+ GPODDER_NET("GPODDER_NET"),
+ NEXTCLOUD_GPODDER("NEXTCLOUD_GPODDER");
+
+ public static SynchronizationProvider fromIdentifier(String provider) {
+ for (SynchronizationProvider synchronizationProvider : SynchronizationProvider.values()) {
+ if (synchronizationProvider.getIdentifier().equals(provider)) {
+ return synchronizationProvider;
+ }
+ }
+ return null;
+ }
+
+ private final String identifier;
+
+ SynchronizationProvider(String identifier) {
+ this.identifier = identifier;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProviderViewData.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProviderViewData.java
deleted file mode 100644
index 19624a95a..000000000
--- a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationProviderViewData.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package de.danoeh.antennapod.net.sync.serviceinterface;
-
-public enum SynchronizationProviderViewData {
- GPODDER_NET(
- "GPODDER_NET",
- R.string.gpodnet_description,
- R.drawable.gpodder_icon
- ),
- NEXTCLOUD_GPODDER(
- "NEXTCLOUD_GPODDER",
- R.string.synchronization_summary_nextcloud,
- R.drawable.nextcloud_logo
- );
-
- public static SynchronizationProviderViewData fromIdentifier(String provider) {
- for (SynchronizationProviderViewData synchronizationProvider : SynchronizationProviderViewData.values()) {
- if (synchronizationProvider.getIdentifier().equals(provider)) {
- return synchronizationProvider;
- }
- }
- return null;
- }
-
- private final String identifier;
- private final int iconResource;
- private final int summaryResource;
-
- SynchronizationProviderViewData(String identifier, int summaryResource, int iconResource) {
- this.identifier = identifier;
- this.iconResource = iconResource;
- this.summaryResource = summaryResource;
- }
-
- public String getIdentifier() {
- return identifier;
- }
-
- public int getIconResource() {
- return iconResource;
- }
-
- public int getSummaryResource() {
- return summaryResource;
- }
-}
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java
index 8c94c44e7..ad235130a 100644
--- a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueSink.java
@@ -4,7 +4,6 @@ import android.content.Context;
import de.danoeh.antennapod.storage.preferences.SynchronizationSettings;
import de.danoeh.antennapod.model.feed.FeedMedia;
-import de.danoeh.antennapod.net.sync.model.EpisodeAction;
public class SynchronizationQueueSink {
// To avoid a dependency loop of every class to SyncService, and from SyncService back to every class.
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueStorage.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueStorage.java
index 0ae794ac8..55dc07ae8 100644
--- a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueStorage.java
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/SynchronizationQueueStorage.java
@@ -9,7 +9,6 @@ import org.json.JSONException;
import java.util.ArrayList;
import de.danoeh.antennapod.storage.preferences.SynchronizationSettings;
-import de.danoeh.antennapod.net.sync.model.EpisodeAction;
public class SynchronizationQueueStorage {
diff --git a/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/UploadChangesResponse.java b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/UploadChangesResponse.java
new file mode 100644
index 000000000..64bddc260
--- /dev/null
+++ b/net/sync/service-interface/src/main/java/de/danoeh/antennapod/net/sync/serviceinterface/UploadChangesResponse.java
@@ -0,0 +1,13 @@
+package de.danoeh.antennapod.net.sync.serviceinterface;
+
+public abstract class UploadChangesResponse {
+
+ /**
+ * timestamp/ID that can be used for requesting changes since this upload.
+ */
+ public final long timestamp;
+
+ public UploadChangesResponse(long timestamp) {
+ this.timestamp = timestamp;
+ }
+}
diff --git a/net/sync/service-interface/src/main/res/drawable-nodpi/gpodder_icon.png b/net/sync/service-interface/src/main/res/drawable-nodpi/gpodder_icon.png
deleted file mode 100644
index cd133aa98..000000000
--- a/net/sync/service-interface/src/main/res/drawable-nodpi/gpodder_icon.png
+++ /dev/null
Binary files differ
diff --git a/net/sync/service-interface/src/main/res/drawable-nodpi/nextcloud_logo.png b/net/sync/service-interface/src/main/res/drawable-nodpi/nextcloud_logo.png
deleted file mode 100644
index 2164e37fb..000000000
--- a/net/sync/service-interface/src/main/res/drawable-nodpi/nextcloud_logo.png
+++ /dev/null
Binary files differ
diff --git a/net/sync/service-interface/src/main/res/values/ids.xml b/net/sync/service-interface/src/main/res/values/ids.xml
deleted file mode 100644
index 842e421ea..000000000
--- a/net/sync/service-interface/src/main/res/values/ids.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<resources>
- <item name="notification_gpodnet_sync_error" type="id"/>
- <item name="notification_gpodnet_sync_autherror" type="id"/>
- <item name="pending_intent_sync_error" type="id"/>
-</resources>