Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
e4651375aa
|
|||
![]() |
afce4c6391 | ||
e95d0cb010
|
|||
f717355519
|
|||
3368e514ca
|
|||
9dca27177f
|
|||
c63274f7a9
|
|||
6c2d2d2345
|
|||
a6fbaa192f
|
|||
![]() |
a01f156535 | ||
3b021c09dc
|
|||
287176c881
|
|||
84eeb5a002
|
|||
b892532023
|
|||
![]() |
56cdc52bb4 | ||
9ef6b1dd91
|
|||
6f7585323b
|
|||
92135e64a3
|
|||
28efeea30b
|
|||
a8a074907b
|
|||
6c29ec9820
|
|||
![]() |
8ec23144ca | ||
b703853b28
|
|||
6f7529fc9b
|
|||
27b45098f0
|
|||
21f66d99cd
|
|||
1745051e6e
|
|||
![]() |
b395e054e6 |
53
android/.idea/assetWizardSettings.xml
generated
@@ -3,6 +3,59 @@
|
|||||||
<component name="WizardSettings">
|
<component name="WizardSettings">
|
||||||
<option name="children">
|
<option name="children">
|
||||||
<map>
|
<map>
|
||||||
|
<entry key="imageWizard">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="imageAssetPanel">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="children">
|
||||||
|
<map>
|
||||||
|
<entry key="launcherLegacy">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="assetType" value="IMAGE" />
|
||||||
|
<entry key="cropped" value="true" />
|
||||||
|
<entry key="iconShape" value="NONE" />
|
||||||
|
<entry key="imageAsset" value="F:\Eigene Dateien\Dropbox\Programming\Java\AndroidStudioProjects\SimpleCloudNotifier\data\icon_512_nobox.png" />
|
||||||
|
<entry key="outputName" value="ic_notification_full" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="notification">
|
||||||
|
<value>
|
||||||
|
<PersistentState>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="assetType" value="IMAGE" />
|
||||||
|
<entry key="imageAsset" value="F:\Eigene Dateien\Dropbox\Programming\Java\AndroidStudioProjects\SimpleCloudNotifier\data\icon_512_transparent.png" />
|
||||||
|
<entry key="outputName" value="ic_notification_white" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="values">
|
||||||
|
<map>
|
||||||
|
<entry key="outputIconType" value="LAUNCHER_LEGACY" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</PersistentState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
<entry key="vectorWizard">
|
<entry key="vectorWizard">
|
||||||
<value>
|
<value>
|
||||||
<PersistentState>
|
<PersistentState>
|
||||||
|
BIN
android/app/src/main/ic_bfb_raster-web.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
android/app/src/main/ic_notification_full-web.png
Normal file
After Width: | Height: | Size: 67 KiB |
@@ -99,14 +99,4 @@ public class SCNApp extends Application implements LifecycleObserver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
//TODO TabLayout indicator does not corretly animate when directly clicking on tabs
|
||||||
==TODO==
|
|
||||||
|
|
||||||
[ ] - test notification channels
|
|
||||||
[ ] - startup time
|
|
||||||
[ ] - periodically get non-ack (option - even when not in-app)
|
|
||||||
|
|
||||||
[ ] - publish (+ HN post ?)
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
@@ -24,6 +24,11 @@ public final class CollectionHelper
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> void sort_inplace(List<T> input, Comparator<T> comparator)
|
||||||
|
{
|
||||||
|
Collections.sort(input, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
public static <T, U extends Comparable<U>> List<T> sort(List<T> input, Func1to1<T, U> mapper)
|
public static <T, U extends Comparable<U>> List<T> sort(List<T> input, Func1to1<T, U> mapper)
|
||||||
{
|
{
|
||||||
return sort(input, mapper, 1);
|
return sort(input, mapper, 1);
|
||||||
|
@@ -0,0 +1,19 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.lib.datatypes;
|
||||||
|
|
||||||
|
public class Tuple5<T1, T2, T3, T4, T5>
|
||||||
|
{
|
||||||
|
public final T1 Item1;
|
||||||
|
public final T2 Item2;
|
||||||
|
public final T3 Item3;
|
||||||
|
public final T4 Item4;
|
||||||
|
public final T5 Item5;
|
||||||
|
|
||||||
|
public Tuple5(T1 i1, T2 i2, T3 i3, T4 i4, T5 i5)
|
||||||
|
{
|
||||||
|
Item1 = i1;
|
||||||
|
Item2 = i2;
|
||||||
|
Item3 = i3;
|
||||||
|
Item4 = i4;
|
||||||
|
Item5 = i5;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.lib.lambda;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Func5to0<TInput1, TInput2, TInput3, TInput4, TInput5> {
|
||||||
|
void invoke(TInput1 value1, TInput2 value2, TInput3 value3, TInput4 value4, TInput5 value5);
|
||||||
|
}
|
@@ -3,17 +3,21 @@ package com.blackforestbytes.simplecloudnotifier.model;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.collections.CollectionHelper;
|
||||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||||
import com.blackforestbytes.simplecloudnotifier.view.MessageAdapter;
|
import com.blackforestbytes.simplecloudnotifier.view.MessageAdapter;
|
||||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class CMessageList
|
public class CMessageList
|
||||||
{
|
{
|
||||||
|
private final Object msg_lock = new Object();
|
||||||
|
|
||||||
public ArrayList<CMessage> Messages;
|
public ArrayList<CMessage> Messages;
|
||||||
public Set<String> AllAcks;
|
public Set<String> AllAcks;
|
||||||
|
|
||||||
@@ -32,23 +36,26 @@ public class CMessageList
|
|||||||
|
|
||||||
private CMessageList()
|
private CMessageList()
|
||||||
{
|
{
|
||||||
Messages = new ArrayList<>();
|
synchronized (msg_lock)
|
||||||
AllAcks = new HashSet<>();
|
|
||||||
|
|
||||||
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
|
|
||||||
int count = sharedPref.getInt("message_count", 0);
|
|
||||||
for (int i=0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
long time = sharedPref.getLong("message["+i+"].timestamp", 0);
|
Messages = new ArrayList<>();
|
||||||
String title = sharedPref.getString("message["+i+"].title", "");
|
AllAcks = new HashSet<>();
|
||||||
String content = sharedPref.getString("message["+i+"].content", "");
|
|
||||||
PriorityEnum prio = PriorityEnum.parseAPI(sharedPref.getInt("message["+i+"].priority", 1));
|
|
||||||
long scnid = sharedPref.getLong("message["+i+"].scnid", 0);
|
|
||||||
|
|
||||||
Messages.add(new CMessage(scnid, time, title, content, prio));
|
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
|
||||||
|
int count = sharedPref.getInt("message_count", 0);
|
||||||
|
for (int i=0; i < count; i++)
|
||||||
|
{
|
||||||
|
long time = sharedPref.getLong("message["+i+"].timestamp", 0);
|
||||||
|
String title = sharedPref.getString("message["+i+"].title", "");
|
||||||
|
String content = sharedPref.getString("message["+i+"].content", "");
|
||||||
|
PriorityEnum prio = PriorityEnum.parseAPI(sharedPref.getInt("message["+i+"].priority", 1));
|
||||||
|
long scnid = sharedPref.getLong("message["+i+"].scnid", 0);
|
||||||
|
|
||||||
|
Messages.add(new CMessage(scnid, time, title, content, prio));
|
||||||
|
}
|
||||||
|
|
||||||
|
AllAcks = sharedPref.getStringSet("acks", new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
AllAcks = sharedPref.getStringSet("acks", new HashSet<>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CMessage add(final long scnid, final long time, final String title, final String content, final PriorityEnum pe)
|
public CMessage add(final long scnid, final long time, final String title, final String content, final PriorityEnum pe)
|
||||||
@@ -60,29 +67,44 @@ public class CMessageList
|
|||||||
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
|
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
|
||||||
int count = sharedPref.getInt("message_count", 0);
|
int count = sharedPref.getInt("message_count", 0);
|
||||||
|
|
||||||
SharedPreferences.Editor e = sharedPref.edit();
|
synchronized (msg_lock)
|
||||||
|
{
|
||||||
|
Messages.add(msg);
|
||||||
|
AllAcks.add(Long.toHexString(msg.SCN_ID));
|
||||||
|
|
||||||
Messages.add(msg);
|
while (Messages.size()>SCNSettings.inst().LocalCacheSize) Messages.remove(0);
|
||||||
AllAcks.add(Long.toHexString(msg.SCN_ID));
|
}
|
||||||
|
|
||||||
while (Messages.size()>SCNSettings.inst().LocalCacheSize) Messages.remove(0);
|
if (Messages.size()>1 && Messages.get(Messages.size()-2).Timestamp < msg.Timestamp)
|
||||||
|
{
|
||||||
|
// quick save
|
||||||
|
|
||||||
e.putInt( "message_count", count+1);
|
SharedPreferences.Editor e = sharedPref.edit();
|
||||||
e.putLong( "message["+count+"].timestamp", time);
|
|
||||||
e.putString("message["+count+"].title", title);
|
|
||||||
e.putString("message["+count+"].content", content);
|
|
||||||
e.putInt( "message["+count+"].priority", pe.ID);
|
|
||||||
e.putLong( "message["+count+"].scnid", scnid);
|
|
||||||
|
|
||||||
e.putStringSet("acks", AllAcks);
|
e.putInt( "message_count", count+1);
|
||||||
|
e.putLong( "message["+count+"].timestamp", time);
|
||||||
|
e.putString("message["+count+"].title", title);
|
||||||
|
e.putString("message["+count+"].content", content);
|
||||||
|
e.putInt( "message["+count+"].priority", pe.ID);
|
||||||
|
e.putLong( "message["+count+"].scnid", scnid);
|
||||||
|
|
||||||
|
e.putStringSet("acks", AllAcks);
|
||||||
|
|
||||||
|
e.apply();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// full save
|
||||||
|
|
||||||
|
fullSave(); // does sort in here
|
||||||
|
}
|
||||||
|
|
||||||
e.apply();
|
|
||||||
|
|
||||||
for (WeakReference<MessageAdapter> ref : _listener)
|
for (WeakReference<MessageAdapter> ref : _listener)
|
||||||
{
|
{
|
||||||
MessageAdapter a = ref.get();
|
MessageAdapter a = ref.get();
|
||||||
if (a == null) continue;
|
if (a == null) continue;
|
||||||
a.customNotifyItemInserted(count);
|
a.customNotifyDataSetChanged();
|
||||||
a.scrollToTop();
|
a.scrollToTop();
|
||||||
}
|
}
|
||||||
CleanUpListener();
|
CleanUpListener();
|
||||||
@@ -90,9 +112,12 @@ public class CMessageList
|
|||||||
|
|
||||||
if (!run)
|
if (!run)
|
||||||
{
|
{
|
||||||
Messages.add(new CMessage(scnid, time, title, content, pe));
|
synchronized (msg_lock)
|
||||||
AllAcks.add(Long.toHexString(msg.SCN_ID));
|
{
|
||||||
fullSave();
|
Messages.add(new CMessage(scnid, time, title, content, pe));
|
||||||
|
AllAcks.add(Long.toHexString(msg.SCN_ID));
|
||||||
|
}
|
||||||
|
fullSave(); // does sort in here
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
@@ -114,31 +139,39 @@ public class CMessageList
|
|||||||
|
|
||||||
public void fullSave()
|
public void fullSave()
|
||||||
{
|
{
|
||||||
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
|
synchronized (msg_lock)
|
||||||
SharedPreferences.Editor e = sharedPref.edit();
|
|
||||||
|
|
||||||
e.clear();
|
|
||||||
|
|
||||||
e.putInt("message_count", Messages.size());
|
|
||||||
|
|
||||||
for (int i = 0; i < Messages.size(); i++)
|
|
||||||
{
|
{
|
||||||
e.putLong( "message["+i+"].timestamp", Messages.get(i).Timestamp);
|
CollectionHelper.sort_inplace(Messages, (a,b) -> Long.compare(a.Timestamp, b.Timestamp));
|
||||||
e.putString("message["+i+"].title", Messages.get(i).Title);
|
|
||||||
e.putString("message["+i+"].content", Messages.get(i).Content);
|
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
|
||||||
e.putInt( "message["+i+"].priority", Messages.get(i).Priority.ID);
|
SharedPreferences.Editor e = sharedPref.edit();
|
||||||
e.putLong( "message["+i+"].scnid", Messages.get(i).SCN_ID);
|
|
||||||
|
e.clear();
|
||||||
|
|
||||||
|
e.putInt("message_count", Messages.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < Messages.size(); i++)
|
||||||
|
{
|
||||||
|
e.putLong( "message["+i+"].timestamp", Messages.get(i).Timestamp);
|
||||||
|
e.putString("message["+i+"].title", Messages.get(i).Title);
|
||||||
|
e.putString("message["+i+"].content", Messages.get(i).Content);
|
||||||
|
e.putInt( "message["+i+"].priority", Messages.get(i).Priority.ID);
|
||||||
|
e.putLong( "message["+i+"].scnid", Messages.get(i).SCN_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.putStringSet("acks", AllAcks);
|
||||||
|
|
||||||
|
e.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
e.putStringSet("acks", AllAcks);
|
|
||||||
|
|
||||||
e.apply();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CMessage tryGet(int pos)
|
public CMessage tryGet(int pos)
|
||||||
{
|
{
|
||||||
if (pos < 0 || pos >= Messages.size()) return null;
|
synchronized (msg_lock)
|
||||||
return Messages.get(pos);
|
{
|
||||||
|
if (pos < 0 || pos >= Messages.size()) return null;
|
||||||
|
return Messages.get(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CMessage tryGetFromBack(int pos)
|
public CMessage tryGetFromBack(int pos)
|
||||||
@@ -148,7 +181,10 @@ public class CMessageList
|
|||||||
|
|
||||||
public int size()
|
public int size()
|
||||||
{
|
{
|
||||||
return Messages.size();
|
synchronized (msg_lock)
|
||||||
|
{
|
||||||
|
return Messages.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(MessageAdapter adp)
|
public void register(MessageAdapter adp)
|
||||||
@@ -167,18 +203,30 @@ public class CMessageList
|
|||||||
|
|
||||||
public boolean isAck(long id)
|
public boolean isAck(long id)
|
||||||
{
|
{
|
||||||
return AllAcks.contains(Long.toHexString(id));
|
synchronized (msg_lock)
|
||||||
|
{
|
||||||
|
return AllAcks.contains(Long.toHexString(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(int index)
|
public CMessage removeFromBack(int pos)
|
||||||
{
|
{
|
||||||
Messages.remove(index);
|
CMessage r;
|
||||||
fullSave();
|
synchronized (msg_lock)
|
||||||
|
{
|
||||||
|
int index = Messages.size() - pos - 1;
|
||||||
|
r = Messages.remove(index);
|
||||||
|
}
|
||||||
|
fullSave(); // does sort in here
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insert(int index, CMessage item)
|
public void insert(int index, CMessage item)
|
||||||
{
|
{
|
||||||
Messages.add(index, item);
|
synchronized (msg_lock)
|
||||||
fullSave();
|
{
|
||||||
|
Messages.add(index, item);
|
||||||
|
}
|
||||||
|
fullSave(); // does sort in here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,14 +15,19 @@ import com.google.firebase.iid.FirebaseInstanceId;
|
|||||||
public class SCNSettings
|
public class SCNSettings
|
||||||
{
|
{
|
||||||
private final static Object _lock = new Object();
|
private final static Object _lock = new Object();
|
||||||
private static SCNSettings _inst = null;
|
private static volatile SCNSettings _inst = null;
|
||||||
public static SCNSettings inst()
|
public static SCNSettings inst()
|
||||||
{
|
{
|
||||||
synchronized (_lock)
|
SCNSettings local = _inst;
|
||||||
|
if (local == null)
|
||||||
{
|
{
|
||||||
if (_inst != null) return _inst;
|
synchronized (_lock)
|
||||||
return _inst = new SCNSettings();
|
{
|
||||||
|
local = _inst;
|
||||||
|
if (local == null) _inst = local = new SCNSettings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
@@ -47,6 +52,7 @@ public class SCNSettings
|
|||||||
|
|
||||||
public boolean Enabled = true;
|
public boolean Enabled = true;
|
||||||
public int LocalCacheSize = 500;
|
public int LocalCacheSize = 500;
|
||||||
|
public boolean EnableDeleteSwipe = true;
|
||||||
|
|
||||||
public final NotificationSettings PriorityLow = new NotificationSettings(PriorityEnum.LOW);
|
public final NotificationSettings PriorityLow = new NotificationSettings(PriorityEnum.LOW);
|
||||||
public final NotificationSettings PriorityNorm = new NotificationSettings(PriorityEnum.NORMAL);
|
public final NotificationSettings PriorityNorm = new NotificationSettings(PriorityEnum.NORMAL);
|
||||||
@@ -70,6 +76,7 @@ public class SCNSettings
|
|||||||
|
|
||||||
Enabled = sharedPref.getBoolean("app_enabled", Enabled);
|
Enabled = sharedPref.getBoolean("app_enabled", Enabled);
|
||||||
LocalCacheSize = sharedPref.getInt("local_cache_size", LocalCacheSize);
|
LocalCacheSize = sharedPref.getInt("local_cache_size", LocalCacheSize);
|
||||||
|
EnableDeleteSwipe = sharedPref.getBoolean("do_del_swipe", EnableDeleteSwipe);
|
||||||
|
|
||||||
PriorityLow.EnableLED = sharedPref.getBoolean("priority_low:enabled_led", PriorityLow.EnableLED);
|
PriorityLow.EnableLED = sharedPref.getBoolean("priority_low:enabled_led", PriorityLow.EnableLED);
|
||||||
PriorityLow.EnableSound = sharedPref.getBoolean("priority_low:enabled_sound", PriorityLow.EnableSound);
|
PriorityLow.EnableSound = sharedPref.getBoolean("priority_low:enabled_sound", PriorityLow.EnableSound);
|
||||||
@@ -116,6 +123,7 @@ public class SCNSettings
|
|||||||
|
|
||||||
e.putBoolean("app_enabled", Enabled);
|
e.putBoolean("app_enabled", Enabled);
|
||||||
e.putInt( "local_cache_size", LocalCacheSize);
|
e.putInt( "local_cache_size", LocalCacheSize);
|
||||||
|
e.putBoolean("do_del_swipe", EnableDeleteSwipe);
|
||||||
|
|
||||||
e.putBoolean("priority_low:enabled_led", PriorityLow.EnableLED);
|
e.putBoolean("priority_low:enabled_led", PriorityLow.EnableLED);
|
||||||
e.putBoolean("priority_low:enabled_sound", PriorityLow.EnableSound);
|
e.putBoolean("priority_low:enabled_sound", PriorityLow.EnableSound);
|
||||||
@@ -155,10 +163,12 @@ public class SCNSettings
|
|||||||
return user_id>=0 && user_key != null && !user_key.isEmpty();
|
return user_id>=0 && user_key != null && !user_key.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String createOnlineURL()
|
public String createOnlineURL(boolean longurl)
|
||||||
{
|
{
|
||||||
if (!isConnected()) return ServerCommunication.BASE_URL + "index.php";
|
String base = longurl ? ServerCommunication.PAGE_URL_LONG : ServerCommunication.PAGE_URL_SHORT;
|
||||||
return ServerCommunication.BASE_URL + "index.php?preset_user_id="+user_id+"&preset_user_key="+user_key;
|
|
||||||
|
if (!isConnected()) return base;
|
||||||
|
return base + "index.php?preset_user_id="+user_id+"&preset_user_key="+user_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setServerToken(String token, View loader)
|
public void setServerToken(String token, View loader)
|
||||||
@@ -184,7 +194,7 @@ public class SCNSettings
|
|||||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(a, instanceIdResult ->
|
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(a, instanceIdResult ->
|
||||||
{
|
{
|
||||||
String newToken = instanceIdResult.getToken();
|
String newToken = instanceIdResult.getToken();
|
||||||
Log.e("FB::GetInstanceId", newToken);
|
Log.d("FB::GetInstanceId", newToken);
|
||||||
SCNSettings.inst().setServerToken(newToken, null);
|
SCNSettings.inst().setServerToken(newToken, null);
|
||||||
}).addOnCompleteListener(r ->
|
}).addOnCompleteListener(r ->
|
||||||
{
|
{
|
||||||
@@ -219,7 +229,7 @@ public class SCNSettings
|
|||||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(a, instanceIdResult ->
|
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(a, instanceIdResult ->
|
||||||
{
|
{
|
||||||
String newToken = instanceIdResult.getToken();
|
String newToken = instanceIdResult.getToken();
|
||||||
Log.e("FB::GetInstanceId", newToken);
|
Log.d("FB::GetInstanceId", newToken);
|
||||||
SCNSettings.inst().setServerToken(newToken, loader); // does register in here
|
SCNSettings.inst().setServerToken(newToken, loader); // does register in here
|
||||||
}).addOnCompleteListener(r ->
|
}).addOnCompleteListener(r ->
|
||||||
{
|
{
|
||||||
|
@@ -4,6 +4,9 @@ import android.util.Log;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple5;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.lambda.Func1to0;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.lambda.Func5to0;
|
||||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||||
import com.blackforestbytes.simplecloudnotifier.service.FBMService;
|
import com.blackforestbytes.simplecloudnotifier.service.FBMService;
|
||||||
|
|
||||||
@@ -24,7 +27,9 @@ import okhttp3.ResponseBody;
|
|||||||
|
|
||||||
public class ServerCommunication
|
public class ServerCommunication
|
||||||
{
|
{
|
||||||
public static final String BASE_URL = /*SCNApp.LOCAL_DEBUG ? "http://localhost:1010/" : */"https://scn.blackforestbytes.com/api/";
|
public static final String PAGE_URL_LONG = "https://simplecloudnotifier.blackforestbytes.com/";
|
||||||
|
public static final String PAGE_URL_SHORT = "https://scn.blackforestbytes.com/";
|
||||||
|
public static final String BASE_URL = "https://scn.blackforestbytes.com/api/";
|
||||||
|
|
||||||
private static final OkHttpClient client = new OkHttpClient();
|
private static final OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
@@ -57,7 +62,7 @@ public class ServerCommunication
|
|||||||
if (responseBody == null) throw new IOException("No response");
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
String r = responseBody.string();
|
String r = responseBody.string();
|
||||||
Log.d("Server::Response", r);
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
@@ -123,7 +128,7 @@ public class ServerCommunication
|
|||||||
if (responseBody == null) throw new IOException("No response");
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
String r = responseBody.string();
|
String r = responseBody.string();
|
||||||
Log.d("Server::Response", r);
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
@@ -185,7 +190,7 @@ public class ServerCommunication
|
|||||||
if (responseBody == null) throw new IOException("No response");
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
String r = responseBody.string();
|
String r = responseBody.string();
|
||||||
Log.d("Server::Response", r);
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
@@ -246,7 +251,7 @@ public class ServerCommunication
|
|||||||
if (responseBody == null) throw new IOException("No response");
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
String r = responseBody.string();
|
String r = responseBody.string();
|
||||||
Log.d("Server::Response", r);
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
@@ -283,10 +288,7 @@ public class ServerCommunication
|
|||||||
|
|
||||||
SCNApp.refreshAccountTab();
|
SCNApp.refreshAccountTab();
|
||||||
|
|
||||||
if (json_int(json, "unack_count")>0)
|
if (json_int(json, "unack_count")>0) ServerCommunication.requery(id, key, loader);
|
||||||
{
|
|
||||||
ServerCommunication.requery(id, key, loader);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("SC:info", e.toString());
|
Log.e("SC:info", e.toString());
|
||||||
@@ -332,7 +334,7 @@ public class ServerCommunication
|
|||||||
if (responseBody == null) throw new IOException("No response");
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
String r = responseBody.string();
|
String r = responseBody.string();
|
||||||
Log.d("Server::Response", r);
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
@@ -346,7 +348,7 @@ public class ServerCommunication
|
|||||||
JSONArray arr = json.getJSONArray("data");
|
JSONArray arr = json.getJSONArray("data");
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
JSONObject o = arr.getJSONObject(0);
|
JSONObject o = arr.getJSONObject(i);
|
||||||
|
|
||||||
long time = json_lng(o, "timestamp");
|
long time = json_lng(o, "timestamp");
|
||||||
String title = json_str(o, "title");
|
String title = json_str(o, "title");
|
||||||
@@ -357,20 +359,6 @@ public class ServerCommunication
|
|||||||
FBMService.recieveData(time, title, content, prio, scn_id, true);
|
FBMService.recieveData(time, title, content, prio, scn_id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCNSettings.inst().user_id = json_int(json, "user_id");
|
|
||||||
SCNSettings.inst().quota_curr = json_int(json, "quota");
|
|
||||||
SCNSettings.inst().quota_max = json_int(json, "quota_max");
|
|
||||||
SCNSettings.inst().promode_server = json_bool(json, "is_pro");
|
|
||||||
if (!json_bool(json, "fcm_token_set")) SCNSettings.inst().fcm_token_server = "";
|
|
||||||
SCNSettings.inst().save();
|
|
||||||
|
|
||||||
SCNApp.refreshAccountTab();
|
|
||||||
|
|
||||||
if (json_int(json, "unack_count")>0)
|
|
||||||
{
|
|
||||||
ServerCommunication.requery(id, key, loader);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("SC:info", e.toString());
|
Log.e("SC:info", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
@@ -414,7 +402,7 @@ public class ServerCommunication
|
|||||||
if (responseBody == null) throw new IOException("No response");
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
String r = responseBody.string();
|
String r = responseBody.string();
|
||||||
Log.d("Server::Response", r);
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
@@ -446,12 +434,12 @@ public class ServerCommunication
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ack(int id, String key, CMessage msg)
|
public static void ack(int id, String key, long msg_scn_id)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(BASE_URL + "ack.php?user_id=" + id + "&user_key=" + key + "&scn_msg_id=" + msg.SCN_ID)
|
.url(BASE_URL + "ack.php?user_id=" + id + "&user_key=" + key + "&scn_msg_id=" + msg_scn_id)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@@ -469,7 +457,7 @@ public class ServerCommunication
|
|||||||
if (responseBody == null) throw new IOException("No response");
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
String r = responseBody.string();
|
String r = responseBody.string();
|
||||||
Log.d("Server::Response", r);
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
@@ -488,6 +476,70 @@ public class ServerCommunication
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void expand(int id, String key, long scn_msg_id, View loader, Func5to0<String, String, PriorityEnum, Long, Long> okResult)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(BASE_URL + "expand.php?user_id=" + id + "&user_key=" + key + "&scn_msg_id=" + scn_msg_id)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
client.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
Log.e("SC:expand", e.toString());
|
||||||
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
|
SCNApp.runOnUiThread(() -> {
|
||||||
|
if (loader != null) loader.setVisibility(View.GONE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, Response response) {
|
||||||
|
try (ResponseBody responseBody = response.body()) {
|
||||||
|
if (!response.isSuccessful())
|
||||||
|
throw new IOException("Unexpected code " + response);
|
||||||
|
if (responseBody == null) throw new IOException("No response");
|
||||||
|
|
||||||
|
String r = responseBody.string();
|
||||||
|
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||||
|
|
||||||
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
|
if (!json_bool(json, "success"))
|
||||||
|
{
|
||||||
|
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject o = json.getJSONObject("data");
|
||||||
|
|
||||||
|
long time = json_lng(o, "timestamp");
|
||||||
|
String title = json_str(o, "title");
|
||||||
|
String content = json_str(o, "body");
|
||||||
|
PriorityEnum prio = PriorityEnum.parseAPI(json_int(o, "priority"));
|
||||||
|
long scn_id = json_lng(o, "scn_msg_id");
|
||||||
|
|
||||||
|
okResult.invoke(title, content, prio, time, scn_id);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("SC:expand", e.toString());
|
||||||
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
|
} finally {
|
||||||
|
SCNApp.runOnUiThread(() -> {
|
||||||
|
if (loader != null) loader.setVisibility(View.GONE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.e("SC:expand", e.toString());
|
||||||
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean json_bool(JSONObject o, String key) throws JSONException
|
private static boolean json_bool(JSONObject o, String key) throws JSONException
|
||||||
{
|
{
|
||||||
Object v = o.get(key);
|
Object v = o.get(key);
|
||||||
|
@@ -4,6 +4,8 @@ import android.util.Log;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple4;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple5;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.CMessageList;
|
import com.blackforestbytes.simplecloudnotifier.model.CMessageList;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.PriorityEnum;
|
import com.blackforestbytes.simplecloudnotifier.model.PriorityEnum;
|
||||||
@@ -38,8 +40,16 @@ public class FBMService extends FirebaseMessagingService
|
|||||||
String content = remoteMessage.getData().get("body");
|
String content = remoteMessage.getData().get("body");
|
||||||
PriorityEnum prio = PriorityEnum.parseAPI(remoteMessage.getData().get("priority"));
|
PriorityEnum prio = PriorityEnum.parseAPI(remoteMessage.getData().get("priority"));
|
||||||
long scn_id = Long.parseLong(remoteMessage.getData().get("scn_msg_id"));
|
long scn_id = Long.parseLong(remoteMessage.getData().get("scn_msg_id"));
|
||||||
|
boolean trimmed = Boolean.parseBoolean(remoteMessage.getData().get("trimmed"));
|
||||||
|
|
||||||
recieveData(time, title, content, prio, scn_id, false);
|
if (trimmed)
|
||||||
|
{
|
||||||
|
ServerCommunication.expand(SCNSettings.inst().user_id, SCNSettings.inst().user_key, scn_id, null, (i1, i2, i3, i4, i5) -> recieveData(i4, i1, i2, i3, i5, false));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recieveData(time, title, content, prio, scn_id, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -50,15 +60,15 @@ public class FBMService extends FirebaseMessagingService
|
|||||||
|
|
||||||
public static void recieveData(long time, String title, String content, PriorityEnum prio, long scn_id, boolean alwaysAck)
|
public static void recieveData(long time, String title, String content, PriorityEnum prio, long scn_id, boolean alwaysAck)
|
||||||
{
|
{
|
||||||
CMessage msg = CMessageList.inst().add(scn_id, time, title, content, prio);
|
|
||||||
|
|
||||||
if (CMessageList.inst().isAck(scn_id))
|
if (CMessageList.inst().isAck(scn_id))
|
||||||
{
|
{
|
||||||
Log.w("FB::MessageReceived", "Recieved ack-ed message: " + scn_id);
|
Log.w("FB::MessageReceived", "Recieved ack-ed message: " + scn_id);
|
||||||
if (alwaysAck) ServerCommunication.ack(SCNSettings.inst().user_id, SCNSettings.inst().user_key, msg);
|
if (alwaysAck) ServerCommunication.ack(SCNSettings.inst().user_id, SCNSettings.inst().user_key, scn_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CMessage msg = CMessageList.inst().add(scn_id, time, title, content, prio);
|
||||||
|
|
||||||
if (SCNApp.isBackground())
|
if (SCNApp.isBackground())
|
||||||
{
|
{
|
||||||
NotificationService.inst().showBackground(msg);
|
NotificationService.inst().showBackground(msg);
|
||||||
@@ -68,6 +78,6 @@ public class FBMService extends FirebaseMessagingService
|
|||||||
NotificationService.inst().showForeground(msg);
|
NotificationService.inst().showForeground(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerCommunication.ack(SCNSettings.inst().user_id, SCNSettings.inst().user_key, msg);
|
ServerCommunication.ack(SCNSettings.inst().user_id, SCNSettings.inst().user_key, scn_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -6,6 +6,7 @@ import android.app.NotificationManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -165,12 +166,15 @@ public class NotificationService
|
|||||||
private void showBackground_old(CMessage msg, Context ctxt, NotificationSettings ns, PriorityEnum prio)
|
private void showBackground_old(CMessage msg, Context ctxt, NotificationSettings ns, PriorityEnum prio)
|
||||||
{
|
{
|
||||||
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctxt, getChannel(prio));
|
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctxt, getChannel(prio));
|
||||||
mBuilder.setSmallIcon(R.drawable.ic_bfb);
|
mBuilder.setSmallIcon(R.drawable.ic_notification_white);
|
||||||
|
mBuilder.setLargeIcon(BitmapFactory.decodeResource(ctxt.getResources(), R.mipmap.ic_notification_full));
|
||||||
mBuilder.setContentTitle(msg.Title);
|
mBuilder.setContentTitle(msg.Title);
|
||||||
mBuilder.setContentText(msg.Content);
|
mBuilder.setContentText(msg.Content);
|
||||||
mBuilder.setShowWhen(true);
|
mBuilder.setShowWhen(true);
|
||||||
mBuilder.setWhen(msg.Timestamp * 1000);
|
mBuilder.setWhen(msg.Timestamp * 1000);
|
||||||
mBuilder.setAutoCancel(true);
|
mBuilder.setAutoCancel(true);
|
||||||
|
mBuilder.setCategory(Notification.CATEGORY_MESSAGE);
|
||||||
|
mBuilder.setGroup("com.blackforestbytes.simplecloudnotifier.notifications.group."+prio.toString());
|
||||||
|
|
||||||
if (msg.Priority == PriorityEnum.LOW) mBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
|
if (msg.Priority == PriorityEnum.LOW) mBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
|
||||||
if (msg.Priority == PriorityEnum.NORMAL) mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
if (msg.Priority == PriorityEnum.NORMAL) mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
||||||
@@ -198,19 +202,22 @@ public class NotificationService
|
|||||||
|
|
||||||
Notification n = mBuilder.build();
|
Notification n = mBuilder.build();
|
||||||
|
|
||||||
if (mNotificationManager != null) mNotificationManager.notify(0, n);
|
if (mNotificationManager != null) mNotificationManager.notify((int)msg.SCN_ID, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
private void showBackground_new(CMessage msg, Context ctxt, NotificationSettings ns, PriorityEnum prio)
|
private void showBackground_new(CMessage msg, Context ctxt, NotificationSettings ns, PriorityEnum prio)
|
||||||
{
|
{
|
||||||
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctxt, getChannel(prio));
|
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctxt, getChannel(prio));
|
||||||
mBuilder.setSmallIcon(R.drawable.ic_bfb);
|
mBuilder.setSmallIcon(R.drawable.ic_notification_white);
|
||||||
|
mBuilder.setLargeIcon(BitmapFactory.decodeResource(ctxt.getResources(), R.mipmap.ic_notification_full));
|
||||||
mBuilder.setContentTitle(msg.Title);
|
mBuilder.setContentTitle(msg.Title);
|
||||||
mBuilder.setContentText(msg.Content);
|
mBuilder.setContentText(msg.Content);
|
||||||
mBuilder.setShowWhen(true);
|
mBuilder.setShowWhen(true);
|
||||||
mBuilder.setWhen(msg.Timestamp * 1000);
|
mBuilder.setWhen(msg.Timestamp * 1000);
|
||||||
mBuilder.setAutoCancel(true);
|
mBuilder.setAutoCancel(true);
|
||||||
|
mBuilder.setCategory(Notification.CATEGORY_MESSAGE);
|
||||||
|
mBuilder.setGroup("com.blackforestbytes.simplecloudnotifier.notifications.group."+prio.toString());
|
||||||
|
|
||||||
if (ns.EnableLED) mBuilder.setLights(ns.LEDColor, 500, 500);
|
if (ns.EnableLED) mBuilder.setLights(ns.LEDColor, 500, 500);
|
||||||
|
|
||||||
@@ -242,7 +249,7 @@ public class NotificationService
|
|||||||
Notification n = mBuilder.build();
|
Notification n = mBuilder.build();
|
||||||
n.flags |= Notification.FLAG_AUTO_CANCEL;
|
n.flags |= Notification.FLAG_AUTO_CANCEL;
|
||||||
|
|
||||||
mNotificationManager.notify(0, n);
|
mNotificationManager.notify((int)msg.SCN_ID, n);
|
||||||
|
|
||||||
if (ns.EnableVibration)
|
if (ns.EnableVibration)
|
||||||
{
|
{
|
||||||
|
@@ -3,6 +3,7 @@ package com.blackforestbytes.simplecloudnotifier.util;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||||
import com.blackforestbytes.simplecloudnotifier.view.MessageAdapter;
|
import com.blackforestbytes.simplecloudnotifier.view.MessageAdapter;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -13,10 +14,21 @@ public class MessageAdapterTouchHelper extends ItemTouchHelper.SimpleCallback
|
|||||||
{
|
{
|
||||||
private MessageAdapterTouchHelperListener listener;
|
private MessageAdapterTouchHelperListener listener;
|
||||||
|
|
||||||
|
private int dir = 0;
|
||||||
|
|
||||||
public MessageAdapterTouchHelper(int dragDirs, int swipeDirs, MessageAdapterTouchHelperListener listener)
|
public MessageAdapterTouchHelper(int dragDirs, int swipeDirs, MessageAdapterTouchHelperListener listener)
|
||||||
{
|
{
|
||||||
super(dragDirs, swipeDirs);
|
super(dragDirs, swipeDirs);
|
||||||
|
this.dir = swipeDirs;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
updateEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateEnabled()
|
||||||
|
{
|
||||||
|
int sdir = SCNSettings.inst().EnableDeleteSwipe ? ItemTouchHelper.LEFT : 0;
|
||||||
|
if (dir == sdir) return;
|
||||||
|
setDefaultSwipeDirs(dir = sdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -6,12 +6,14 @@ import android.content.ClipData;
|
|||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
@@ -91,7 +93,7 @@ public class AccountFragment extends Fragment
|
|||||||
|
|
||||||
builder.setPositiveButton("YES", (dialog, which) -> {
|
builder.setPositiveButton("YES", (dialog, which) -> {
|
||||||
CMessageList.inst().clear();
|
CMessageList.inst().clear();
|
||||||
SCNApp.showToast("Notifications cleared", 1000);
|
SCNApp.showToast("Messages cleared", 1000);
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -103,7 +105,7 @@ public class AccountFragment extends Fragment
|
|||||||
|
|
||||||
v.findViewById(R.id.btnQR).setOnClickListener(cv ->
|
v.findViewById(R.id.btnQR).setOnClickListener(cv ->
|
||||||
{
|
{
|
||||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(SCNSettings.inst().createOnlineURL()));
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(SCNSettings.inst().createOnlineURL(true)));
|
||||||
startActivity(browserIntent);
|
startActivity(browserIntent);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -126,10 +128,11 @@ public class AccountFragment extends Fragment
|
|||||||
public void updateUI(View v)
|
public void updateUI(View v)
|
||||||
{
|
{
|
||||||
if (v == null) return;
|
if (v == null) return;
|
||||||
TextView tvUserID = v.findViewById(R.id.tvUserID);
|
TextView tvUserID = v.findViewById(R.id.tvUserID);
|
||||||
TextView tvUserKey = v.findViewById(R.id.tvUserKey);
|
TextView tvUserKey = v.findViewById(R.id.tvUserKey);
|
||||||
TextView tvQuota = v.findViewById(R.id.tvQuota);
|
TextView tvQuota = v.findViewById(R.id.tvQuota);
|
||||||
ImageButton btnQR = v.findViewById(R.id.btnQR);
|
ImageView ivQuota = v.findViewById(R.id.ic_img_quota);
|
||||||
|
ImageButton btnQR = v.findViewById(R.id.btnQR);
|
||||||
|
|
||||||
SCNSettings s = SCNSettings.inst();
|
SCNSettings s = SCNSettings.inst();
|
||||||
|
|
||||||
@@ -138,7 +141,8 @@ public class AccountFragment extends Fragment
|
|||||||
tvUserID.setText(String.valueOf(s.user_id));
|
tvUserID.setText(String.valueOf(s.user_id));
|
||||||
tvUserKey.setText(s.user_key);
|
tvUserKey.setText(s.user_key);
|
||||||
tvQuota.setText(String.format("%d / %d", s.quota_curr, s.quota_max));
|
tvQuota.setText(String.format("%d / %d", s.quota_curr, s.quota_max));
|
||||||
btnQR.setImageBitmap(QRCode.from(s.createOnlineURL()).to(ImageType.PNG).withSize(512, 512).bitmap());
|
btnQR.setImageBitmap(QRCode.from(s.createOnlineURL(false)).to(ImageType.PNG).withSize(512, 512).bitmap());
|
||||||
|
ivQuota.setColorFilter(s.quota_curr>=s.quota_max ? Color.rgb(200, 0, 0) : Color.rgb(128, 128, 128));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -146,6 +150,7 @@ public class AccountFragment extends Fragment
|
|||||||
tvUserKey.setText(R.string.str_not_connected);
|
tvUserKey.setText(R.string.str_not_connected);
|
||||||
tvQuota.setText(R.string.str_not_connected);
|
tvQuota.setText(R.string.str_not_connected);
|
||||||
btnQR.setImageResource(R.drawable.qr_default);
|
btnQR.setImageResource(R.drawable.qr_default);
|
||||||
|
ivQuota.setColorFilter(0x80_80_80);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package com.blackforestbytes.simplecloudnotifier.view;
|
package com.blackforestbytes.simplecloudnotifier.view;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -57,7 +58,6 @@ public class MessageAdapter extends RecyclerView.Adapter
|
|||||||
viewHolders.put(view, true);
|
viewHolders.put(view, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder)
|
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder)
|
||||||
{
|
{
|
||||||
@@ -87,16 +87,17 @@ public class MessageAdapter extends RecyclerView.Adapter
|
|||||||
manLayout.smoothScrollToPosition(viewRecycler, null, 0);
|
manLayout.smoothScrollToPosition(viewRecycler, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeItem(int position)
|
public CMessage removeItem(int position)
|
||||||
{
|
{
|
||||||
CMessageList.inst().remove(position);
|
CMessage i = CMessageList.inst().removeFromBack(position);
|
||||||
notifyItemRemoved(position);
|
notifyDataSetChanged();
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restoreItem(CMessage item, int position)
|
public void restoreItem(CMessage item, int position)
|
||||||
{
|
{
|
||||||
CMessageList.inst().insert(position, item);
|
CMessageList.inst().insert(position, item);
|
||||||
notifyItemInserted(position);
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MessagePresenter extends RecyclerView.ViewHolder implements View.OnClickListener
|
public class MessagePresenter extends RecyclerView.ViewHolder implements View.OnClickListener
|
||||||
@@ -140,13 +141,16 @@ public class MessageAdapter extends RecyclerView.Adapter
|
|||||||
case LOW:
|
case LOW:
|
||||||
ivPriority.setVisibility(View.VISIBLE);
|
ivPriority.setVisibility(View.VISIBLE);
|
||||||
ivPriority.setImageResource(R.drawable.priority_low);
|
ivPriority.setImageResource(R.drawable.priority_low);
|
||||||
|
ivPriority.setColorFilter(Color.rgb(176, 176, 176));
|
||||||
break;
|
break;
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
ivPriority.setVisibility(View.GONE);
|
ivPriority.setVisibility(View.GONE);
|
||||||
|
ivPriority.setColorFilter(Color.rgb(176, 176, 176));
|
||||||
break;
|
break;
|
||||||
case HIGH:
|
case HIGH:
|
||||||
ivPriority.setVisibility(View.VISIBLE);
|
ivPriority.setVisibility(View.VISIBLE);
|
||||||
ivPriority.setImageResource(R.drawable.priority_high);
|
ivPriority.setImageResource(R.drawable.priority_high);
|
||||||
|
ivPriority.setColorFilter(Color.rgb(200, 0, 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,6 @@ import android.view.ViewGroup;
|
|||||||
import com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.CMessageList;
|
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||||
import com.blackforestbytes.simplecloudnotifier.service.IABService;
|
import com.blackforestbytes.simplecloudnotifier.service.IABService;
|
||||||
import com.blackforestbytes.simplecloudnotifier.util.MessageAdapterTouchHelper;
|
import com.blackforestbytes.simplecloudnotifier.util.MessageAdapterTouchHelper;
|
||||||
@@ -28,6 +27,8 @@ public class NotificationsFragment extends Fragment implements MessageAdapterTou
|
|||||||
private PublisherAdView adView;
|
private PublisherAdView adView;
|
||||||
private MessageAdapter adpMessages;
|
private MessageAdapter adpMessages;
|
||||||
|
|
||||||
|
public MessageAdapterTouchHelper touchHelper;
|
||||||
|
|
||||||
public NotificationsFragment()
|
public NotificationsFragment()
|
||||||
{
|
{
|
||||||
// Required empty public constructor
|
// Required empty public constructor
|
||||||
@@ -43,7 +44,7 @@ public class NotificationsFragment extends Fragment implements MessageAdapterTou
|
|||||||
rvMessages.setLayoutManager(lman);
|
rvMessages.setLayoutManager(lman);
|
||||||
rvMessages.setAdapter(adpMessages = new MessageAdapter(v.findViewById(R.id.tvNoElements), lman, rvMessages));
|
rvMessages.setAdapter(adpMessages = new MessageAdapter(v.findViewById(R.id.tvNoElements), lman, rvMessages));
|
||||||
|
|
||||||
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new MessageAdapterTouchHelper(0, ItemTouchHelper.LEFT, this);
|
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = touchHelper = new MessageAdapterTouchHelper(0, ItemTouchHelper.LEFT, this);
|
||||||
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(rvMessages);
|
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(rvMessages);
|
||||||
|
|
||||||
adView = v.findViewById(R.id.adBanner);
|
adView = v.findViewById(R.id.adBanner);
|
||||||
@@ -65,13 +66,11 @@ public class NotificationsFragment extends Fragment implements MessageAdapterTou
|
|||||||
{
|
{
|
||||||
if (viewHolder instanceof MessageAdapter.MessagePresenter)
|
if (viewHolder instanceof MessageAdapter.MessagePresenter)
|
||||||
{
|
{
|
||||||
final CMessage deletedItem = CMessageList.inst().tryGet(viewHolder.getAdapterPosition());
|
|
||||||
final int deletedIndex = viewHolder.getAdapterPosition();
|
final int deletedIndex = viewHolder.getAdapterPosition();
|
||||||
|
|
||||||
|
final CMessage deletedItem = adpMessages.removeItem(viewHolder.getAdapterPosition());
|
||||||
String name = deletedItem.Title;
|
String name = deletedItem.Title;
|
||||||
|
|
||||||
adpMessages.removeItem(viewHolder.getAdapterPosition());
|
|
||||||
|
|
||||||
Snackbar snackbar = Snackbar.make(SCNApp.getMainActivity().layoutRoot, name + " removed", Snackbar.LENGTH_LONG);
|
Snackbar snackbar = Snackbar.make(SCNApp.getMainActivity().layoutRoot, name + " removed", Snackbar.LENGTH_LONG);
|
||||||
snackbar.setAction("UNDO", view -> adpMessages.restoreItem(deletedItem, deletedIndex));
|
snackbar.setAction("UNDO", view -> adpMessages.restoreItem(deletedItem, deletedIndex));
|
||||||
snackbar.setActionTextColor(Color.YELLOW);
|
snackbar.setActionTextColor(Color.YELLOW);
|
||||||
|
@@ -22,6 +22,7 @@ import android.widget.SeekBar;
|
|||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.android.billingclient.api.Purchase;
|
import com.android.billingclient.api.Purchase;
|
||||||
import com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
@@ -49,6 +50,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
private Button prefUpgradeAccount;
|
private Button prefUpgradeAccount;
|
||||||
private TextView prefUpgradeAccount_msg;
|
private TextView prefUpgradeAccount_msg;
|
||||||
private TextView prefUpgradeAccount_info;
|
private TextView prefUpgradeAccount_info;
|
||||||
|
private Switch prefEnableDeleteSwipe;
|
||||||
|
|
||||||
private Switch prefMsgLowEnableSound;
|
private Switch prefMsgLowEnableSound;
|
||||||
private TextView prefMsgLowRingtone_value;
|
private TextView prefMsgLowRingtone_value;
|
||||||
@@ -114,6 +116,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefUpgradeAccount = v.findViewById(R.id.prefUpgradeAccount);
|
prefUpgradeAccount = v.findViewById(R.id.prefUpgradeAccount);
|
||||||
prefUpgradeAccount_msg = v.findViewById(R.id.prefUpgradeAccount2);
|
prefUpgradeAccount_msg = v.findViewById(R.id.prefUpgradeAccount2);
|
||||||
prefUpgradeAccount_info = v.findViewById(R.id.prefUpgradeAccount_info);
|
prefUpgradeAccount_info = v.findViewById(R.id.prefUpgradeAccount_info);
|
||||||
|
prefEnableDeleteSwipe = v.findViewById(R.id.prefEnableDeleteSwipe);
|
||||||
|
|
||||||
prefMsgLowEnableSound = v.findViewById(R.id.prefMsgLowEnableSound);
|
prefMsgLowEnableSound = v.findViewById(R.id.prefMsgLowEnableSound);
|
||||||
prefMsgLowRingtone_value = v.findViewById(R.id.prefMsgLowRingtone_value);
|
prefMsgLowRingtone_value = v.findViewById(R.id.prefMsgLowRingtone_value);
|
||||||
@@ -159,6 +162,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
if (c == null) return;
|
if (c == null) return;
|
||||||
|
|
||||||
if (prefAppEnabled.isChecked() != s.Enabled) prefAppEnabled.setChecked(s.Enabled);
|
if (prefAppEnabled.isChecked() != s.Enabled) prefAppEnabled.setChecked(s.Enabled);
|
||||||
|
if (prefEnableDeleteSwipe.isChecked() != s.EnableDeleteSwipe) prefEnableDeleteSwipe.setChecked(s.EnableDeleteSwipe);
|
||||||
|
|
||||||
prefUpgradeAccount.setVisibility( SCNSettings.inst().promode_local ? View.GONE : View.VISIBLE);
|
prefUpgradeAccount.setVisibility( SCNSettings.inst().promode_local ? View.GONE : View.VISIBLE);
|
||||||
prefUpgradeAccount_info.setVisibility(SCNSettings.inst().promode_local ? View.GONE : View.VISIBLE);
|
prefUpgradeAccount_info.setVisibility(SCNSettings.inst().promode_local ? View.GONE : View.VISIBLE);
|
||||||
@@ -213,7 +217,8 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
{
|
{
|
||||||
SCNSettings s = SCNSettings.inst();
|
SCNSettings s = SCNSettings.inst();
|
||||||
|
|
||||||
prefAppEnabled.setOnCheckedChangeListener((a,b) -> { s.Enabled=b; saveAndUpdate(); });
|
prefAppEnabled.setOnCheckedChangeListener((a,b) -> { boolean prev=s.Enabled; s.Enabled=b; saveAndUpdate(); updateEnabled(prev, b); });
|
||||||
|
prefEnableDeleteSwipe.setOnCheckedChangeListener((a,b) -> { s.EnableDeleteSwipe=b; saveAndUpdate(); });
|
||||||
|
|
||||||
prefLocalCacheSize.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
|
prefLocalCacheSize.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
|
||||||
{
|
{
|
||||||
@@ -257,6 +262,18 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefMsgHighVolumeTest.setOnClickListener((v) -> { if (s.PriorityHigh.ForceVolume) playTestSound(2, prefMsgHighVolumeTest, s.PriorityHigh.SoundSource, s.PriorityHigh.ForceVolumeValue); });
|
prefMsgHighVolumeTest.setOnClickListener((v) -> { if (s.PriorityHigh.ForceVolume) playTestSound(2, prefMsgHighVolumeTest, s.PriorityHigh.SoundSource, s.PriorityHigh.ForceVolumeValue); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateEnabled(boolean prev, boolean now)
|
||||||
|
{
|
||||||
|
if (!prev && now)
|
||||||
|
{
|
||||||
|
SCNApp.showToast("SimpleCloudNotifier is now enabled", Toast.LENGTH_SHORT);
|
||||||
|
}
|
||||||
|
else if (prev && !now)
|
||||||
|
{
|
||||||
|
SCNApp.showToast("SimpleCloudNotifier is now disabled\nYou won't recieve new messages.", Toast.LENGTH_LONG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateVolume(int idx, int volume)
|
private void updateVolume(int idx, int volume)
|
||||||
{
|
{
|
||||||
if (mPlayers[idx] != null && mPlayers[idx].isPlaying())
|
if (mPlayers[idx] != null && mPlayers[idx].isPlaying())
|
||||||
@@ -324,6 +341,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
{
|
{
|
||||||
SCNSettings.inst().save();
|
SCNSettings.inst().save();
|
||||||
updateUI();
|
updateUI();
|
||||||
|
SCNApp.getMainActivity().adpTabs.tab1.touchHelper.updateEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUpgradeAccount()
|
private void onUpgradeAccount()
|
||||||
|
@@ -35,7 +35,7 @@ public class TabAdapter extends FragmentStatePagerAdapter {
|
|||||||
{
|
{
|
||||||
switch (position)
|
switch (position)
|
||||||
{
|
{
|
||||||
case 0: return "Notifications";
|
case 0: return "Messages";
|
||||||
case 1: return "Account";
|
case 1: return "Account";
|
||||||
case 2: return "Settings";
|
case 2: return "Settings";
|
||||||
default: return null;
|
default: return null;
|
||||||
|
BIN
android/app/src/main/res/drawable-hdpi/ic_notification_white.png
Normal file
After Width: | Height: | Size: 472 B |
BIN
android/app/src/main/res/drawable-mdpi/ic_notification_white.png
Normal file
After Width: | Height: | Size: 320 B |
After Width: | Height: | Size: 551 B |
After Width: | Height: | Size: 949 B |
After Width: | Height: | Size: 1.0 KiB |
@@ -1,15 +0,0 @@
|
|||||||
<vector android:height="24dp" android:viewportHeight="1000"
|
|
||||||
android:viewportWidth="1000" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FF000000"
|
|
||||||
android:pathData="M500,500m-500,0a500,500 0,1 1,1000 0a500,500 0,1 1,-1000 0"
|
|
||||||
android:strokeColor="#000000" android:strokeWidth="1"/>
|
|
||||||
<path android:fillColor="#ffffff" android:pathData="M300,694L700,694L500,136L300,694"/>
|
|
||||||
<path android:fillColor="#ffffff" android:pathData="M473,559L527,559L527,774L473,774"/>
|
|
||||||
<path android:fillColor="#000000" android:pathData="M376,640L624,640L500,295L376,640"/>
|
|
||||||
<path android:fillColor="#ffffff" android:pathData="M100,730L500,730L300,172L100,730"/>
|
|
||||||
<path android:fillColor="#000000" android:pathData="M176,676L424,676L300,331L176,676"/>
|
|
||||||
<path android:fillColor="#ffffff" android:pathData="M273,595L327,595L327,810L273,810"/>
|
|
||||||
<path android:fillColor="#ffffff" android:pathData="M500,730L900,730L700,172L500,730"/>
|
|
||||||
<path android:fillColor="#000000" android:pathData="M576,676L824,676L700,331L576,676"/>
|
|
||||||
<path android:fillColor="#ffffff" android:pathData="M673,595L727,595L727,810L673,810"/>
|
|
||||||
</vector>
|
|
@@ -79,6 +79,22 @@
|
|||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:id="@+id/prefEnableDeleteSwipe"
|
||||||
|
android:text="@string/str_deleteswipe"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_notification_full.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_notification_full.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_notification_full.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_notification_full.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_notification_full.png
Normal file
After Width: | Height: | Size: 17 KiB |
@@ -11,13 +11,13 @@
|
|||||||
<string name="ic_img_fuel_desc">Icon Fuel</string>
|
<string name="ic_img_fuel_desc">Icon Fuel</string>
|
||||||
<string name="str_qr_code">QR Code</string>
|
<string name="str_qr_code">QR Code</string>
|
||||||
<string name="str_reset_account">Reset Account</string>
|
<string name="str_reset_account">Reset Account</string>
|
||||||
<string name="no_notifications">No notifications</string>
|
<string name="no_notifications">No messages</string>
|
||||||
<string name="str_not_connected">not connected</string>
|
<string name="str_not_connected">not connected</string>
|
||||||
<string name="str_reload">reload</string>
|
<string name="str_reload">reload</string>
|
||||||
<string name="desc_priority_icon">Priority icon</string>
|
<string name="desc_priority_icon">Priority icon</string>
|
||||||
<string name="str_common_settings">Common Settings</string>
|
<string name="str_common_settings">Common Settings</string>
|
||||||
<string name="str_enabled">Enabled</string>
|
<string name="str_enabled">Enabled</string>
|
||||||
<string name="str_localcachesize">Remember the last x notifications locally</string>
|
<string name="str_localcachesize">Remember the last x messages locally</string>
|
||||||
<string name="str_header_prio0">Notifications (priority 0 - Low)</string>
|
<string name="str_header_prio0">Notifications (priority 0 - Low)</string>
|
||||||
<string name="str_header_prio1">Notifications (priority 1 - Normal)</string>
|
<string name="str_header_prio1">Notifications (priority 1 - Normal)</string>
|
||||||
<string name="str_header_prio2">Notifications (priority 2 - High)</string>
|
<string name="str_header_prio2">Notifications (priority 2 - High)</string>
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
<string name="str_ledcolor">Notification light color</string>
|
<string name="str_ledcolor">Notification light color</string>
|
||||||
<string name="str_enable_vibration">Enable notification vibration</string>
|
<string name="str_enable_vibration">Enable notification vibration</string>
|
||||||
<string name="str_upgrade_account">Upgrade account</string>
|
<string name="str_upgrade_account">Upgrade account</string>
|
||||||
|
<string name="str_deleteswipe">Delete messages by swiping left</string>
|
||||||
<string name="str_promode">Thank you for supporting the app and using the pro mode</string>
|
<string name="str_promode">Thank you for supporting the app and using the pro mode</string>
|
||||||
<string name="str_promode_info">Increase your daily quota, remove the ad banner and support the developer (that\'s me)</string>
|
<string name="str_promode_info">Increase your daily quota, remove the ad banner and support the developer (that\'s me)</string>
|
||||||
<string name="volume_icon">Volume icon</string>
|
<string name="volume_icon">Volume icon</string>
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
#Mon Nov 12 18:26:41 CET 2018
|
#Sun Nov 18 00:14:54 CET 2018
|
||||||
VERSION_NAME=0.0.7
|
VERSION_NAME=0.0.12
|
||||||
VERSION_CODE=7
|
VERSION_CODE=12
|
||||||
|
BIN
data/icon_512_nobox.png
Normal file
After Width: | Height: | Size: 237 KiB |
BIN
data/icon_512_transparent.png
Normal file
After Width: | Height: | Size: 18 KiB |
77
examples/scn_send.sh
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Call with `scn_send title`
|
||||||
|
# or `scn_send title content`
|
||||||
|
# or `scn_send title content priority`
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ "$#" -lt 1 ]; then
|
||||||
|
echo "no title supplied via parameter"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# INSERT YOUR DATA HERE #
|
||||||
|
################################################################################
|
||||||
|
user_id=999
|
||||||
|
user_key="????????????????????????????????????????????????????????????????"
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
title=$1
|
||||||
|
content=""
|
||||||
|
|
||||||
|
if [ "$#" -gt 1 ]; then
|
||||||
|
content=$2
|
||||||
|
fi
|
||||||
|
|
||||||
|
priority=1
|
||||||
|
|
||||||
|
if [ "$#" -gt 2 ]; then
|
||||||
|
priority=$3
|
||||||
|
fi
|
||||||
|
|
||||||
|
usr_msg_id=$(uuidgen)
|
||||||
|
|
||||||
|
while true ; do
|
||||||
|
|
||||||
|
curlresp=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-d "user_id=$user_id" -d "user_key=$user_key" -d "title=$title" \
|
||||||
|
-d "content=$content" -d "priority=$priority" -d "msg_id=$usr_msg_id" \
|
||||||
|
https://scn.blackforestbytes.com/send.php)
|
||||||
|
|
||||||
|
if [ "$curlresp" == 200 ] ; then
|
||||||
|
echo "Successfully send"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$curlresp" == 400 ] ; then
|
||||||
|
echo "Bad request - something went wrong"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$curlresp" == 401 ] ; then
|
||||||
|
echo "Unauthorized - wrong userid/userkey"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$curlresp" == 403 ] ; then
|
||||||
|
echo "Quota exceeded - wait one hour before re-try"
|
||||||
|
sleep 3600
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$curlresp" == 412 ] ; then
|
||||||
|
echo "Precondition Failed - No device linked"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$curlresp" == 500 ] ; then
|
||||||
|
echo "Internal server error - waiting for better times"
|
||||||
|
sleep 60
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if none of the above matched we probably hav no network ...
|
||||||
|
echo "Send failed (response code $curlresp) ... try again in 5s"
|
||||||
|
sleep 5
|
||||||
|
done
|
BIN
store/screenshot_1.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
store/screenshot_2.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
store/screenshot_3.png
Normal file
After Width: | Height: | Size: 55 KiB |
56
web/api/__config_example.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// insert your values here and rename to config.php
|
||||||
|
|
||||||
|
return
|
||||||
|
[
|
||||||
|
'global' =>
|
||||||
|
[
|
||||||
|
'prod' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'database' =>
|
||||||
|
[
|
||||||
|
'host' => '?',
|
||||||
|
'database' => '?',
|
||||||
|
'user' => '?',
|
||||||
|
'password' => '?',
|
||||||
|
],
|
||||||
|
|
||||||
|
'firebase' =>
|
||||||
|
[
|
||||||
|
'type' => 'service_account',
|
||||||
|
'project_id' => '?',
|
||||||
|
'private_key_id' => '???',
|
||||||
|
'client_email' => '???.iam.gserviceaccount.com',
|
||||||
|
'client_id' => '???',
|
||||||
|
'auth_uri' => 'https://accounts.google.com/o/oauth2/auth',
|
||||||
|
'token_uri' => 'https://oauth2.googleapis.com/token',
|
||||||
|
'auth_provider_x509_cert_url' => 'https://www.googleapis.com/oauth2/v1/certs',
|
||||||
|
'client_x509_cert_url' => 'https://www.googleapis.com/robot/v1/metadata/x509/???f.iam.gserviceaccount.com',
|
||||||
|
'private_key' => "-----BEGIN PRIVATE KEY-----\n"
|
||||||
|
. "??????????\n"
|
||||||
|
. "-----END PRIVATE KEY-----\n",
|
||||||
|
'server_key' => '????',
|
||||||
|
],
|
||||||
|
|
||||||
|
'verify_api' =>
|
||||||
|
[
|
||||||
|
'package_name' => 'com.blackforestbytes.simplecloudnotifier',
|
||||||
|
'product_id' => '???',
|
||||||
|
|
||||||
|
'clientid' => '???.apps.googleusercontent.com',
|
||||||
|
'clientsecret' => '???',
|
||||||
|
'accesstoken' => file_exists('.verify_accesstoken') ? file_get_contents('.verify_accesstoken') : '',
|
||||||
|
'refreshtoken' => '???',
|
||||||
|
'scope' => 'https://www.googleapis.com/auth/androidpublisher',
|
||||||
|
],
|
||||||
|
|
||||||
|
'error_reporting' =>
|
||||||
|
[
|
||||||
|
'send-mail' => true,
|
||||||
|
'email-error-target' => '???@???.com',
|
||||||
|
'email-error-sender' => '???@???.com',
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
53
web/api/expand.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
include_once 'model.php';
|
||||||
|
|
||||||
|
$INPUT = array_merge($_GET, $_POST);
|
||||||
|
|
||||||
|
|
||||||
|
if (!isset($INPUT['user_id'])) die(json_encode(['success' => false, 'errid'=>101, 'message' => 'Missing parameter [[user_id]]']));
|
||||||
|
if (!isset($INPUT['user_key'])) die(json_encode(['success' => false, 'errid'=>102, 'message' => 'Missing parameter [[user_key]]']));
|
||||||
|
if (!isset($INPUT['scn_msg_id'])) die(json_encode(['success' => false, 'errid'=>103, 'message' => 'Missing parameter [[scn_msg_id]]']));
|
||||||
|
|
||||||
|
$user_id = $INPUT['user_id'];
|
||||||
|
$user_key = $INPUT['user_key'];
|
||||||
|
$scn_msg_id = $INPUT['scn_msg_id'];
|
||||||
|
|
||||||
|
//----------------------
|
||||||
|
|
||||||
|
$pdo = getDatabase();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, is_pro, quota_day, fcm_token FROM users WHERE user_id = :uid LIMIT 1');
|
||||||
|
$stmt->execute(['uid' => $user_id]);
|
||||||
|
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (count($datas)<=0) die(json_encode(['success' => false, 'errid'=>201, 'message' => 'User not found']));
|
||||||
|
$data = $datas[0];
|
||||||
|
|
||||||
|
if ($data === null) die(json_encode(['success' => false, 'errid'=>202, 'message' => 'User not found']));
|
||||||
|
if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'errid'=>203, 'message' => 'UserID not found']));
|
||||||
|
if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'errid'=>204, 'message' => 'Authentification failed']));
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT * FROM messages WHERE scn_message_id=:smid AND sender_user_id=:uid LIMIT 1');
|
||||||
|
$stmt->execute(['smid' => $scn_msg_id, 'uid' => $user_id]);
|
||||||
|
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (count($datas)<=0) die(json_encode(['success' => false, 'errid'=>301, 'message' => 'Message not found']));
|
||||||
|
|
||||||
|
$msg = $datas[0];
|
||||||
|
|
||||||
|
api_return(200,
|
||||||
|
[
|
||||||
|
'success' => true,
|
||||||
|
'data' =>
|
||||||
|
[
|
||||||
|
'title' => $msg['title'],
|
||||||
|
'body' => $msg['content'],
|
||||||
|
'trimmed' => false,
|
||||||
|
'priority' => $msg['priority'],
|
||||||
|
'timestamp' => strtotime($msg['timestamp']),
|
||||||
|
'usr_msg_id' => $msg['usr_message_id'],
|
||||||
|
'scn_msg_id' => $msg['scn_message_id'],
|
||||||
|
],
|
||||||
|
'message' => 'ok'
|
||||||
|
]);
|
@@ -30,7 +30,7 @@ if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'errid
|
|||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT COUNT(*) FROM messages WHERE ack=0 AND sender_user_id=:uid');
|
$stmt = $pdo->prepare('SELECT COUNT(*) FROM messages WHERE ack=0 AND sender_user_id=:uid');
|
||||||
$stmt->execute(['uid' => $user_id]);
|
$stmt->execute(['uid' => $user_id]);
|
||||||
$nack_count = $stmt->fetch(PDO::FETCH_NUM);
|
$nack_count = $stmt->fetch(PDO::FETCH_NUM)[0];
|
||||||
|
|
||||||
|
|
||||||
$quota = $data['quota_today'];
|
$quota = $data['quota_today'];
|
||||||
|
@@ -35,6 +35,14 @@ class Statics
|
|||||||
public static $CFG = NULL;
|
public static $CFG = NULL;
|
||||||
|
|
||||||
public static function quota_max($is_pro) { return $is_pro ? 1000 : 50; }
|
public static function quota_max($is_pro) { return $is_pro ? 1000 : 50; }
|
||||||
|
|
||||||
|
public static function contentlen_max($is_pro) { return $is_pro ? 16384 : 2048; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function str_limit($str, $len)
|
||||||
|
{
|
||||||
|
if (strlen($str)>$len) return substr($str, 0, $len-3)."...";
|
||||||
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getConfig()
|
function getConfig()
|
||||||
|
@@ -41,7 +41,7 @@ foreach ($nonacks_sql as $nack)
|
|||||||
'title' => $nack['title'],
|
'title' => $nack['title'],
|
||||||
'body' => $nack['content'],
|
'body' => $nack['content'],
|
||||||
'priority' => $nack['priority'],
|
'priority' => $nack['priority'],
|
||||||
'timestamp' => $nack['timestamp'],
|
'timestamp' => strtotime($nack['timestamp']),
|
||||||
'usr_msg_id' => $nack['usr_message_id'],
|
'usr_msg_id' => $nack['usr_message_id'],
|
||||||
'scn_msg_id' => $nack['scn_message_id'],
|
'scn_msg_id' => $nack['scn_message_id'],
|
||||||
];
|
];
|
||||||
|
@@ -187,6 +187,95 @@
|
|||||||
Be aware that the server only saves send messages for a short amount of time. Because of that you can only use this to prevent duplicates in a short time-frame, older messages with the same ID are probably already deleted and the message will be send again.
|
Be aware that the server only saves send messages for a short amount of time. Because of that you can only use this to prevent duplicates in a short time-frame, older messages with the same ID are probably already deleted and the message will be send again.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2>Bash script example</h2>
|
||||||
|
<div class="section">
|
||||||
|
<p>
|
||||||
|
Depending on your use case it can be useful to create a bash script that handles things like resending messages if you have connection problems or waiting if there is no quota left.<br/>
|
||||||
|
Here is an example how such a scrippt could look like, you can put it into <code>/usr/local/sbin</code> and call it with <code>scn_send "title" "content"</code>
|
||||||
|
</p>
|
||||||
|
<pre style="color:#000000;" class="yellow-code"><span style="color:#3f7f59; font-weight:bold;">#!/usr/bin/env bash</span>
|
||||||
|
|
||||||
|
<span style="color:#3f7f59; ">#</span>
|
||||||
|
<span style="color:#3f7f59; "># Call with `scn_send title`</span>
|
||||||
|
<span style="color:#3f7f59; "># or `scn_send title content`</span>
|
||||||
|
<span style="color:#3f7f59; "># or `scn_send title content priority`</span>
|
||||||
|
<span style="color:#3f7f59; ">#</span>
|
||||||
|
<span style="color:#3f7f59; ">#</span>
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"$#"</span> -lt 1 ]; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"no title supplied via parameter"</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">exit</span> 1
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
<span style="color:#3f7f59; ">################################################################################</span>
|
||||||
|
<span style="color:#3f7f59; "># INSERT YOUR DATA HERE #</span>
|
||||||
|
<span style="color:#3f7f59; ">################################################################################</span>
|
||||||
|
user_id=999
|
||||||
|
user_key=<span style="color:#2a00ff; ">"????????????????????????????????????????????????????????????????"</span>
|
||||||
|
<span style="color:#3f7f59; ">################################################################################</span>
|
||||||
|
|
||||||
|
title=$1
|
||||||
|
content=<span style="color:#2a00ff; ">""</span>
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"$#"</span> -gt 1 ]; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
content=$2
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
priority=1
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"$#"</span> -gt 2 ]; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
priority=$3
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
usr_msg_id=$(uuidgen)
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">while</span> true ; <span style="color:#7f0055; font-weight:bold; ">do</span>
|
||||||
|
|
||||||
|
curlresp=$(curl -s -o <span style="color:#3f3fbf; ">/dev/null</span> -w <span style="color:#2a00ff; ">"%{http_code}"</span> <span style="color:#2a00ff; ">\</span>
|
||||||
|
-d <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">user_id</span><span style="color:#2a00ff; ">=</span><span style="color:#2a00ff; ">$user_id</span><span style="color:#2a00ff; ">"</span> -d <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">user_key</span><span style="color:#2a00ff; ">=</span><span style="color:#2a00ff; ">$user_key</span><span style="color:#2a00ff; ">"</span> -d <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">title</span><span style="color:#2a00ff; ">=</span><span style="color:#2a00ff; ">$title</span><span style="color:#2a00ff; ">"</span> <span style="color:#2a00ff; ">\</span>
|
||||||
|
-d <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">content</span><span style="color:#2a00ff; ">=</span><span style="color:#2a00ff; ">$content</span><span style="color:#2a00ff; ">"</span> -d <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">priority</span><span style="color:#2a00ff; ">=</span><span style="color:#2a00ff; ">$priority</span><span style="color:#2a00ff; ">"</span> -d <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">msg_id</span><span style="color:#2a00ff; ">=</span><span style="color:#2a00ff; ">$usr_msg_id</span><span style="color:#2a00ff; ">"</span> <span style="color:#2a00ff; ">\</span>
|
||||||
|
https:<span style="color:#3f3fbf; ">/</span><span style="color:#3f3fbf; ">/scn.blackforestbytes.com/send.php</span>)
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">$curlresp</span><span style="color:#2a00ff; ">"</span> == 200 ] ; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"Successfully send"</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">exit</span> 0
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">$curlresp</span><span style="color:#2a00ff; ">"</span> == 400 ] ; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"Bad request - something went wrong"</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">exit</span> 1
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">$curlresp</span><span style="color:#2a00ff; ">"</span> == 401 ] ; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"Unauthorized - wrong </span><span style="color:#3f3fbf; ">userid/userkey</span><span style="color:#2a00ff; ">"</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">exit</span> 1
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">$curlresp</span><span style="color:#2a00ff; ">"</span> == 403 ] ; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"Quota exceeded - wait one hour before re-try"</span>
|
||||||
|
sleep 3600
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">$curlresp</span><span style="color:#2a00ff; ">"</span> == 412 ] ; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"Precondition Failed - No device linked"</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">exit</span> 1
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">if</span> [ <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">$curlresp</span><span style="color:#2a00ff; ">"</span> == 500 ] ; <span style="color:#7f0055; font-weight:bold; ">then</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"Internal server error - waiting for better times"</span>
|
||||||
|
sleep 60
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">fi</span>
|
||||||
|
|
||||||
|
<span style="color:#3f7f59; "># if none of the above matched we probably hav no network ...</span>
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">echo</span> <span style="color:#2a00ff; ">"Send failed (response code </span><span style="color:#2a00ff; ">$curlresp</span><span style="color:#2a00ff; ">) ... try again in 5s"</span>
|
||||||
|
sleep 5
|
||||||
|
<span style="color:#7f0055; font-weight:bold; ">done</span>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Be aware that the server only saves send messages for a short amount of time. Because of that you can only use this to prevent duplicates in a short time-frame, older messages with the same ID are probably already deleted and the message will be send again.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@@ -42,6 +42,11 @@ body
|
|||||||
border-left: .25rem solid #E53935;
|
border-left: .25rem solid #E53935;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.yellow-code
|
||||||
|
{
|
||||||
|
border-left: .25rem solid #FFCB05;
|
||||||
|
}
|
||||||
|
|
||||||
#mainpnl input,
|
#mainpnl input,
|
||||||
#mainpnl textarea
|
#mainpnl textarea
|
||||||
{
|
{
|
||||||
@@ -233,6 +238,13 @@ table.scode_table th:nth-child(2) {
|
|||||||
margin-top: 1.75rem;
|
margin-top: 1.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.linkcaption:hover {
|
.linkcaption:hover,
|
||||||
|
.linkcaption:focus {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre, pre span
|
||||||
|
{
|
||||||
|
font-family: Menlo, Consolas, monospace;
|
||||||
|
background: #F9F9F9;;
|
||||||
}
|
}
|
@@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
<div class="row responsive-label">
|
<div class="row responsive-label">
|
||||||
<div class="col-sm-12 col-md-3"><label for="txt" class="doc">Message Content</label></div>
|
<div class="col-sm-12 col-md-3"><label for="txt" class="doc">Message Content</label></div>
|
||||||
<div class="col-sm-12 col-md"><textarea id="txt" class="doc" <?php echo (isset($_GET['preset_content']) ? (' value="'.$_GET['preset_content'].'" '):(''));?> rows="8"></textarea></div>
|
<div class="col-sm-12 col-md"><textarea id="txt" class="doc" <?php echo (isset($_GET['preset_content']) ? (' value="'.$_GET['preset_content'].'" '):(''));?> rows="8" maxlength="2048"></textarea></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@@ -34,10 +34,10 @@ function send()
|
|||||||
if (xhr.readyState !== 4) return;
|
if (xhr.readyState !== 4) return;
|
||||||
|
|
||||||
console.log('Status: ' + xhr.status);
|
console.log('Status: ' + xhr.status);
|
||||||
if (xhr.status === 200)
|
if (xhr.status === 200 || xhr.status === 401 || xhr.status === 403 || xhr.status === 412)
|
||||||
{
|
{
|
||||||
let resp = JSON.parse(xhr.responseText);
|
let resp = JSON.parse(xhr.responseText);
|
||||||
if (!resp.success)
|
if (!resp.success || xhr.status !== 200)
|
||||||
{
|
{
|
||||||
if (resp.errhighlight === 101) uid.classList.add('input-invalid');
|
if (resp.errhighlight === 101) uid.classList.add('input-invalid');
|
||||||
if (resp.errhighlight === 102) key.classList.add('input-invalid');
|
if (resp.errhighlight === 102) key.classList.add('input-invalid');
|
||||||
|
32
web/send.php
@@ -32,8 +32,6 @@ try
|
|||||||
if ($priority !== '0' && $priority !== '1' && $priority !== '2') api_return(400, ['success' => false, 'error' => ERR::INVALID_PRIO, 'errhighlight' => 105, 'message' => 'Invalid priority']);
|
if ($priority !== '0' && $priority !== '1' && $priority !== '2') api_return(400, ['success' => false, 'error' => ERR::INVALID_PRIO, 'errhighlight' => 105, 'message' => 'Invalid priority']);
|
||||||
|
|
||||||
if (strlen(trim($message)) == 0) api_return(400, ['success' => false, 'error' => ERR::NO_TITLE, 'errhighlight' => 103, 'message' => 'No title specified']);
|
if (strlen(trim($message)) == 0) api_return(400, ['success' => false, 'error' => ERR::NO_TITLE, 'errhighlight' => 103, 'message' => 'No title specified']);
|
||||||
if (strlen($message) > 120) api_return(400, ['success' => false, 'error' => ERR::TITLE_TOO_LONG, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)']);
|
|
||||||
if (strlen($content) > 10000) api_return(400, ['success' => false, 'error' => ERR::CONTENT_TOO_LONG, 'errhighlight' => 104, 'message' => 'Content too long (10000 characters)']);
|
|
||||||
if ($usrmsgid != null && strlen($usrmsgid) > 64) api_return(400, ['success' => false, 'error' => ERR::USR_MSG_ID_TOO_LONG, 'errhighlight' => -1, 'message' => 'MessageID too long (64 characters)']);
|
if ($usrmsgid != null && strlen($usrmsgid) > 64) api_return(400, ['success' => false, 'error' => ERR::USR_MSG_ID_TOO_LONG, 'errhighlight' => -1, 'message' => 'MessageID too long (64 characters)']);
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
@@ -44,13 +42,20 @@ try
|
|||||||
$stmt->execute(['uid' => $user_id]);
|
$stmt->execute(['uid' => $user_id]);
|
||||||
|
|
||||||
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
if (count($datas)<=0) die(json_encode(['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']));
|
if (count($datas)<=0) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']);
|
||||||
$data = $datas[0];
|
$data = $datas[0];
|
||||||
|
|
||||||
if ($data === null) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']);
|
if ($data === null) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']);
|
||||||
if ($data['user_id'] !== (int)$user_id) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'UserID not found']);
|
if ($data['user_id'] !== (int)$user_id) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'UserID not found']);
|
||||||
if ($data['user_key'] !== $user_key) api_return(401, ['success' => false, 'error' => ERR::USER_AUTH_FAILED, 'errhighlight' => 102, 'message' => 'Authentification failed']);
|
if ($data['user_key'] !== $user_key) api_return(401, ['success' => false, 'error' => ERR::USER_AUTH_FAILED, 'errhighlight' => 102, 'message' => 'Authentification failed']);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
|
if (strlen($message) > 120) api_return(400, ['success' => false, 'error' => ERR::TITLE_TOO_LONG, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)']);
|
||||||
|
if (strlen($content) > Statics::contentlen_max($data['is_pro'])) api_return(400, ['success' => false, 'error' => ERR::CONTENT_TOO_LONG, 'errhighlight' => 104, 'message' => 'Content too long ('.Statics::contentlen_max($data['is_pro']).' characters)']);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
$fcm = $data['fcm_token'];
|
$fcm = $data['fcm_token'];
|
||||||
|
|
||||||
$new_quota = $data['quota_today'] + 1;
|
$new_quota = $data['quota_today'] + 1;
|
||||||
@@ -115,14 +120,15 @@ try
|
|||||||
// 'body' => $content,
|
// 'body' => $content,
|
||||||
//],
|
//],
|
||||||
'data' =>
|
'data' =>
|
||||||
[
|
[
|
||||||
'title' => $message,
|
'title' => $message,
|
||||||
'body' => $content,
|
'body' => str_limit($content, 1900),
|
||||||
'priority' => $priority,
|
'trimmed' => (strlen($content) > 1900),
|
||||||
'timestamp' => time(),
|
'priority' => $priority,
|
||||||
'usr_msg_id' => $usrmsgid,
|
'timestamp' => time(),
|
||||||
'scn_msg_id' => $scn_msg_id,
|
'usr_msg_id' => $usrmsgid,
|
||||||
]
|
'scn_msg_id' => $scn_msg_id,
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
$header=
|
$header=
|
||||||
[
|
[
|
||||||
@@ -148,6 +154,8 @@ try
|
|||||||
api_return(500, ['success' => false, 'error' => ERR::FIREBASE_COM_FAILED, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.'."\n\n".'Exception: ' . $e->getMessage()]);
|
api_return(500, ['success' => false, 'error' => ERR::FIREBASE_COM_FAILED, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.'."\n\n".'Exception: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1, quota_today=:q, quota_day=NOW() WHERE user_id = :uid');
|
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1, quota_today=:q, quota_day=NOW() WHERE user_id = :uid');
|
||||||
$stmt->execute(['uid' => $user_id, 'q' => $new_quota]);
|
$stmt->execute(['uid' => $user_id, 'q' => $new_quota]);
|
||||||
|
|
||||||
@@ -156,6 +164,8 @@ try
|
|||||||
|
|
||||||
$pdo->commit();
|
$pdo->commit();
|
||||||
|
|
||||||
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
api_return(200,
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
|