diff --git a/.project b/.project
new file mode 100644
index 0000000..3964dd3
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ android
+ Project android created by Buildship.
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectnature
+
+
diff --git a/app/build.gradle b/app/build.gradle
index de7d26a..0c2c47a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,8 +11,8 @@ android {
applicationId "com.github.gotify"
minSdkVersion 19
targetSdkVersion 29
- versionCode 15
- versionName "2.0.12"
+ versionCode 17
+ versionName "2.0.14"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3dfbef8..9cc4491 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,6 +15,7 @@
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
+ android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/AppTheme">
+
+
+
+
+
+
+
@@ -61,4 +72,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/java/com/github/gotify/MissedMessageUtil.java b/app/src/main/java/com/github/gotify/MissedMessageUtil.java
index 661c63d..d197830 100644
--- a/app/src/main/java/com/github/gotify/MissedMessageUtil.java
+++ b/app/src/main/java/com/github/gotify/MissedMessageUtil.java
@@ -14,7 +14,7 @@ import java.util.List;
import static com.github.gotify.api.Callback.call;
public class MissedMessageUtil {
- static final int NO_MESSAGES = 0;
+ static final long NO_MESSAGES = 0;
private final MessageApi api;
@@ -22,8 +22,8 @@ public class MissedMessageUtil {
this.api = api;
}
- public void lastReceivedMessage(Callback.SuccessCallback successCallback) {
- api.getMessages(1, 0)
+ public void lastReceivedMessage(Callback.SuccessCallback successCallback) {
+ api.getMessages(1, 0L)
.enqueue(
call(
(messages) -> {
@@ -37,11 +37,11 @@ public class MissedMessageUtil {
(e) -> {}));
}
- public List missingMessages(int till) {
+ public List missingMessages(long till) {
List result = new ArrayList<>();
try {
- Integer since = null;
+ Long since = null;
while (true) {
PagedMessages pagedMessages = Api.execute(api.getMessages(10, since));
List messages = pagedMessages.getMessages();
@@ -61,7 +61,7 @@ public class MissedMessageUtil {
return result;
}
- private List filter(List messages, int till) {
+ private List filter(List messages, long till) {
List result = new ArrayList<>();
for (Message message : messages) {
diff --git a/app/src/main/java/com/github/gotify/Utils.java b/app/src/main/java/com/github/gotify/Utils.java
index 739c5a1..2a3dd48 100644
--- a/app/src/main/java/com/github/gotify/Utils.java
+++ b/app/src/main/java/com/github/gotify/Utils.java
@@ -33,6 +33,10 @@ public class Utils {
Snackbar.make(rootView, message, Snackbar.LENGTH_SHORT).show();
}
+ public static int longToInt(long value) {
+ return (int) (value % Integer.MAX_VALUE);
+ }
+
public static String dateToRelative(OffsetDateTime data) {
long time = data.toInstant().toEpochMilli();
long now = System.currentTimeMillis();
@@ -96,4 +100,11 @@ public class Utils {
if (str == null) return null;
return new Buffer().writeUtf8(str).inputStream();
}
+
+ public static T first(T[] data) {
+ if (data.length != 1) {
+ throw new IllegalArgumentException("must be one element");
+ }
+ return data[0];
+ }
}
diff --git a/app/src/main/java/com/github/gotify/messages/ListMessageAdapter.java b/app/src/main/java/com/github/gotify/messages/ListMessageAdapter.java
index 3c6da03..02aad06 100644
--- a/app/src/main/java/com/github/gotify/messages/ListMessageAdapter.java
+++ b/app/src/main/java/com/github/gotify/messages/ListMessageAdapter.java
@@ -1,5 +1,7 @@
package com.github.gotify.messages;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Context;
import android.text.util.Linkify;
import android.view.LayoutInflater;
@@ -8,6 +10,7 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
@@ -133,6 +136,7 @@ public class ListMessageAdapter extends RecyclerView.Adapter {
+ ClipboardManager clipboard =
+ (ClipboardManager)
+ view.getContext()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip =
+ ClipData.newPlainText(
+ "GotifyMessageContent", message.getText().toString());
+
+ if (clipboard != null) {
+ clipboard.setPrimaryClip(clip);
+ Toast toast =
+ Toast.makeText(
+ view.getContext(),
+ view.getContext()
+ .getString(
+ R.string.message_copied_to_clipboard),
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+
+ return true;
+ });
+ }
}
public interface Delete {
diff --git a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java
index 3522dd5..0b680a1 100644
--- a/app/src/main/java/com/github/gotify/messages/MessagesActivity.java
+++ b/app/src/main/java/com/github/gotify/messages/MessagesActivity.java
@@ -43,7 +43,6 @@ import com.github.gotify.Settings;
import com.github.gotify.Utils;
import com.github.gotify.api.Api;
import com.github.gotify.api.ApiException;
-import com.github.gotify.api.CertUtils;
import com.github.gotify.api.ClientFactory;
import com.github.gotify.client.ApiClient;
import com.github.gotify.client.api.ClientApi;
@@ -60,23 +59,20 @@ import com.github.gotify.messages.provider.MessageDeletion;
import com.github.gotify.messages.provider.MessageFacade;
import com.github.gotify.messages.provider.MessageState;
import com.github.gotify.messages.provider.MessageWithImage;
-import com.github.gotify.picasso.PicassoDataRequestHandler;
+import com.github.gotify.picasso.PicassoHandler;
import com.github.gotify.service.WebSocketService;
import com.github.gotify.settings.SettingsActivity;
+import com.github.gotify.sharing.ShareActivity;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.snackbar.Snackbar;
-import com.squareup.picasso.OkHttp3Downloader;
-import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import okhttp3.Cache;
-import okhttp3.OkHttpClient;
+import static com.github.gotify.Utils.first;
import static java.util.Collections.emptyList;
public class MessagesActivity extends AppCompatActivity
@@ -118,14 +114,12 @@ public class MessagesActivity extends AppCompatActivity
private Settings settings;
protected ApplicationHolder appsHolder;
- private int appId = MessageState.ALL_MESSAGES;
+ private long appId = MessageState.ALL_MESSAGES;
private boolean isLoadMore = false;
- private Integer selectAppIdOnDrawerClose = null;
+ private Long selectAppIdOnDrawerClose = null;
- int PICASSO_CACHE_SIZE = 50 * 1024 * 1024; // 50 MB
- private Cache picassoCache;
- private Picasso picasso;
+ private PicassoHandler picassoHandler;
// we need to keep the target references otherwise they get gc'ed before they can be called.
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@@ -139,8 +133,7 @@ public class MessagesActivity extends AppCompatActivity
Log.i("Entering " + getClass().getSimpleName());
settings = new Settings(this);
- picassoCache = new Cache(new File(getCacheDir(), "picasso-cache"), PICASSO_CACHE_SIZE);
- picasso = makePicasso();
+ picassoHandler = new PicassoHandler(this, settings);
client =
ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token());
@@ -157,7 +150,7 @@ public class MessagesActivity extends AppCompatActivity
messagesView.getContext(), layoutManager.getOrientation());
ListMessageAdapter adapter =
new ListMessageAdapter(
- this, settings, picasso, emptyList(), this::scheduleDeletion);
+ this, settings, picassoHandler.get(), emptyList(), this::scheduleDeletion);
messagesView.addItemDecoration(dividerItemDecoration);
messagesView.setHasFixedSize(true);
@@ -200,7 +193,7 @@ public class MessagesActivity extends AppCompatActivity
public void onRefreshAll(View view) {
try {
- picassoCache.evictAll();
+ picassoHandler.evict();
} catch (IOException e) {
Log.e("Problem evicting Picasso cache", e);
}
@@ -229,12 +222,15 @@ public class MessagesActivity extends AppCompatActivity
menu.removeGroup(R.id.apps);
targetReferences.clear();
updateMessagesAndStopLoading(messages.get(appId));
- for (Application app : applications) {
- MenuItem item = menu.add(R.id.apps, app.getId(), APPLICATION_ORDER, app.getName());
+ for (int i = 0; i < applications.size(); i++) {
+ Application app = applications.get(i);
+ MenuItem item = menu.add(R.id.apps, i, APPLICATION_ORDER, app.getName());
item.setCheckable(true);
Target t = Utils.toDrawable(getResources(), item::setIcon);
targetReferences.add(t);
- picasso.load(Utils.resolveAbsoluteUrl(settings.url() + "/", app.getImage()))
+ picassoHandler
+ .get()
+ .load(Utils.resolveAbsoluteUrl(settings.url() + "/", app.getImage()))
.error(R.drawable.ic_alarm)
.placeholder(R.drawable.ic_placeholder)
.resize(100, 100)
@@ -242,20 +238,6 @@ public class MessagesActivity extends AppCompatActivity
}
}
- private Picasso makePicasso() {
- OkHttpClient.Builder builder = new OkHttpClient.Builder();
- builder.cache(picassoCache);
-
- CertUtils.applySslSettings(builder, settings.sslSettings());
-
- OkHttp3Downloader downloader = new OkHttp3Downloader(builder.build());
-
- return new Picasso.Builder(this)
- .addRequestHandler(new PicassoDataRequestHandler())
- .downloader(downloader)
- .build();
- }
-
private void initDrawer() {
setSupportActionBar(toolbar);
navigationView.setItemIconTintList(null);
@@ -303,7 +285,8 @@ public class MessagesActivity extends AppCompatActivity
int id = item.getItemId();
if (item.getGroupId() == R.id.apps) {
- selectAppIdOnDrawerClose = id;
+ Application app = appsHolder.get().get(id);
+ selectAppIdOnDrawerClose = app != null ? app.getId() : MessageState.ALL_MESSAGES;
startLoading();
toolbar.setSubtitle(item.getTitle());
} else if (id == R.id.nav_all_messages) {
@@ -321,6 +304,9 @@ public class MessagesActivity extends AppCompatActivity
startActivity(new Intent(this, LogsActivity.class));
} else if (id == R.id.settings) {
startActivity(new Intent(this, SettingsActivity.class));
+ } else if (id == R.id.push_message) {
+ Intent intent = new Intent(MessagesActivity.this, ShareActivity.class);
+ startActivity(intent);
}
drawer.closeDrawer(GravityCompat.START);
@@ -330,7 +316,6 @@ public class MessagesActivity extends AppCompatActivity
public void doLogout(DialogInterface dialog, int which) {
setContentView(R.layout.splash);
new DeleteClientAndNavigateToLogin().execute();
- finish();
}
private void startLoading() {
@@ -355,10 +340,17 @@ public class MessagesActivity extends AppCompatActivity
filter.addAction(WebSocketService.NEW_MESSAGE_BROADCAST);
registerReceiver(receiver, filter);
new UpdateMissedMessages().execute(messages.getLastReceivedMessage());
- navigationView
- .getMenu()
- .findItem(appId == MessageState.ALL_MESSAGES ? R.id.nav_all_messages : appId)
- .setChecked(true);
+
+ int selectedIndex = R.id.nav_all_messages;
+ if (appId != MessageState.ALL_MESSAGES) {
+ for (int i = 0; i < appsHolder.get().size(); i++) {
+ if (appsHolder.get().get(i).getId() == appId) {
+ selectedIndex = i;
+ }
+ }
+ }
+
+ navigationView.getMenu().findItem(selectedIndex).setChecked(true);
super.onResume();
}
@@ -371,7 +363,7 @@ public class MessagesActivity extends AppCompatActivity
@Override
protected void onDestroy() {
super.onDestroy();
- picasso.shutdown();
+ picassoHandler.get().shutdown();
}
private void scheduleDeletion(int position, Message message, boolean listAnimation) {
@@ -542,10 +534,10 @@ public class MessagesActivity extends AppCompatActivity
}
}
- private class UpdateMissedMessages extends AsyncTask {
+ private class UpdateMissedMessages extends AsyncTask {
@Override
- protected Boolean doInBackground(Integer... ids) {
- Integer id = first(ids);
+ protected Boolean doInBackground(Long... ids) {
+ Long id = first(ids);
if (id == -1) {
return false;
}
@@ -579,10 +571,10 @@ public class MessagesActivity extends AppCompatActivity
return super.onContextItemSelected(item);
}
- private class LoadMore extends AsyncTask> {
+ private class LoadMore extends AsyncTask> {
@Override
- protected List doInBackground(Integer... appId) {
+ protected List doInBackground(Long... appId) {
return messages.loadMore(first(appId));
}
@@ -592,7 +584,7 @@ public class MessagesActivity extends AppCompatActivity
}
}
- private class SelectApplicationAndUpdateMessages extends AsyncTask {
+ private class SelectApplicationAndUpdateMessages extends AsyncTask {
private SelectApplicationAndUpdateMessages(boolean withLoadingSpinner) {
if (withLoadingSpinner) {
@@ -601,14 +593,14 @@ public class MessagesActivity extends AppCompatActivity
}
@Override
- protected Integer doInBackground(Integer... appIds) {
- Integer appId = first(appIds);
+ protected Long doInBackground(Long... appIds) {
+ Long appId = first(appIds);
messages.loadMoreIfNotPresent(appId);
return appId;
}
@Override
- protected void onPostExecute(Integer appId) {
+ protected void onPostExecute(Long appId) {
updateMessagesAndStopLoading(messages.get(appId));
}
}
@@ -641,14 +633,14 @@ public class MessagesActivity extends AppCompatActivity
}
}
- private class DeleteMessages extends AsyncTask {
+ private class DeleteMessages extends AsyncTask {
DeleteMessages() {
startLoading();
}
@Override
- protected Boolean doInBackground(Integer... appId) {
+ protected Boolean doInBackground(Long... appId) {
return messages.deleteAll(first(appId));
}
@@ -683,7 +675,7 @@ public class MessagesActivity extends AppCompatActivity
if (currentClient != null) {
Log.i("Delete client with id " + currentClient.getId());
- api.deleteClient(currentClient.getId());
+ Api.execute(api.deleteClient(currentClient.getId()));
} else {
Log.e("Could not delete client, client does not exist.");
}
@@ -717,12 +709,4 @@ public class MessagesActivity extends AppCompatActivity
adapter.setItems(messageWithImages);
adapter.notifyDataSetChanged();
}
-
- private T first(T[] data) {
- if (data.length != 1) {
- throw new IllegalArgumentException("must be one element");
- }
-
- return data[0];
- }
}
diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java b/app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java
index cacafb8..1252576 100644
--- a/app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java
+++ b/app/src/main/java/com/github/gotify/messages/provider/MessageFacade.java
@@ -18,7 +18,7 @@ public class MessageFacade {
this.state = new MessageStateHolder();
}
- public synchronized List get(Integer appId) {
+ public synchronized List get(long appId) {
return combiner.combine(state.state(appId).messages, applicationHolder.get());
}
@@ -28,7 +28,7 @@ public class MessageFacade {
}
}
- public synchronized List loadMore(Integer appId) {
+ public synchronized List loadMore(long appId) {
MessageState state = this.state.state(appId);
if (state.hasNext || !state.loaded) {
PagedMessages pagedMessages = requester.loadMore(state);
@@ -37,7 +37,7 @@ public class MessageFacade {
return get(appId);
}
- public synchronized void loadMoreIfNotPresent(Integer appId) {
+ public synchronized void loadMoreIfNotPresent(long appId) {
MessageState state = this.state.state(appId);
if (!state.loaded) {
loadMore(appId);
@@ -48,7 +48,7 @@ public class MessageFacade {
this.state.clear();
}
- public int getLastReceivedMessage() {
+ public long getLastReceivedMessage() {
return state.getLastReceivedMessage();
}
@@ -70,13 +70,13 @@ public class MessageFacade {
return this.state.undoPendingDeletion();
}
- public synchronized boolean deleteAll(Integer appId) {
+ public synchronized boolean deleteAll(long appId) {
boolean success = this.requester.deleteAll(appId);
this.state.deleteAll(appId);
return success;
}
- public synchronized boolean canLoadMore(Integer appId) {
+ public synchronized boolean canLoadMore(long appId) {
return state.state(appId).hasNext;
}
}
diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java
index 4a145f6..a258b02 100644
--- a/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java
+++ b/app/src/main/java/com/github/gotify/messages/provider/MessageImageCombiner.java
@@ -3,14 +3,14 @@ package com.github.gotify.messages.provider;
import com.github.gotify.client.model.Application;
import com.github.gotify.client.model.Message;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
-class MessageImageCombiner {
+public class MessageImageCombiner {
List combine(List messages, List applications) {
- Map appIdToImage = appIdToImage(applications);
+ Map appIdToImage = appIdToImage(applications);
List result = new ArrayList<>();
@@ -26,8 +26,8 @@ class MessageImageCombiner {
return result;
}
- private Map appIdToImage(List applications) {
- Map map = new HashMap<>();
+ public static Map appIdToImage(List applications) {
+ Map map = new ConcurrentHashMap<>();
for (Application app : applications) {
map.put(app.getId(), app.getImage());
}
diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java b/app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java
index 8f07fdc..707ffc8 100644
--- a/app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java
+++ b/app/src/main/java/com/github/gotify/messages/provider/MessageRequester.java
@@ -35,7 +35,7 @@ class MessageRequester {
messageApi.deleteMessage(message.getId()).enqueue(Callback.call());
}
- boolean deleteAll(Integer appId) {
+ boolean deleteAll(Long appId) {
try {
Log.i("Deleting all messages for " + appId);
if (MessageState.ALL_MESSAGES == appId) {
diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageState.java b/app/src/main/java/com/github/gotify/messages/provider/MessageState.java
index 8c8db1e..d90da5f 100644
--- a/app/src/main/java/com/github/gotify/messages/provider/MessageState.java
+++ b/app/src/main/java/com/github/gotify/messages/provider/MessageState.java
@@ -5,11 +5,11 @@ import java.util.ArrayList;
import java.util.List;
public class MessageState {
- public static final int ALL_MESSAGES = -1;
+ public static final long ALL_MESSAGES = -1;
- int appId;
+ long appId;
boolean loaded;
boolean hasNext;
- int nextSince = 0;
+ long nextSince = 0;
List messages = new ArrayList<>();
}
diff --git a/app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java b/app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java
index 25e37b4..4065d46 100644
--- a/app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java
+++ b/app/src/main/java/com/github/gotify/messages/provider/MessageStateHolder.java
@@ -6,8 +6,8 @@ import java.util.HashMap;
import java.util.Map;
class MessageStateHolder {
- private int lastReceivedMessage = -1;
- private Map states = new HashMap<>();
+ private long lastReceivedMessage = -1;
+ private Map states = new HashMap<>();
private MessageDeletion pendingDeletion = null;
@@ -15,7 +15,7 @@ class MessageStateHolder {
states = new HashMap<>();
}
- synchronized void newMessages(Integer appId, PagedMessages pagedMessages) {
+ synchronized void newMessages(Long appId, PagedMessages pagedMessages) {
MessageState state = state(appId);
if (!state.loaded && pagedMessages.getMessages().size() > 0) {
@@ -49,7 +49,7 @@ class MessageStateHolder {
if (deletion != null) deleteMessage(deletion.getMessage());
}
- synchronized MessageState state(Integer appId) {
+ synchronized MessageState state(Long appId) {
MessageState state = states.get(appId);
if (state == null) {
return emptyState(appId);
@@ -57,14 +57,14 @@ class MessageStateHolder {
return state;
}
- synchronized void deleteAll(Integer appId) {
+ synchronized void deleteAll(Long appId) {
clear();
MessageState state = state(appId);
state.loaded = true;
states.put(appId, state);
}
- private MessageState emptyState(Integer appId) {
+ private MessageState emptyState(Long appId) {
MessageState emptyState = new MessageState();
emptyState.loaded = false;
emptyState.hasNext = false;
@@ -73,7 +73,7 @@ class MessageStateHolder {
return emptyState;
}
- synchronized int getLastReceivedMessage() {
+ synchronized long getLastReceivedMessage() {
return lastReceivedMessage;
}
diff --git a/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java b/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java
new file mode 100644
index 0000000..546b06b
--- /dev/null
+++ b/app/src/main/java/com/github/gotify/picasso/PicassoHandler.java
@@ -0,0 +1,94 @@
+package com.github.gotify.picasso;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import com.github.gotify.R;
+import com.github.gotify.Settings;
+import com.github.gotify.Utils;
+import com.github.gotify.api.Callback;
+import com.github.gotify.api.CertUtils;
+import com.github.gotify.api.ClientFactory;
+import com.github.gotify.client.api.ApplicationApi;
+import com.github.gotify.log.Log;
+import com.github.gotify.messages.provider.MessageImageCombiner;
+import com.squareup.picasso.OkHttp3Downloader;
+import com.squareup.picasso.Picasso;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import okhttp3.Cache;
+import okhttp3.OkHttpClient;
+
+public class PicassoHandler {
+
+ private static final int PICASSO_CACHE_SIZE = 50 * 1024 * 1024; // 50 MB
+ private static final String PICASSO_CACHE_SUBFOLDER = "picasso-cache";
+
+ private Context context;
+ private Settings settings;
+
+ private Cache picassoCache;
+
+ private Picasso picasso;
+ private Map appIdToAppImage = new ConcurrentHashMap<>();
+
+ public PicassoHandler(Context context, Settings settings) {
+ this.context = context;
+ this.settings = settings;
+
+ picassoCache =
+ new Cache(
+ new File(context.getCacheDir(), PICASSO_CACHE_SUBFOLDER),
+ PICASSO_CACHE_SIZE);
+ picasso = makePicasso();
+ }
+
+ private Picasso makePicasso() {
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.cache(picassoCache);
+ CertUtils.applySslSettings(builder, settings.sslSettings());
+ OkHttp3Downloader downloader = new OkHttp3Downloader(builder.build());
+ return new Picasso.Builder(context).downloader(downloader).build();
+ }
+
+ public Bitmap getIcon(Long appId) {
+ if (appId == -1) {
+ return BitmapFactory.decodeResource(context.getResources(), R.drawable.gotify);
+ }
+
+ try {
+ return picasso.load(
+ Utils.resolveAbsoluteUrl(
+ settings.url() + "/", appIdToAppImage.get(appId)))
+ .get();
+ } catch (IOException e) {
+ Log.e("Could not load image for notification", e);
+ }
+ return BitmapFactory.decodeResource(context.getResources(), R.drawable.gotify);
+ }
+
+ public void updateAppIds() {
+ ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token())
+ .createService(ApplicationApi.class)
+ .getApps()
+ .enqueue(
+ Callback.call(
+ (apps) -> {
+ appIdToAppImage.clear();
+ appIdToAppImage.putAll(MessageImageCombiner.appIdToImage(apps));
+ },
+ (t) -> {
+ appIdToAppImage.clear();
+ }));
+ }
+
+ public Picasso get() {
+ return picasso;
+ }
+
+ public void evict() throws IOException {
+ picassoCache.evictAll();
+ }
+}
diff --git a/app/src/main/java/com/github/gotify/service/MessagingDatabase.kt b/app/src/main/java/com/github/gotify/service/MessagingDatabase.kt
index 27d4070..71571f9 100644
--- a/app/src/main/java/com/github/gotify/service/MessagingDatabase.kt
+++ b/app/src/main/java/com/github/gotify/service/MessagingDatabase.kt
@@ -29,7 +29,7 @@ class MessagingDatabase(context: Context) : SQLiteOpenHelper(context, DB_NAME, n
throw IllegalStateException("Upgrades not supported")
}
- fun registerApp(packageName: String, appId :Int, gotify_token: String, connector_token: String){
+ fun registerApp(packageName: String, appId :Long, gotify_token: String, connector_token: String){
val db = writableDatabase
val values = ContentValues().apply {
put(FIELD_PACKAGE_NAME, packageName)
@@ -88,7 +88,7 @@ class MessagingDatabase(context: Context) : SQLiteOpenHelper(context, DB_NAME, n
}
}
- fun getAppFromId(appId: Int): String{
+ fun getAppFromId(appId: Long): String{
val db = readableDatabase
val projection = arrayOf(FIELD_PACKAGE_NAME)
val selection = "$FIELD_APP_ID = ?"
@@ -106,7 +106,7 @@ class MessagingDatabase(context: Context) : SQLiteOpenHelper(context, DB_NAME, n
}
}
- fun getAppId(packageName: String): Int{
+ fun getAppId(packageName: String): Long{
val db = readableDatabase
val projection = arrayOf(FIELD_APP_ID)
val selection = "$FIELD_PACKAGE_NAME = ?"
@@ -120,7 +120,7 @@ class MessagingDatabase(context: Context) : SQLiteOpenHelper(context, DB_NAME, n
null,
null
).use { cursor ->
- if (cursor.moveToFirst()) cursor.getInt(cursor.getColumnIndex(FIELD_APP_ID)) else -1
+ if (cursor.moveToFirst()) cursor.getLong(cursor.getColumnIndex(FIELD_APP_ID)) else -1
}
}
diff --git a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java
index ebda4da..2810128 100644
--- a/app/src/main/java/com/github/gotify/service/WebSocketConnection.java
+++ b/app/src/main/java/com/github/gotify/service/WebSocketConnection.java
@@ -1,7 +1,9 @@
package com.github.gotify.service;
+import android.app.AlarmManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.os.Build;
import android.os.Handler;
import com.github.gotify.SSLSettings;
import com.github.gotify.Utils;
@@ -9,7 +11,9 @@ import com.github.gotify.api.Callback;
import com.github.gotify.api.CertUtils;
import com.github.gotify.client.model.Message;
import com.github.gotify.log.Log;
+import java.util.Calendar;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@@ -17,8 +21,10 @@ import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
-public class WebSocketConnection {
+class WebSocketConnection {
+ private static final AtomicLong ID = new AtomicLong(0);
private final ConnectivityManager connectivityManager;
+ private final AlarmManager alarmManager;
private OkHttpClient client;
private final Handler reconnectHandler = new Handler();
@@ -34,15 +40,17 @@ public class WebSocketConnection {
private BadRequestRunnable onBadRequest;
private OnNetworkFailureRunnable onNetworkFailure;
private Runnable onReconnected;
- private boolean isClosed;
+ private State state;
private Runnable onDisconnect;
WebSocketConnection(
String baseUrl,
SSLSettings settings,
String token,
- ConnectivityManager connectivityManager) {
+ ConnectivityManager connectivityManager,
+ AlarmManager alarmManager) {
this.connectivityManager = connectivityManager;
+ this.alarmManager = alarmManager;
OkHttpClient.Builder builder =
new OkHttpClient.Builder()
.readTimeout(0, TimeUnit.MILLISECONDS)
@@ -102,67 +110,97 @@ public class WebSocketConnection {
}
public synchronized WebSocketConnection start() {
+ if (state == State.Connecting || state == State.Connected) {
+ return this;
+ }
close();
- isClosed = false;
- Log.i("WebSocket: starting...");
+ state = State.Connecting;
+ long nextId = ID.incrementAndGet();
+ Log.i("WebSocket(" + nextId + "): starting...");
- webSocket = client.newWebSocket(request(), new Listener());
+ webSocket = client.newWebSocket(request(), new Listener(nextId));
return this;
}
public synchronized void close() {
if (webSocket != null) {
- Log.i("WebSocket: closing existing connection.");
- isClosed = true;
+ Log.i("WebSocket(" + ID.get() + "): closing existing connection.");
+ state = State.Disconnected;
webSocket.close(1000, "");
webSocket = null;
}
}
- public synchronized void scheduleReconnect(long millis) {
- reconnectHandler.removeCallbacks(reconnectCallback);
+ public synchronized void scheduleReconnect(long seconds) {
+ if (state == State.Connecting || state == State.Connected) {
+ return;
+ }
+ state = State.Scheduled;
- Log.i(
- "WebSocket: scheduling a restart in "
- + TimeUnit.SECONDS.convert(millis, TimeUnit.MILLISECONDS)
- + " second(s)");
- reconnectHandler.postDelayed(reconnectCallback, millis);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ Log.i(
+ "WebSocket: scheduling a restart in "
+ + seconds
+ + " second(s) (via alarm manager)");
+ final Calendar future = Calendar.getInstance();
+ future.add(Calendar.SECOND, (int) seconds);
+ alarmManager.setExact(
+ AlarmManager.RTC_WAKEUP,
+ future.getTimeInMillis(),
+ "reconnect-tag",
+ this::start,
+ null);
+ } else {
+ Log.i("WebSocket: scheduling a restart in " + seconds + " second(s)");
+ reconnectHandler.removeCallbacks(reconnectCallback);
+ reconnectHandler.postDelayed(reconnectCallback, TimeUnit.SECONDS.toMillis(seconds));
+ }
}
private class Listener extends WebSocketListener {
+ private final long id;
+
+ public Listener(long id) {
+ this.id = id;
+ }
@Override
public void onOpen(WebSocket webSocket, Response response) {
- Log.i("WebSocket: opened");
- synchronized (this) {
- onOpen.run();
+ syncExec(
+ () -> {
+ state = State.Connected;
+ Log.i("WebSocket(" + id + "): opened");
+ onOpen.run();
- if (errorCount > 0) {
- onReconnected.run();
- errorCount = 0;
- }
- }
+ if (errorCount > 0) {
+ onReconnected.run();
+ errorCount = 0;
+ }
+ });
super.onOpen(webSocket, response);
}
@Override
public void onMessage(WebSocket webSocket, String text) {
- Log.i("WebSocket: received message " + text);
- synchronized (this) {
- Message message = Utils.JSON.fromJson(text, Message.class);
- onMessage.onSuccess(message);
- }
+ syncExec(
+ () -> {
+ Log.i("WebSocket(" + id + "): received message " + text);
+ Message message = Utils.JSON.fromJson(text, Message.class);
+ onMessage.onSuccess(message);
+ });
super.onMessage(webSocket, text);
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
- synchronized (this) {
- if (!isClosed) {
- Log.w("WebSocket: closed");
- onClose.run();
- }
- }
+ syncExec(
+ () -> {
+ if (state == State.Connected) {
+ Log.w("WebSocket(" + id + "): closed");
+ onClose.run();
+ }
+ state = State.Disconnected;
+ });
super.onClosed(webSocket, code, reason);
}
@@ -171,31 +209,41 @@ public class WebSocketConnection {
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
String code = response != null ? "StatusCode: " + response.code() : "";
String message = response != null ? response.message() : "";
- Log.e("WebSocket: failure " + code + " Message: " + message, t);
- synchronized (this) {
- if (response != null && response.code() >= 400 && response.code() <= 499) {
- onBadRequest.execute(message);
- close();
- return;
- }
+ Log.e("WebSocket(" + id + "): failure " + code + " Message: " + message, t);
+ syncExec(
+ () -> {
+ state = State.Disconnected;
+ if (response != null && response.code() >= 400 && response.code() <= 499) {
+ onBadRequest.execute(message);
+ close();
+ return;
+ }
- errorCount++;
+ errorCount++;
- NetworkInfo network = connectivityManager.getActiveNetworkInfo();
- if (network == null || !network.isConnected()) {
- Log.i("WebSocket: Network not connected");
- onDisconnect.run();
- return;
- }
+ NetworkInfo network = connectivityManager.getActiveNetworkInfo();
+ if (network == null || !network.isConnected()) {
+ Log.i("WebSocket(" + id + "): Network not connected");
+ onDisconnect.run();
+ return;
+ }
- int minutes = Math.min(errorCount * 2 - 1, 20);
+ int minutes = Math.min(errorCount * 2 - 1, 20);
- onNetworkFailure.execute(minutes);
- scheduleReconnect(TimeUnit.MINUTES.toMillis(minutes));
- }
+ onNetworkFailure.execute(minutes);
+ scheduleReconnect(TimeUnit.MINUTES.toSeconds(minutes));
+ });
super.onFailure(webSocket, t, response);
}
+
+ private void syncExec(Runnable runnable) {
+ synchronized (this) {
+ if (ID.get() == id) {
+ runnable.run();
+ }
+ }
+ }
}
interface BadRequestRunnable {
@@ -205,4 +253,11 @@ public class WebSocketConnection {
interface OnNetworkFailureRunnable {
void execute(long millis);
}
+
+ enum State {
+ Scheduled,
+ Connecting,
+ Connected,
+ Disconnected
+ }
}
diff --git a/app/src/main/java/com/github/gotify/service/WebSocketService.java b/app/src/main/java/com/github/gotify/service/WebSocketService.java
index b395793..9da5ef8 100644
--- a/app/src/main/java/com/github/gotify/service/WebSocketService.java
+++ b/app/src/main/java/com/github/gotify/service/WebSocketService.java
@@ -1,5 +1,6 @@
package com.github.gotify.service;
+import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -22,40 +23,44 @@ import com.github.gotify.R;
import com.github.gotify.Settings;
import com.github.gotify.Utils;
import com.github.gotify.api.ClientFactory;
+import com.github.gotify.client.ApiClient;
import com.github.gotify.client.api.MessageApi;
import com.github.gotify.client.model.Message;
import com.github.gotify.log.Log;
import com.github.gotify.log.UncaughtExceptionHandler;
import com.github.gotify.messages.Extras;
import com.github.gotify.messages.MessagesActivity;
+import com.github.gotify.picasso.PicassoHandler;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static com.github.gotify.api.Callback.call;
public class WebSocketService extends Service {
public static final String NEW_MESSAGE_BROADCAST =
WebSocketService.class.getName() + ".NEW_MESSAGE";
- private static final int NOT_LOADED = -2;
+ private static final long NOT_LOADED = -2;
private Settings settings;
private WebSocketConnection connection;
- private AtomicInteger lastReceivedMessage = new AtomicInteger(NOT_LOADED);
+ private AtomicLong lastReceivedMessage = new AtomicLong(NOT_LOADED);
private MissedMessageUtil missingMessageUtil;
+ private PicassoHandler picassoHandler;
+
@Override
public void onCreate() {
super.onCreate();
settings = new Settings(this);
- missingMessageUtil =
- new MissedMessageUtil(
- ClientFactory.clientToken(
- settings.url(), settings.sslSettings(), settings.token())
- .createService(MessageApi.class));
+ ApiClient client =
+ ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token());
+ missingMessageUtil = new MissedMessageUtil(client.createService(MessageApi.class));
Log.i("Create " + getClass().getSimpleName());
+ picassoHandler = new PicassoHandler(this, settings);
}
@Override
@@ -92,12 +97,17 @@ public class WebSocketService extends Service {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
connection =
new WebSocketConnection(
- settings.url(), settings.sslSettings(), settings.token(), cm)
+ settings.url(),
+ settings.sslSettings(),
+ settings.token(),
+ cm,
+ alarmManager)
.onOpen(this::onOpen)
- .onClose(() -> foreground(getString(R.string.websocket_closed)))
+ .onClose(this::onClose)
.onBadRequest(this::onBadRequest)
.onNetworkFailure(
(min) -> foreground(getString(R.string.websocket_failed, min)))
@@ -110,6 +120,26 @@ public class WebSocketService extends Service {
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
ReconnectListener receiver = new ReconnectListener(this::doReconnect);
registerReceiver(receiver, intentFilter);
+
+ picassoHandler.updateAppIds();
+ }
+
+ private void onClose() {
+ foreground(getString(R.string.websocket_closed_try_reconnect));
+ ClientFactory.userApiWithToken(settings)
+ .currentUser()
+ .enqueue(
+ call(
+ (ignored) -> this.doReconnect(),
+ (exception) -> {
+ if (exception.code() == 401) {
+ foreground(getString(R.string.websocket_closed_logout));
+ } else {
+ Log.i(
+ "WebSocket closed but the user still authenticated, trying to reconnect");
+ this.doReconnect();
+ }
+ }));
}
private void onDisconnect() {
@@ -121,7 +151,7 @@ public class WebSocketService extends Service {
return;
}
- connection.scheduleReconnect(TimeUnit.SECONDS.toMillis(5));
+ connection.scheduleReconnect(15);
}
private void onBadRequest(String message) {
@@ -133,7 +163,7 @@ public class WebSocketService extends Service {
}
private void notifyMissedNotifications() {
- int messageId = lastReceivedMessage.get();
+ long messageId = lastReceivedMessage.get();
if (messageId == NOT_LOADED) {
return;
}
@@ -171,6 +201,7 @@ public class WebSocketService extends Service {
if (lastReceivedMessage.get() < message.getId()) {
lastReceivedMessage.set(message.getId());
}
+
broadcast(message);
try (MessagingDatabase db = new MessagingDatabase(this)) {
String registeredAppName = db.getAppFromId(message.getAppid());
@@ -186,7 +217,8 @@ public class WebSocketService extends Service {
message.getTitle(),
message.getMessage(),
message.getPriority(),
- message.getExtras());
+ message.getExtras(),
+ message.getAppid());
}
private void broadcast(Message message) {
@@ -228,6 +260,16 @@ public class WebSocketService extends Service {
private void showNotification(
int id, String title, String message, long priority, Map extras) {
+ showNotification(id, title, message, priority, extras, -1L);
+ }
+
+ private void showNotification(
+ long id,
+ String title,
+ String message,
+ long priority,
+ Map extras,
+ Long appid) {
Intent intent;
@@ -267,6 +309,7 @@ public class WebSocketService extends Service {
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_gotify)
+ .setLargeIcon(picassoHandler.getIcon(appid))
.setTicker(getString(R.string.app_name) + " - " + title)
.setGroup(NotificationSupport.Group.MESSAGES)
.setContentTitle(title)
@@ -279,7 +322,7 @@ public class WebSocketService extends Service {
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.notify(id, b.build());
+ notificationManager.notify(Utils.longToInt(id), b.build());
}
@RequiresApi(Build.VERSION_CODES.N)
diff --git a/app/src/main/java/com/github/gotify/sharing/ShareActivity.java b/app/src/main/java/com/github/gotify/sharing/ShareActivity.java
new file mode 100644
index 0000000..065a096
--- /dev/null
+++ b/app/src/main/java/com/github/gotify/sharing/ShareActivity.java
@@ -0,0 +1,153 @@
+package com.github.gotify.sharing;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.Toast;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import com.github.gotify.R;
+import com.github.gotify.Settings;
+import com.github.gotify.api.Api;
+import com.github.gotify.api.ApiException;
+import com.github.gotify.api.ClientFactory;
+import com.github.gotify.client.ApiClient;
+import com.github.gotify.client.api.MessageApi;
+import com.github.gotify.client.model.Application;
+import com.github.gotify.client.model.Message;
+import com.github.gotify.log.Log;
+import com.github.gotify.messages.provider.ApplicationHolder;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.github.gotify.Utils.first;
+
+public class ShareActivity extends AppCompatActivity {
+ private Settings settings;
+ private ApplicationHolder appsHolder;
+
+ @BindView(R.id.title)
+ EditText edtTxtTitle;
+
+ @BindView(R.id.content)
+ EditText edtTxtContent;
+
+ @BindView(R.id.edtTxtPriority)
+ EditText edtTxtPriority;
+
+ @BindView(R.id.appSpinner)
+ Spinner appSpinner;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_share);
+ ButterKnife.bind(this);
+
+ Log.i("Entering " + getClass().getSimpleName());
+ setSupportActionBar(findViewById(R.id.toolbar));
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowCustomEnabled(true);
+ }
+ settings = new Settings(this);
+
+ Intent intent = getIntent();
+ String type = intent.getType();
+ if (Intent.ACTION_SEND.equals(intent.getAction()) && "text/plain".equals(type)) {
+ String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
+ if (sharedText != null) {
+ edtTxtContent.setText(sharedText);
+ }
+ }
+
+ ApiClient client =
+ ClientFactory.clientToken(settings.url(), settings.sslSettings(), settings.token());
+ appsHolder = new ApplicationHolder(this, client);
+ appsHolder.onUpdate(() -> populateSpinner(appsHolder.get()));
+ appsHolder.request();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @OnClick(R.id.push_button)
+ public void pushMessage(View view) {
+ String titleText = edtTxtTitle.getText().toString();
+ String contentText = edtTxtContent.getText().toString();
+ String priority = edtTxtPriority.getText().toString();
+ int appIndex = appSpinner.getSelectedItemPosition();
+
+ if (contentText.isEmpty()) {
+ Toast.makeText(this, "Content should not be empty.", Toast.LENGTH_LONG).show();
+ return;
+ } else if (priority.isEmpty()) {
+ Toast.makeText(this, "Priority should be number.", Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ Message message = new Message();
+ if (!titleText.isEmpty()) {
+ message.setTitle(titleText);
+ }
+ message.setMessage(contentText);
+ message.setPriority(Long.parseLong(priority));
+ new PushMessage(appsHolder.get().get(appIndex).getToken()).execute(message);
+ }
+
+ private void populateSpinner(List apps) {
+ List appNameList = new ArrayList<>();
+ for (Application app : apps) {
+ appNameList.add(app.getName());
+ }
+
+ ArrayAdapter adapter =
+ new ArrayAdapter<>(
+ this, android.R.layout.simple_spinner_dropdown_item, appNameList);
+ appSpinner.setAdapter(adapter);
+ }
+
+ private class PushMessage extends AsyncTask {
+ private String token;
+
+ public PushMessage(String token) {
+ this.token = token;
+ }
+
+ @Override
+ protected String doInBackground(Message... messages) {
+ List apps = appsHolder.get();
+ ApiClient pushClient =
+ ClientFactory.clientToken(settings.url(), settings.sslSettings(), token);
+
+ try {
+ MessageApi messageApi = pushClient.createService(MessageApi.class);
+ Api.execute(messageApi.createMessage(first(messages)));
+ return "Pushed!";
+ } catch (ApiException apiException) {
+ Log.e("Failed sending message", apiException);
+ return "Oops! Something went wrong...";
+ }
+ }
+
+ @Override
+ protected void onPostExecute(String message) {
+ Toast.makeText(ShareActivity.this, message, Toast.LENGTH_LONG).show();
+ ShareActivity.this.finish();
+ }
+ }
+}
diff --git a/app/src/main/res/drawable/ic_send.xml b/app/src/main/res/drawable/ic_send.xml
new file mode 100644
index 0000000..ac34cb9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_send.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
index a087c86..af2a382 100644
--- a/app/src/main/res/drawable/ic_settings.xml
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -1,5 +1,7 @@
+ android:viewportWidth="20"
+ android:width="24dp"
+ xmlns:android="http://schemas.android.com/apk/res/android">
diff --git a/app/src/main/res/layout/activity_share.xml b/app/src/main/res/layout/activity_share.xml
new file mode 100644
index 0000000..1c20d6b
--- /dev/null
+++ b/app/src/main/res/layout/activity_share.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/messages_menu.xml b/app/src/main/res/menu/messages_menu.xml
index 28241bf..2ab5007 100644
--- a/app/src/main/res/menu/messages_menu.xml
+++ b/app/src/main/res/menu/messages_menu.xml
@@ -15,6 +15,12 @@
+
- Server returned 401 unauthorized while trying to get current user. This can be caused by deleting the client for this session.
Could not get current user. Server (%s) responded with code %d: body (first 200 chars): %s
Connection failed, trying again in %d minutes
- WebSocket closed; The client-token could be invalidated, please re-login
+ User action required: Please login, the authentication token isn\'t valid anymore.
+ Connection closed, trying to establish a new one.
Received %d messages while being disconnected
Delete all
Delete logs
@@ -36,7 +37,6 @@
https://push.example.com
Username
Password
- Show Advanced Options
Disable SSL Validation
Select CA Certificate
Select a Certificate File
@@ -68,4 +68,12 @@
Appearance
Theme
theme
+ Push message
+ App:
+ Priority:
+ Push Message
+ Title
+ Content
+ Priority
+ Content copied to clipboard
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..18c1056
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index a508aa4..cf99d82 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,10 +8,9 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.3'
+ classpath 'com.android.tools.build:gradle:4.0.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -70,4 +69,4 @@ dependencies {
swaggerCodegen 'io.swagger:swagger-codegen-cli:2.3.1'
}
-generateSwaggerCode.dependsOn downloadSpec
\ No newline at end of file
+generateSwaggerCode.dependsOn downloadSpec
diff --git a/client/build.gradle b/client/build.gradle
index 409ba3d..564e4d5 100644
--- a/client/build.gradle
+++ b/client/build.gradle
@@ -10,7 +10,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.3'
+ classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
diff --git a/client/docs/Application.md b/client/docs/Application.md
index dc6909f..00abef6 100644
--- a/client/docs/Application.md
+++ b/client/docs/Application.md
@@ -5,7 +5,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**description** | **String** | The description of the application. |
-**id** | **Integer** | The application id. |
+**id** | **Long** | The application id. |
**image** | **String** | The image of the application. |
**internal** | **Boolean** | Whether the application is an internal application. Internal applications should not be deleted. |
**name** | **String** | The application name. This is how the application should be displayed to the user. |
diff --git a/client/docs/ApplicationApi.md b/client/docs/ApplicationApi.md
index d094ccb..4ac61b0 100644
--- a/client/docs/ApplicationApi.md
+++ b/client/docs/ApplicationApi.md
@@ -110,7 +110,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
ApplicationApi apiInstance = new ApplicationApi();
-Integer id = 56; // Integer | the application id
+Long id = 789L; // Long | the application id
try {
Void result = apiInstance.deleteApp(id);
System.out.println(result);
@@ -124,7 +124,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the application id |
+ **id** | **Long**| the application id |
### Return type
@@ -235,7 +235,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
ApplicationApi apiInstance = new ApplicationApi();
Application body = new Application(); // Application | the application to update
-Integer id = 56; // Integer | the application id
+Long id = 789L; // Long | the application id
try {
Application result = apiInstance.updateApplication(body, id);
System.out.println(result);
@@ -250,7 +250,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**body** | [**Application**](Application.md)| the application to update |
- **id** | **Integer**| the application id |
+ **id** | **Long**| the application id |
### Return type
@@ -301,7 +301,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
ApplicationApi apiInstance = new ApplicationApi();
File file = new File("/path/to/file.txt"); // File | the application image
-Integer id = 56; // Integer | the application id
+Long id = 789L; // Long | the application id
try {
Application result = apiInstance.uploadAppImage(file, id);
System.out.println(result);
@@ -316,7 +316,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**file** | **File**| the application image |
- **id** | **Integer**| the application id |
+ **id** | **Long**| the application id |
### Return type
diff --git a/client/docs/Client.md b/client/docs/Client.md
index d562678..3de1e6c 100644
--- a/client/docs/Client.md
+++ b/client/docs/Client.md
@@ -4,7 +4,7 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
-**id** | **Integer** | The client id. |
+**id** | **Long** | The client id. |
**name** | **String** | The client name. This is how the client should be displayed to the user. |
**token** | **String** | The client token. Can be used as `clientToken`. See Authentication. |
diff --git a/client/docs/ClientApi.md b/client/docs/ClientApi.md
index 2d1f8c7..aee74ad 100644
--- a/client/docs/ClientApi.md
+++ b/client/docs/ClientApi.md
@@ -7,6 +7,7 @@ Method | HTTP request | Description
[**createClient**](ClientApi.md#createClient) | **POST** client | Create a client.
[**deleteClient**](ClientApi.md#deleteClient) | **DELETE** client/{id} | Delete a client.
[**getClients**](ClientApi.md#getClients) | **GET** client | Return all clients.
+[**updateClient**](ClientApi.md#updateClient) | **PUT** client/{id} | Update a client.
@@ -108,7 +109,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
ClientApi apiInstance = new ClientApi();
-Integer id = 56; // Integer | the client id
+Long id = 789L; // Long | the client id
try {
Void result = apiInstance.deleteClient(id);
System.out.println(result);
@@ -122,7 +123,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the client id |
+ **id** | **Long**| the client id |
### Return type
@@ -197,3 +198,69 @@ This endpoint does not need any parameter.
- **Content-Type**: application/json
- **Accept**: application/json
+
+# **updateClient**
+> Client updateClient(body, id)
+
+Update a client.
+
+### Example
+```java
+// Import classes:
+//import com.github.gotify.client.ApiClient;
+//import com.github.gotify.client.ApiException;
+//import com.github.gotify.client.Configuration;
+//import com.github.gotify.client.auth.*;
+//import com.github.gotify.client.api.ClientApi;
+
+ApiClient defaultClient = Configuration.getDefaultApiClient();
+
+// Configure HTTP basic authorization: basicAuth
+HttpBasicAuth basicAuth = (HttpBasicAuth) defaultClient.getAuthentication("basicAuth");
+basicAuth.setUsername("YOUR USERNAME");
+basicAuth.setPassword("YOUR PASSWORD");
+
+// Configure API key authorization: clientTokenHeader
+ApiKeyAuth clientTokenHeader = (ApiKeyAuth) defaultClient.getAuthentication("clientTokenHeader");
+clientTokenHeader.setApiKey("YOUR API KEY");
+// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
+//clientTokenHeader.setApiKeyPrefix("Token");
+
+// Configure API key authorization: clientTokenQuery
+ApiKeyAuth clientTokenQuery = (ApiKeyAuth) defaultClient.getAuthentication("clientTokenQuery");
+clientTokenQuery.setApiKey("YOUR API KEY");
+// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null)
+//clientTokenQuery.setApiKeyPrefix("Token");
+
+ClientApi apiInstance = new ClientApi();
+Client body = new Client(); // Client | the client to update
+Long id = 789L; // Long | the client id
+try {
+ Client result = apiInstance.updateClient(body, id);
+ System.out.println(result);
+} catch (ApiException e) {
+ System.err.println("Exception when calling ClientApi#updateClient");
+ e.printStackTrace();
+}
+```
+
+### Parameters
+
+Name | Type | Description | Notes
+------------- | ------------- | ------------- | -------------
+ **body** | [**Client**](Client.md)| the client to update |
+ **id** | **Long**| the client id |
+
+### Return type
+
+[**Client**](Client.md)
+
+### Authorization
+
+[basicAuth](../README.md#basicAuth), [clientTokenHeader](../README.md#clientTokenHeader), [clientTokenQuery](../README.md#clientTokenQuery)
+
+### HTTP request headers
+
+ - **Content-Type**: application/json
+ - **Accept**: application/json
+
diff --git a/client/docs/Health.md b/client/docs/Health.md
new file mode 100644
index 0000000..e6181a2
--- /dev/null
+++ b/client/docs/Health.md
@@ -0,0 +1,11 @@
+
+# Health
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**database** | **String** | The health of the database connection. |
+**health** | **String** | The health of the overall application. |
+
+
+
diff --git a/client/docs/HealthApi.md b/client/docs/HealthApi.md
new file mode 100644
index 0000000..0fbd9e5
--- /dev/null
+++ b/client/docs/HealthApi.md
@@ -0,0 +1,48 @@
+# HealthApi
+
+All URIs are relative to *http://localhost*
+
+Method | HTTP request | Description
+------------- | ------------- | -------------
+[**getHealth**](HealthApi.md#getHealth) | **GET** health | Get health information.
+
+
+
+# **getHealth**
+> Health getHealth()
+
+Get health information.
+
+### Example
+```java
+// Import classes:
+//import com.github.gotify.client.ApiException;
+//import com.github.gotify.client.api.HealthApi;
+
+
+HealthApi apiInstance = new HealthApi();
+try {
+ Health result = apiInstance.getHealth();
+ System.out.println(result);
+} catch (ApiException e) {
+ System.err.println("Exception when calling HealthApi#getHealth");
+ e.printStackTrace();
+}
+```
+
+### Parameters
+This endpoint does not need any parameter.
+
+### Return type
+
+[**Health**](Health.md)
+
+### Authorization
+
+No authorization required
+
+### HTTP request headers
+
+ - **Content-Type**: application/json
+ - **Accept**: application/json
+
diff --git a/client/docs/Message.md b/client/docs/Message.md
index e5baed9..64caad4 100644
--- a/client/docs/Message.md
+++ b/client/docs/Message.md
@@ -4,11 +4,11 @@
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
-**appid** | **Integer** | The application id that send this message. |
+**appid** | **Long** | The application id that send this message. |
**date** | [**OffsetDateTime**](OffsetDateTime.md) | The date the message was created. |
**extras** | **Map<String, Object>** | The extra data sent along the message. The extra fields are stored in a key-value scheme. Only accepted in CreateMessage requests with application/json content-type. The keys should be in the following format: <top-namespace>::[<sub-namespace>::]<action> These namespaces are reserved and might be used in the official clients: gotify android ios web server client. Do not use them for other purposes. | [optional]
-**id** | **Integer** | The message id. |
-**message** | **String** | The actual message. |
+**id** | **Long** | The message id. |
+**message** | **String** | The message. Markdown (excluding html) is allowed. |
**priority** | **Long** | The priority of the message. | [optional]
**title** | **String** | The title of the message. | [optional]
diff --git a/client/docs/MessageApi.md b/client/docs/MessageApi.md
index 22e8c03..5f19cb4 100644
--- a/client/docs/MessageApi.md
+++ b/client/docs/MessageApi.md
@@ -109,7 +109,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
MessageApi apiInstance = new MessageApi();
-Integer id = 56; // Integer | the application id
+Long id = 789L; // Long | the application id
try {
Void result = apiInstance.deleteAppMessages(id);
System.out.println(result);
@@ -123,7 +123,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the application id |
+ **id** | **Long**| the application id |
### Return type
@@ -173,7 +173,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
MessageApi apiInstance = new MessageApi();
-Integer id = 56; // Integer | the message id
+Long id = 789L; // Long | the message id
try {
Void result = apiInstance.deleteMessage(id);
System.out.println(result);
@@ -187,7 +187,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the message id |
+ **id** | **Long**| the message id |
### Return type
@@ -297,9 +297,9 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
MessageApi apiInstance = new MessageApi();
-Integer id = 56; // Integer | the application id
+Long id = 789L; // Long | the application id
Integer limit = 100; // Integer | the maximal amount of messages to return
-Integer since = 56; // Integer | return all messages with an ID less than this value
+Long since = 789L; // Long | return all messages with an ID less than this value
try {
PagedMessages result = apiInstance.getAppMessages(id, limit, since);
System.out.println(result);
@@ -313,9 +313,9 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the application id |
+ **id** | **Long**| the application id |
**limit** | **Integer**| the maximal amount of messages to return | [optional] [default to 100]
- **since** | **Integer**| return all messages with an ID less than this value | [optional]
+ **since** | **Long**| return all messages with an ID less than this value | [optional]
### Return type
@@ -366,7 +366,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
MessageApi apiInstance = new MessageApi();
Integer limit = 100; // Integer | the maximal amount of messages to return
-Integer since = 56; // Integer | return all messages with an ID less than this value
+Long since = 789L; // Long | return all messages with an ID less than this value
try {
PagedMessages result = apiInstance.getMessages(limit, since);
System.out.println(result);
@@ -381,7 +381,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**limit** | **Integer**| the maximal amount of messages to return | [optional] [default to 100]
- **since** | **Integer**| return all messages with an ID less than this value | [optional]
+ **since** | **Long**| return all messages with an ID less than this value | [optional]
### Return type
diff --git a/client/docs/Paging.md b/client/docs/Paging.md
index 37ca059..ef1a360 100644
--- a/client/docs/Paging.md
+++ b/client/docs/Paging.md
@@ -6,7 +6,7 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**limit** | **Long** | The limit of the messages for the current request. |
**next** | **String** | The request url for the next page. Empty/Null when no next page is available. | [optional]
-**since** | **Integer** | The ID of the last message returned in the current request. Use this as alternative to the next link. |
+**since** | **Long** | The ID of the last message returned in the current request. Use this as alternative to the next link. |
**size** | **Long** | The amount of messages that got returned in the current request. |
diff --git a/client/docs/PluginApi.md b/client/docs/PluginApi.md
index 0aa3544..f52d235 100644
--- a/client/docs/PluginApi.md
+++ b/client/docs/PluginApi.md
@@ -47,7 +47,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
PluginApi apiInstance = new PluginApi();
-Integer id = 56; // Integer | the plugin id
+Long id = 789L; // Long | the plugin id
try {
Void result = apiInstance.disablePlugin(id);
System.out.println(result);
@@ -61,7 +61,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the plugin id |
+ **id** | **Long**| the plugin id |
### Return type
@@ -111,7 +111,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
PluginApi apiInstance = new PluginApi();
-Integer id = 56; // Integer | the plugin id
+Long id = 789L; // Long | the plugin id
try {
Void result = apiInstance.enablePlugin(id);
System.out.println(result);
@@ -125,7 +125,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the plugin id |
+ **id** | **Long**| the plugin id |
### Return type
@@ -175,7 +175,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
PluginApi apiInstance = new PluginApi();
-Integer id = 56; // Integer | the plugin id
+Long id = 789L; // Long | the plugin id
try {
Object result = apiInstance.getPluginConfig(id);
System.out.println(result);
@@ -189,7 +189,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the plugin id |
+ **id** | **Long**| the plugin id |
### Return type
@@ -239,7 +239,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
PluginApi apiInstance = new PluginApi();
-Integer id = 56; // Integer | the plugin id
+Long id = 789L; // Long | the plugin id
try {
String result = apiInstance.getPluginDisplay(id);
System.out.println(result);
@@ -253,7 +253,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the plugin id |
+ **id** | **Long**| the plugin id |
### Return type
@@ -363,7 +363,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
PluginApi apiInstance = new PluginApi();
-Integer id = 56; // Integer | the plugin id
+Long id = 789L; // Long | the plugin id
try {
Void result = apiInstance.updatePluginConfig(id);
System.out.println(result);
@@ -377,7 +377,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the plugin id |
+ **id** | **Long**| the plugin id |
### Return type
diff --git a/client/docs/PluginConf.md b/client/docs/PluginConf.md
index 0a78fb1..daecd72 100644
--- a/client/docs/PluginConf.md
+++ b/client/docs/PluginConf.md
@@ -7,7 +7,7 @@ Name | Type | Description | Notes
**author** | **String** | The author of the plugin. | [optional]
**capabilities** | **List<String>** | Capabilities the plugin provides |
**enabled** | **Boolean** | Whether the plugin instance is enabled. |
-**id** | **Integer** | The plugin id. |
+**id** | **Long** | The plugin id. |
**license** | **String** | The license of the plugin. | [optional]
**modulePath** | **String** | The module path of the plugin. |
**name** | **String** | The plugin name. |
diff --git a/client/docs/User.md b/client/docs/User.md
index 431c4c7..34b372c 100644
--- a/client/docs/User.md
+++ b/client/docs/User.md
@@ -5,7 +5,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**admin** | **Boolean** | If the user is an administrator. | [optional]
-**id** | **Integer** | The user id. |
+**id** | **Long** | The user id. |
**name** | **String** | The user name. For login. |
diff --git a/client/docs/UserApi.md b/client/docs/UserApi.md
index 3d8fd33..2305bba 100644
--- a/client/docs/UserApi.md
+++ b/client/docs/UserApi.md
@@ -172,7 +172,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
UserApi apiInstance = new UserApi();
-Integer id = 56; // Integer | the user id
+Long id = 789L; // Long | the user id
try {
Void result = apiInstance.deleteUser(id);
System.out.println(result);
@@ -186,7 +186,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the user id |
+ **id** | **Long**| the user id |
### Return type
@@ -236,7 +236,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
UserApi apiInstance = new UserApi();
-Integer id = 56; // Integer | the user id
+Long id = 789L; // Long | the user id
try {
User result = apiInstance.getUser(id);
System.out.println(result);
@@ -250,7 +250,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the user id |
+ **id** | **Long**| the user id |
### Return type
@@ -424,7 +424,7 @@ clientTokenQuery.setApiKey("YOUR API KEY");
//clientTokenQuery.setApiKeyPrefix("Token");
UserApi apiInstance = new UserApi();
-Integer id = 56; // Integer | the user id
+Long id = 789L; // Long | the user id
UserWithPass body = new UserWithPass(); // UserWithPass | the updated user
try {
User result = apiInstance.updateUser(id, body);
@@ -439,7 +439,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **id** | **Integer**| the user id |
+ **id** | **Long**| the user id |
**body** | [**UserWithPass**](UserWithPass.md)| the updated user |
### Return type
diff --git a/client/docs/UserWithPass.md b/client/docs/UserWithPass.md
index ad34a03..2a24912 100644
--- a/client/docs/UserWithPass.md
+++ b/client/docs/UserWithPass.md
@@ -5,7 +5,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**admin** | **Boolean** | If the user is an administrator. | [optional]
-**id** | **Integer** | The user id. |
+**id** | **Long** | The user id. |
**name** | **String** | The user name. For login. |
**pass** | **String** | The user password. For login. |
diff --git a/client/src/main/java/com/github/gotify/client/JSON.java b/client/src/main/java/com/github/gotify/client/JSON.java
index 918b320..fdd1edb 100644
--- a/client/src/main/java/com/github/gotify/client/JSON.java
+++ b/client/src/main/java/com/github/gotify/client/JSON.java
@@ -2,7 +2,7 @@
* Gotify REST-API.
* This is the documentation of the Gotify REST-API. # Authentication In Gotify there are two token types: __clientToken__: a client is something that receives message and manages stuff like creating new tokens or delete messages. (f.ex this token should be used for an android app) __appToken__: an application is something that sends messages (f.ex. this token should be used for a shell script) The token can be either transmitted through a header named `X-Gotify-Key` or a query parameter named `token`. There is also the possibility to authenticate through basic auth, this should only be used for creating a clientToken. \\--- Found a bug or have some questions? [Create an issue on GitHub](https://github.com/gotify/server/issues)
*
- * OpenAPI spec version: 1.0.6
+ * OpenAPI spec version: 2.0.1
*
*
* NOTE: This class is auto generated by the swagger code generator program.
diff --git a/client/src/main/java/com/github/gotify/client/StringUtil.java b/client/src/main/java/com/github/gotify/client/StringUtil.java
index c042ca5..b4f7158 100644
--- a/client/src/main/java/com/github/gotify/client/StringUtil.java
+++ b/client/src/main/java/com/github/gotify/client/StringUtil.java
@@ -2,7 +2,7 @@
* Gotify REST-API.
* This is the documentation of the Gotify REST-API. # Authentication In Gotify there are two token types: __clientToken__: a client is something that receives message and manages stuff like creating new tokens or delete messages. (f.ex this token should be used for an android app) __appToken__: an application is something that sends messages (f.ex. this token should be used for a shell script) The token can be either transmitted through a header named `X-Gotify-Key` or a query parameter named `token`. There is also the possibility to authenticate through basic auth, this should only be used for creating a clientToken. \\--- Found a bug or have some questions? [Create an issue on GitHub](https://github.com/gotify/server/issues)
*
- * OpenAPI spec version: 1.0.6
+ * OpenAPI spec version: 2.0.1
*
*
* NOTE: This class is auto generated by the swagger code generator program.
@@ -13,7 +13,7 @@
package com.github.gotify.client;
-@javax.annotation.Generated(value = "io.swagger.codegen.languages.JavaClientCodegen", date = "2019-02-17T19:42:51.206+01:00")
+@javax.annotation.Generated(value = "io.swagger.codegen.languages.JavaClientCodegen", date = "2020-06-24T18:39:01.386+02:00")
public class StringUtil {
/**
* Check if the given array contains the given value (with case-insensitive comparison).
diff --git a/client/src/main/java/com/github/gotify/client/api/ApplicationApi.java b/client/src/main/java/com/github/gotify/client/api/ApplicationApi.java
index 375e6ff..2a7de1c 100644
--- a/client/src/main/java/com/github/gotify/client/api/ApplicationApi.java
+++ b/client/src/main/java/com/github/gotify/client/api/ApplicationApi.java
@@ -43,7 +43,7 @@ public interface ApplicationApi {
})
@DELETE("application/{id}")
Call deleteApp(
- @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Path("id") Long id
);
/**
@@ -70,7 +70,7 @@ public interface ApplicationApi {
})
@PUT("application/{id}")
Call updateApplication(
- @retrofit2.http.Body Application body, @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Body Application body, @retrofit2.http.Path("id") Long id
);
/**
@@ -83,7 +83,7 @@ public interface ApplicationApi {
@retrofit2.http.Multipart
@POST("application/{id}/image")
Call uploadAppImage(
- @retrofit2.http.Part("file\"; filename=\"file") RequestBody file, @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Part("file\"; filename=\"file") RequestBody file, @retrofit2.http.Path("id") Long id
);
}
diff --git a/client/src/main/java/com/github/gotify/client/api/ClientApi.java b/client/src/main/java/com/github/gotify/client/api/ClientApi.java
index 71cb1b6..3da8dda 100644
--- a/client/src/main/java/com/github/gotify/client/api/ClientApi.java
+++ b/client/src/main/java/com/github/gotify/client/api/ClientApi.java
@@ -42,7 +42,7 @@ public interface ClientApi {
})
@DELETE("client/{id}")
Call deleteClient(
- @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Path("id") Long id
);
/**
@@ -57,4 +57,19 @@ public interface ClientApi {
Call> getClients();
+ /**
+ * Update a client.
+ *
+ * @param body the client to update (required)
+ * @param id the client id (required)
+ * @return Call<Client>
+ */
+ @Headers({
+ "Content-Type:application/json"
+ })
+ @PUT("client/{id}")
+ Call updateClient(
+ @retrofit2.http.Body Client body, @retrofit2.http.Path("id") Long id
+ );
+
}
diff --git a/client/src/main/java/com/github/gotify/client/api/HealthApi.java b/client/src/main/java/com/github/gotify/client/api/HealthApi.java
new file mode 100644
index 0000000..38a37a9
--- /dev/null
+++ b/client/src/main/java/com/github/gotify/client/api/HealthApi.java
@@ -0,0 +1,31 @@
+package com.github.gotify.client.api;
+
+import com.github.gotify.client.CollectionFormats.*;
+
+import retrofit2.Call;
+import retrofit2.http.*;
+
+import okhttp3.RequestBody;
+import okhttp3.ResponseBody;
+
+import com.github.gotify.client.model.Health;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public interface HealthApi {
+ /**
+ * Get health information.
+ *
+ * @return Call<Health>
+ */
+ @Headers({
+ "Content-Type:application/json"
+ })
+ @GET("health")
+ Call getHealth();
+
+
+}
diff --git a/client/src/main/java/com/github/gotify/client/api/MessageApi.java b/client/src/main/java/com/github/gotify/client/api/MessageApi.java
index 60df793..8e54861 100644
--- a/client/src/main/java/com/github/gotify/client/api/MessageApi.java
+++ b/client/src/main/java/com/github/gotify/client/api/MessageApi.java
@@ -43,7 +43,7 @@ public interface MessageApi {
})
@DELETE("application/{id}/message")
Call deleteAppMessages(
- @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Path("id") Long id
);
/**
@@ -57,7 +57,7 @@ public interface MessageApi {
})
@DELETE("message/{id}")
Call deleteMessage(
- @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Path("id") Long id
);
/**
@@ -85,7 +85,7 @@ public interface MessageApi {
})
@GET("application/{id}/message")
Call getAppMessages(
- @retrofit2.http.Path("id") Integer id, @retrofit2.http.Query("limit") Integer limit, @retrofit2.http.Query("since") Integer since
+ @retrofit2.http.Path("id") Long id, @retrofit2.http.Query("limit") Integer limit, @retrofit2.http.Query("since") Long since
);
/**
@@ -100,7 +100,7 @@ public interface MessageApi {
})
@GET("message")
Call getMessages(
- @retrofit2.http.Query("limit") Integer limit, @retrofit2.http.Query("since") Integer since
+ @retrofit2.http.Query("limit") Integer limit, @retrofit2.http.Query("since") Long since
);
/**
diff --git a/client/src/main/java/com/github/gotify/client/api/PluginApi.java b/client/src/main/java/com/github/gotify/client/api/PluginApi.java
index b144706..ed54908 100644
--- a/client/src/main/java/com/github/gotify/client/api/PluginApi.java
+++ b/client/src/main/java/com/github/gotify/client/api/PluginApi.java
@@ -28,7 +28,7 @@ public interface PluginApi {
})
@POST("plugin/{id}/disable")
Call disablePlugin(
- @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Path("id") Long id
);
/**
@@ -42,7 +42,7 @@ public interface PluginApi {
})
@POST("plugin/{id}/enable")
Call enablePlugin(
- @retrofit2.http.Path("id") Integer id
+ @retrofit2.http.Path("id") Long id
);
/**
@@ -56,7 +56,7 @@ public interface PluginApi {
})
@GET("plugin/{id}/config")
Call