Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
90f4270b74
|
|||
f68d75c226
|
|||
9cf5133469
|
|||
75929aad48
|
|||
dca149ec4e
|
|||
75a7b97d24
|
|||
eb62873fb6
|
|||
f8effe7d1e
|
|||
87a3d34315
|
|||
0f38ad6e5c
|
|||
0ec6ab71b2
|
|||
b42204c87d
|
|||
53cb259ec1
|
|||
0150cc9e8e
|
|||
20214473f1
|
|||
![]() |
586ac07ef3 | ||
66f82f26d5
|
|||
6cb2aa00fb
|
|||
96a236803e
|
|||
9d24044eb3
|
|||
90248bcb54
|
|||
a3b2a1b14f
|
|||
b21b159b95
|
|||
93ec261dc0
|
|||
ae246e9219
|
|||
3f18fdd35a
|
|||
faf5207478
|
|||
71f003dd66
|
|||
3f85ab514e
|
|||
9eb5a6b1b9
|
|||
8e26cd6078
|
|||
36b9263730
|
|||
3d29fecaec
|
|||
![]() |
92ac05f1e3 |
4
android/.idea/assetWizardSettings.xml
generated
4
android/.idea/assetWizardSettings.xml
generated
@@ -14,8 +14,8 @@
|
|||||||
<option name="values">
|
<option name="values">
|
||||||
<map>
|
<map>
|
||||||
<entry key="assetSourceType" value="FILE" />
|
<entry key="assetSourceType" value="FILE" />
|
||||||
<entry key="outputName" value="priority_low" />
|
<entry key="outputName" value="ic_garbage" />
|
||||||
<entry key="sourceFile" value="C:\Users\Mike\Downloads\Low Priority-595b40b75ba036ed117d9842.svg" />
|
<entry key="sourceFile" value="C:\Users\Mike\Downloads\garbage.svg" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</PersistentState>
|
</PersistentState>
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="com.android.vending.BILLING" />
|
<uses-permission android:name="com.android.vending.BILLING" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
@@ -35,6 +36,8 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<receiver android:name=".service.BroadcastReceiverService" android:exported="false" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@@ -19,7 +19,7 @@ import androidx.lifecycle.ProcessLifecycleOwner;
|
|||||||
public class SCNApp extends Application implements LifecycleObserver
|
public class SCNApp extends Application implements LifecycleObserver
|
||||||
{
|
{
|
||||||
private static SCNApp instance;
|
private static SCNApp instance;
|
||||||
private static WeakReference<MainActivity> mainActivity;
|
private static WeakReference<MainActivity> mainActivity = new WeakReference<>(null);
|
||||||
|
|
||||||
public static final boolean LOCAL_DEBUG = BuildConfig.DEBUG;
|
public static final boolean LOCAL_DEBUG = BuildConfig.DEBUG;
|
||||||
public static final boolean DEBUG = BuildConfig.DEBUG || !BuildConfig.VERSION_NAME.endsWith(".0");
|
public static final boolean DEBUG = BuildConfig.DEBUG || !BuildConfig.VERSION_NAME.endsWith(".0");
|
||||||
@@ -102,29 +102,11 @@ public class SCNApp extends Application implements LifecycleObserver
|
|||||||
/*
|
/*
|
||||||
==TODO==
|
==TODO==
|
||||||
|
|
||||||
[X] - Pro mode
|
|
||||||
[X] - no ads
|
|
||||||
[X] - more quota
|
|
||||||
[X] - restore pro mode
|
|
||||||
[X] - send pro state to server
|
|
||||||
|
|
||||||
[X] - prevent duplicate-send
|
|
||||||
[X] - send custom msg-id in API
|
|
||||||
[X] - prevent second ack on same msg-id
|
|
||||||
|
|
||||||
[X] - more in-depth API doc on website (?)
|
|
||||||
|
|
||||||
[X] - perhaps response codes in api (?)
|
|
||||||
|
|
||||||
[ ] - test notification channels
|
[ ] - test notification channels
|
||||||
|
[ ] - startup time
|
||||||
|
[ ] - periodically get non-ack (option - even when not in-app)
|
||||||
|
|
||||||
[ ] - publish (+ HN post ?)
|
[ ] - publish (+ HN post ?)
|
||||||
|
|
||||||
[ ] - Use for mscom server errrors
|
|
||||||
[ ] - Use for bfb server errors
|
|
||||||
[ ] - Use for transmission state
|
|
||||||
[ ] - Message on connnection lost (seperate process - resend until succ)
|
|
||||||
[ ] - Message on connnection regained
|
|
||||||
[ ] - Message on seed-count changed
|
|
||||||
|
|
||||||
*/
|
*/
|
@@ -0,0 +1,29 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.lib.lambda;
|
||||||
|
|
||||||
|
import android.widget.SeekBar;
|
||||||
|
|
||||||
|
public final class FI
|
||||||
|
{
|
||||||
|
private FI() throws InstantiationException { throw new InstantiationException(); }
|
||||||
|
|
||||||
|
public static SeekBar.OnSeekBarChangeListener SeekBarChanged(Func3to0<SeekBar, Integer, Boolean> action)
|
||||||
|
{
|
||||||
|
return new SeekBar.OnSeekBarChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||||
|
action.invoke(seekBar, progress, fromUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.lib.lambda;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Func3to0<TInput1, TInput2, TInput3> {
|
||||||
|
void invoke(TInput1 value1, TInput2 value2, TInput3 value3);
|
||||||
|
}
|
@@ -0,0 +1,6 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.lib.lambda;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Func4to0<TInput1, TInput2, TInput3, TInput4> {
|
||||||
|
void invoke(TInput1 value1, TInput2 value2, TInput3 value3, TInput4 value4);
|
||||||
|
}
|
@@ -9,6 +9,7 @@ import java.util.TimeZone;
|
|||||||
|
|
||||||
public class CMessage
|
public class CMessage
|
||||||
{
|
{
|
||||||
|
public final long SCN_ID;
|
||||||
public final long Timestamp;
|
public final long Timestamp;
|
||||||
public final String Title;
|
public final String Title;
|
||||||
public final String Content;
|
public final String Content;
|
||||||
@@ -21,8 +22,9 @@ public class CMessage
|
|||||||
_format.setTimeZone(TimeZone.getDefault());
|
_format.setTimeZone(TimeZone.getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CMessage(long t, String mt, String mc, PriorityEnum p)
|
public CMessage(long id, long t, String mt, String mc, PriorityEnum p)
|
||||||
{
|
{
|
||||||
|
SCN_ID = id;
|
||||||
Timestamp = t;
|
Timestamp = t;
|
||||||
Title = mt;
|
Title = mt;
|
||||||
Content = mc;
|
Content = mc;
|
||||||
|
@@ -3,15 +3,19 @@ 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.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.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class CMessageList
|
public class CMessageList
|
||||||
{
|
{
|
||||||
public ArrayList<CMessage> Messages;
|
public ArrayList<CMessage> Messages;
|
||||||
|
public Set<String> AllAcks;
|
||||||
|
|
||||||
private ArrayList<WeakReference<MessageAdapter>> _listener = new ArrayList<>();
|
private ArrayList<WeakReference<MessageAdapter>> _listener = new ArrayList<>();
|
||||||
|
|
||||||
@@ -29,6 +33,7 @@ public class CMessageList
|
|||||||
private CMessageList()
|
private CMessageList()
|
||||||
{
|
{
|
||||||
Messages = new ArrayList<>();
|
Messages = new ArrayList<>();
|
||||||
|
AllAcks = new HashSet<>();
|
||||||
|
|
||||||
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);
|
||||||
@@ -38,14 +43,17 @@ public class CMessageList
|
|||||||
String title = sharedPref.getString("message["+i+"].title", "");
|
String title = sharedPref.getString("message["+i+"].title", "");
|
||||||
String content = sharedPref.getString("message["+i+"].content", "");
|
String content = sharedPref.getString("message["+i+"].content", "");
|
||||||
PriorityEnum prio = PriorityEnum.parseAPI(sharedPref.getInt("message["+i+"].priority", 1));
|
PriorityEnum prio = PriorityEnum.parseAPI(sharedPref.getInt("message["+i+"].priority", 1));
|
||||||
|
long scnid = sharedPref.getLong("message["+i+"].scnid", 0);
|
||||||
|
|
||||||
Messages.add(new CMessage(time, title, content, prio));
|
Messages.add(new CMessage(scnid, time, title, content, prio));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CMessage add(final long time, final String title, final String content, final PriorityEnum pe)
|
AllAcks = sharedPref.getStringSet("acks", new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CMessage add(final long scnid, final long time, final String title, final String content, final PriorityEnum pe)
|
||||||
{
|
{
|
||||||
CMessage msg = new CMessage(time, title, content, pe);
|
CMessage msg = new CMessage(scnid, time, title, content, pe);
|
||||||
|
|
||||||
boolean run = SCNApp.runOnUiThread(() ->
|
boolean run = SCNApp.runOnUiThread(() ->
|
||||||
{
|
{
|
||||||
@@ -55,6 +63,7 @@ public class CMessageList
|
|||||||
SharedPreferences.Editor e = sharedPref.edit();
|
SharedPreferences.Editor e = sharedPref.edit();
|
||||||
|
|
||||||
Messages.add(msg);
|
Messages.add(msg);
|
||||||
|
AllAcks.add(Long.toHexString(msg.SCN_ID));
|
||||||
|
|
||||||
while (Messages.size()>SCNSettings.inst().LocalCacheSize) Messages.remove(0);
|
while (Messages.size()>SCNSettings.inst().LocalCacheSize) Messages.remove(0);
|
||||||
|
|
||||||
@@ -63,6 +72,9 @@ public class CMessageList
|
|||||||
e.putString("message["+count+"].title", title);
|
e.putString("message["+count+"].title", title);
|
||||||
e.putString("message["+count+"].content", content);
|
e.putString("message["+count+"].content", content);
|
||||||
e.putInt( "message["+count+"].priority", pe.ID);
|
e.putInt( "message["+count+"].priority", pe.ID);
|
||||||
|
e.putLong( "message["+count+"].scnid", scnid);
|
||||||
|
|
||||||
|
e.putStringSet("acks", AllAcks);
|
||||||
|
|
||||||
e.apply();
|
e.apply();
|
||||||
|
|
||||||
@@ -71,13 +83,15 @@ public class CMessageList
|
|||||||
MessageAdapter a = ref.get();
|
MessageAdapter a = ref.get();
|
||||||
if (a == null) continue;
|
if (a == null) continue;
|
||||||
a.customNotifyItemInserted(count);
|
a.customNotifyItemInserted(count);
|
||||||
|
a.scrollToTop();
|
||||||
}
|
}
|
||||||
CleanUpListener();
|
CleanUpListener();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!run)
|
if (!run)
|
||||||
{
|
{
|
||||||
Messages.add(new CMessage(time, title, content, pe));
|
Messages.add(new CMessage(scnid, time, title, content, pe));
|
||||||
|
AllAcks.add(Long.toHexString(msg.SCN_ID));
|
||||||
fullSave();
|
fullSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +127,11 @@ public class CMessageList
|
|||||||
e.putString("message["+i+"].title", Messages.get(i).Title);
|
e.putString("message["+i+"].title", Messages.get(i).Title);
|
||||||
e.putString("message["+i+"].content", Messages.get(i).Content);
|
e.putString("message["+i+"].content", Messages.get(i).Content);
|
||||||
e.putInt( "message["+i+"].priority", Messages.get(i).Priority.ID);
|
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.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +141,11 @@ public class CMessageList
|
|||||||
return Messages.get(pos);
|
return Messages.get(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CMessage tryGetFromBack(int pos)
|
||||||
|
{
|
||||||
|
return tryGet(Messages.size() - pos - 1);
|
||||||
|
}
|
||||||
|
|
||||||
public int size()
|
public int size()
|
||||||
{
|
{
|
||||||
return Messages.size();
|
return Messages.size();
|
||||||
@@ -142,4 +164,21 @@ public class CMessageList
|
|||||||
if (_listener.get(i).get() == null) _listener.remove(i);
|
if (_listener.get(i).get() == null) _listener.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAck(long id)
|
||||||
|
{
|
||||||
|
return AllAcks.contains(Long.toHexString(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(int index)
|
||||||
|
{
|
||||||
|
Messages.remove(index);
|
||||||
|
fullSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insert(int index, CMessage item)
|
||||||
|
{
|
||||||
|
Messages.add(index, item);
|
||||||
|
fullSave();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,34 @@
|
|||||||
package com.blackforestbytes.simplecloudnotifier.model;
|
package com.blackforestbytes.simplecloudnotifier.model;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
public class NotificationSettings
|
public class NotificationSettings
|
||||||
{
|
{
|
||||||
public boolean EnableSound = false;
|
public boolean EnableSound;
|
||||||
public String SoundName = "";
|
public String SoundName;
|
||||||
public String SoundSource = Uri.EMPTY.toString();
|
public String SoundSource;
|
||||||
public boolean RepeatSound = false;
|
public boolean RepeatSound;
|
||||||
|
|
||||||
public boolean EnableLED = false;
|
public boolean ForceVolume;
|
||||||
public int LEDColor = Color.BLUE;
|
public int ForceVolumeValue;
|
||||||
|
|
||||||
public boolean EnableVibration = false;
|
public boolean EnableLED;
|
||||||
|
public int LEDColor;
|
||||||
|
|
||||||
|
public boolean EnableVibration;
|
||||||
|
|
||||||
|
public NotificationSettings(PriorityEnum p)
|
||||||
|
{
|
||||||
|
EnableSound = (p == PriorityEnum.HIGH);
|
||||||
|
SoundName = "Default";
|
||||||
|
SoundSource = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION).toString();
|
||||||
|
RepeatSound = false;
|
||||||
|
EnableLED = (p == PriorityEnum.HIGH) || (p == PriorityEnum.NORMAL);
|
||||||
|
LEDColor = Color.BLUE;
|
||||||
|
EnableVibration = (p == PriorityEnum.HIGH) || (p == PriorityEnum.NORMAL);
|
||||||
|
ForceVolume = false;
|
||||||
|
ForceVolumeValue = 50;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import android.view.View;
|
|||||||
|
|
||||||
import com.android.billingclient.api.Purchase;
|
import com.android.billingclient.api.Purchase;
|
||||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||||
import com.blackforestbytes.simplecloudnotifier.service.IABService;
|
import com.blackforestbytes.simplecloudnotifier.service.IABService;
|
||||||
import com.google.firebase.iid.FirebaseInstanceId;
|
import com.google.firebase.iid.FirebaseInstanceId;
|
||||||
|
|
||||||
@@ -47,9 +48,9 @@ public class SCNSettings
|
|||||||
public boolean Enabled = true;
|
public boolean Enabled = true;
|
||||||
public int LocalCacheSize = 500;
|
public int LocalCacheSize = 500;
|
||||||
|
|
||||||
public final NotificationSettings PriorityLow = new NotificationSettings();
|
public final NotificationSettings PriorityLow = new NotificationSettings(PriorityEnum.LOW);
|
||||||
public final NotificationSettings PriorityNorm = new NotificationSettings();
|
public final NotificationSettings PriorityNorm = new NotificationSettings(PriorityEnum.NORMAL);
|
||||||
public final NotificationSettings PriorityHigh = new NotificationSettings();
|
public final NotificationSettings PriorityHigh = new NotificationSettings(PriorityEnum.HIGH);
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -77,6 +78,8 @@ public class SCNSettings
|
|||||||
PriorityLow.SoundName = sharedPref.getString( "priority_low:sound_name", PriorityLow.SoundName);
|
PriorityLow.SoundName = sharedPref.getString( "priority_low:sound_name", PriorityLow.SoundName);
|
||||||
PriorityLow.SoundSource = sharedPref.getString( "priority_low:sound_source", PriorityLow.SoundSource);
|
PriorityLow.SoundSource = sharedPref.getString( "priority_low:sound_source", PriorityLow.SoundSource);
|
||||||
PriorityLow.LEDColor = sharedPref.getInt( "priority_low:led_color", PriorityLow.LEDColor);
|
PriorityLow.LEDColor = sharedPref.getInt( "priority_low:led_color", PriorityLow.LEDColor);
|
||||||
|
PriorityLow.ForceVolume = sharedPref.getBoolean("priority_low:force_volume", PriorityLow.ForceVolume);
|
||||||
|
PriorityLow.ForceVolumeValue = sharedPref.getInt( "priority_low:force_volume_value", PriorityLow.ForceVolumeValue);
|
||||||
|
|
||||||
PriorityNorm.EnableLED = sharedPref.getBoolean("priority_norm:enabled_led", PriorityNorm.EnableLED);
|
PriorityNorm.EnableLED = sharedPref.getBoolean("priority_norm:enabled_led", PriorityNorm.EnableLED);
|
||||||
PriorityNorm.EnableSound = sharedPref.getBoolean("priority_norm:enabled_sound", PriorityNorm.EnableSound);
|
PriorityNorm.EnableSound = sharedPref.getBoolean("priority_norm:enabled_sound", PriorityNorm.EnableSound);
|
||||||
@@ -85,6 +88,8 @@ public class SCNSettings
|
|||||||
PriorityNorm.SoundName = sharedPref.getString( "priority_norm:sound_name", PriorityNorm.SoundName);
|
PriorityNorm.SoundName = sharedPref.getString( "priority_norm:sound_name", PriorityNorm.SoundName);
|
||||||
PriorityNorm.SoundSource = sharedPref.getString( "priority_norm:sound_source", PriorityNorm.SoundSource);
|
PriorityNorm.SoundSource = sharedPref.getString( "priority_norm:sound_source", PriorityNorm.SoundSource);
|
||||||
PriorityNorm.LEDColor = sharedPref.getInt( "priority_norm:led_color", PriorityNorm.LEDColor);
|
PriorityNorm.LEDColor = sharedPref.getInt( "priority_norm:led_color", PriorityNorm.LEDColor);
|
||||||
|
PriorityNorm.ForceVolume = sharedPref.getBoolean("priority_norm:force_volume", PriorityNorm.ForceVolume);
|
||||||
|
PriorityNorm.ForceVolumeValue = sharedPref.getInt( "priority_norm:force_volume_value", PriorityNorm.ForceVolumeValue);
|
||||||
|
|
||||||
PriorityHigh.EnableLED = sharedPref.getBoolean("priority_high:enabled_led", PriorityHigh.EnableLED);
|
PriorityHigh.EnableLED = sharedPref.getBoolean("priority_high:enabled_led", PriorityHigh.EnableLED);
|
||||||
PriorityHigh.EnableSound = sharedPref.getBoolean("priority_high:enabled_sound", PriorityHigh.EnableSound);
|
PriorityHigh.EnableSound = sharedPref.getBoolean("priority_high:enabled_sound", PriorityHigh.EnableSound);
|
||||||
@@ -93,6 +98,8 @@ public class SCNSettings
|
|||||||
PriorityHigh.SoundName = sharedPref.getString( "priority_high:sound_name", PriorityHigh.SoundName);
|
PriorityHigh.SoundName = sharedPref.getString( "priority_high:sound_name", PriorityHigh.SoundName);
|
||||||
PriorityHigh.SoundSource = sharedPref.getString( "priority_high:sound_source", PriorityHigh.SoundSource);
|
PriorityHigh.SoundSource = sharedPref.getString( "priority_high:sound_source", PriorityHigh.SoundSource);
|
||||||
PriorityHigh.LEDColor = sharedPref.getInt( "priority_high:led_color", PriorityHigh.LEDColor);
|
PriorityHigh.LEDColor = sharedPref.getInt( "priority_high:led_color", PriorityHigh.LEDColor);
|
||||||
|
PriorityHigh.ForceVolume = sharedPref.getBoolean("priority_high:force_volume", PriorityHigh.ForceVolume);
|
||||||
|
PriorityHigh.ForceVolumeValue = sharedPref.getInt( "priority_high:force_volume_value", PriorityHigh.ForceVolumeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save()
|
public void save()
|
||||||
@@ -117,6 +124,8 @@ public class SCNSettings
|
|||||||
e.putString( "priority_low:sound_name", PriorityLow.SoundName);
|
e.putString( "priority_low:sound_name", PriorityLow.SoundName);
|
||||||
e.putString( "priority_low:sound_source", PriorityLow.SoundSource);
|
e.putString( "priority_low:sound_source", PriorityLow.SoundSource);
|
||||||
e.putInt( "priority_low:led_color", PriorityLow.LEDColor);
|
e.putInt( "priority_low:led_color", PriorityLow.LEDColor);
|
||||||
|
e.putBoolean("priority_low:force_volume", PriorityLow.ForceVolume);
|
||||||
|
e.putInt( "priority_low:force_volume_value", PriorityLow.ForceVolumeValue);
|
||||||
|
|
||||||
e.putBoolean("priority_norm:enabled_led", PriorityNorm.EnableLED);
|
e.putBoolean("priority_norm:enabled_led", PriorityNorm.EnableLED);
|
||||||
e.putBoolean("priority_norm:enabled_sound", PriorityNorm.EnableSound);
|
e.putBoolean("priority_norm:enabled_sound", PriorityNorm.EnableSound);
|
||||||
@@ -125,6 +134,8 @@ public class SCNSettings
|
|||||||
e.putString( "priority_norm:sound_name", PriorityNorm.SoundName);
|
e.putString( "priority_norm:sound_name", PriorityNorm.SoundName);
|
||||||
e.putString( "priority_norm:sound_source", PriorityNorm.SoundSource);
|
e.putString( "priority_norm:sound_source", PriorityNorm.SoundSource);
|
||||||
e.putInt( "priority_norm:led_color", PriorityNorm.LEDColor);
|
e.putInt( "priority_norm:led_color", PriorityNorm.LEDColor);
|
||||||
|
e.putBoolean("priority_norm:force_volume", PriorityNorm.ForceVolume);
|
||||||
|
e.putInt( "priority_norm:force_volume_value", PriorityNorm.ForceVolumeValue);
|
||||||
|
|
||||||
e.putBoolean("priority_high:enabled_led", PriorityHigh.EnableLED);
|
e.putBoolean("priority_high:enabled_led", PriorityHigh.EnableLED);
|
||||||
e.putBoolean("priority_high:enabled_sound", PriorityHigh.EnableSound);
|
e.putBoolean("priority_high:enabled_sound", PriorityHigh.EnableSound);
|
||||||
@@ -133,6 +144,8 @@ public class SCNSettings
|
|||||||
e.putString( "priority_high:sound_name", PriorityHigh.SoundName);
|
e.putString( "priority_high:sound_name", PriorityHigh.SoundName);
|
||||||
e.putString( "priority_high:sound_source", PriorityHigh.SoundSource);
|
e.putString( "priority_high:sound_source", PriorityHigh.SoundSource);
|
||||||
e.putInt( "priority_high:led_color", PriorityHigh.LEDColor);
|
e.putInt( "priority_high:led_color", PriorityHigh.LEDColor);
|
||||||
|
e.putBoolean("priority_high:force_volume", PriorityHigh.ForceVolume);
|
||||||
|
e.putInt( "priority_high:force_volume_value", PriorityHigh.ForceVolumeValue);
|
||||||
|
|
||||||
e.apply();
|
e.apply();
|
||||||
}
|
}
|
||||||
@@ -154,7 +167,7 @@ public class SCNSettings
|
|||||||
{
|
{
|
||||||
fcm_token_local = token;
|
fcm_token_local = token;
|
||||||
save();
|
save();
|
||||||
if (!fcm_token_local.equals(fcm_token_server)) ServerCommunication.update(user_id, user_key, fcm_token_local, loader);
|
if (!fcm_token_local.equals(fcm_token_server)) ServerCommunication.updateFCMToken(user_id, user_key, fcm_token_local, loader);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -186,7 +199,7 @@ public class SCNSettings
|
|||||||
{
|
{
|
||||||
if (!isConnected()) return;
|
if (!isConnected()) return;
|
||||||
|
|
||||||
ServerCommunication.update(user_id, user_key, loader);
|
ServerCommunication.resetSecret(user_id, user_key, loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
// refresh account data
|
// refresh account data
|
||||||
@@ -195,10 +208,10 @@ public class SCNSettings
|
|||||||
if (isConnected())
|
if (isConnected())
|
||||||
{
|
{
|
||||||
ServerCommunication.info(user_id, user_key, loader);
|
ServerCommunication.info(user_id, user_key, loader);
|
||||||
if (promode_server != promode_local)
|
|
||||||
{
|
if (promode_server != promode_local) updateProState(loader);
|
||||||
updateProState(loader);
|
|
||||||
}
|
if (!Str.equals(fcm_token_local, fcm_token_server)) work(a);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -4,7 +4,11 @@ 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.string.Str;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.service.FBMService;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONTokener;
|
import org.json.JSONTokener;
|
||||||
|
|
||||||
@@ -20,7 +24,7 @@ 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/";
|
public static final String BASE_URL = /*SCNApp.LOCAL_DEBUG ? "http://localhost:1010/" : */"https://scn.blackforestbytes.com/api/";
|
||||||
|
|
||||||
private static final OkHttpClient client = new OkHttpClient();
|
private static final OkHttpClient client = new OkHttpClient();
|
||||||
|
|
||||||
@@ -39,7 +43,7 @@ public class ServerCommunication
|
|||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, IOException e)
|
public void onFailure(Call call, IOException e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:register", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
SCNApp.runOnUiThread(() -> { if (loader!=null)loader.setVisibility(View.GONE); });
|
SCNApp.runOnUiThread(() -> { if (loader!=null)loader.setVisibility(View.GONE); });
|
||||||
}
|
}
|
||||||
@@ -57,25 +61,25 @@ public class ServerCommunication
|
|||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
if (!json.getBoolean("success"))
|
if (!json_bool(json, "success"))
|
||||||
{
|
{
|
||||||
SCNApp.showToast(json.getString("message"), 4000);
|
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCNSettings.inst().user_id = json.getInt("user_id");
|
SCNSettings.inst().user_id = json_int(json, "user_id");
|
||||||
SCNSettings.inst().user_key = json.getString("user_key");
|
SCNSettings.inst().user_key = json_str(json, "user_key");
|
||||||
SCNSettings.inst().fcm_token_server = token;
|
SCNSettings.inst().fcm_token_server = token;
|
||||||
SCNSettings.inst().quota_curr = json.getInt("quota");
|
SCNSettings.inst().quota_curr = json_int(json, "quota");
|
||||||
SCNSettings.inst().quota_max = json.getInt("quota_max");
|
SCNSettings.inst().quota_max = json_int(json, "quota_max");
|
||||||
SCNSettings.inst().promode_server = json.getBoolean("is_pro");
|
SCNSettings.inst().promode_server = json_bool(json, "is_pro");
|
||||||
SCNSettings.inst().save();
|
SCNSettings.inst().save();
|
||||||
|
|
||||||
SCNApp.refreshAccountTab();
|
SCNApp.refreshAccountTab();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:register", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -87,17 +91,17 @@ public class ServerCommunication
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:register", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void update(int id, String key, String token, View loader)
|
public static void updateFCMToken(int id, String key, String token, View loader)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(BASE_URL + "update.php?user_id="+id+"&user_key="+key+"&fcm_token="+token)
|
.url(BASE_URL + "updateFCMToken.php?user_id="+id+"&user_key="+key+"&fcm_token="+token)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
client.newCall(request).enqueue(new Callback()
|
client.newCall(request).enqueue(new Callback()
|
||||||
@@ -105,7 +109,7 @@ public class ServerCommunication
|
|||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, IOException e)
|
public void onFailure(Call call, IOException e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:update_1", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
SCNApp.runOnUiThread(() -> { if (loader!=null)loader.setVisibility(View.GONE); });
|
SCNApp.runOnUiThread(() -> { if (loader!=null)loader.setVisibility(View.GONE); });
|
||||||
}
|
}
|
||||||
@@ -123,25 +127,25 @@ public class ServerCommunication
|
|||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
if (!json.getBoolean("success"))
|
if (!json_bool(json, "success"))
|
||||||
{
|
{
|
||||||
SCNApp.showToast(json.getString("message"), 4000);
|
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCNSettings.inst().user_id = json.getInt("user_id");
|
SCNSettings.inst().user_id = json_int(json, "user_id");
|
||||||
SCNSettings.inst().user_key = json.getString("user_key");
|
SCNSettings.inst().user_key = json_str(json, "user_key");
|
||||||
SCNSettings.inst().fcm_token_server = token;
|
SCNSettings.inst().fcm_token_server = token;
|
||||||
SCNSettings.inst().quota_curr = json.getInt("quota");
|
SCNSettings.inst().quota_curr = json_int(json, "quota");
|
||||||
SCNSettings.inst().quota_max = json.getInt("quota_max");
|
SCNSettings.inst().quota_max = json_int(json, "quota_max");
|
||||||
SCNSettings.inst().promode_server = json.getBoolean("is_pro");
|
SCNSettings.inst().promode_server = json_bool(json, "is_pro");
|
||||||
SCNSettings.inst().save();
|
SCNSettings.inst().save();
|
||||||
|
|
||||||
SCNApp.refreshAccountTab();
|
SCNApp.refreshAccountTab();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:update_1", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -153,23 +157,23 @@ public class ServerCommunication
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:update_1", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void update(int id, String key, View loader)
|
public static void resetSecret(int id, String key, View loader)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(BASE_URL + "update.php?user_id=" + id + "&user_key=" + key)
|
.url(BASE_URL + "updateFCMToken.php?user_id=" + id + "&user_key=" + key)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, IOException e) {
|
public void onFailure(Call call, IOException e) {
|
||||||
e.printStackTrace();
|
Log.e("SC:update_2", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,21 +189,21 @@ public class ServerCommunication
|
|||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
if (!json.getBoolean("success")) {
|
if (!json_bool(json, "success")) {
|
||||||
SCNApp.showToast(json.getString("message"), 4000);
|
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCNSettings.inst().user_id = json.getInt("user_id");
|
SCNSettings.inst().user_id = json_int(json, "user_id");
|
||||||
SCNSettings.inst().user_key = json.getString("user_key");
|
SCNSettings.inst().user_key = json_str(json, "user_key");
|
||||||
SCNSettings.inst().quota_curr = json.getInt("quota");
|
SCNSettings.inst().quota_curr = json_int(json, "quota");
|
||||||
SCNSettings.inst().quota_max = json.getInt("quota_max");
|
SCNSettings.inst().quota_max = json_int(json, "quota_max");
|
||||||
SCNSettings.inst().promode_server = json.getBoolean("is_pro");
|
SCNSettings.inst().promode_server = json_bool(json, "is_pro");
|
||||||
SCNSettings.inst().save();
|
SCNSettings.inst().save();
|
||||||
|
|
||||||
SCNApp.refreshAccountTab();
|
SCNApp.refreshAccountTab();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Log.e("SC:update_2", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
} finally {
|
} finally {
|
||||||
SCNApp.runOnUiThread(() -> {
|
SCNApp.runOnUiThread(() -> {
|
||||||
@@ -211,7 +215,7 @@ public class ServerCommunication
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:update_2", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,7 +231,7 @@ public class ServerCommunication
|
|||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, IOException e) {
|
public void onFailure(Call call, IOException e) {
|
||||||
e.printStackTrace();
|
Log.e("SC:info", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
SCNApp.runOnUiThread(() -> {
|
SCNApp.runOnUiThread(() -> {
|
||||||
if (loader != null) loader.setVisibility(View.GONE);
|
if (loader != null) loader.setVisibility(View.GONE);
|
||||||
@@ -246,20 +250,46 @@ public class ServerCommunication
|
|||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
if (!json.getBoolean("success")) {
|
if (!json_bool(json, "success"))
|
||||||
SCNApp.showToast(json.getString("message"), 4000);
|
{
|
||||||
return;
|
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
}
|
|
||||||
|
|
||||||
SCNSettings.inst().user_id = json.getInt("user_id");
|
int errid = json.optInt("errid", 0);
|
||||||
SCNSettings.inst().quota_curr = json.getInt("quota");
|
|
||||||
SCNSettings.inst().quota_max = json.getInt("quota_max");
|
if (errid == 201 || errid == 202 || errid == 203 || errid == 204)
|
||||||
SCNSettings.inst().promode_server = json.getBoolean("is_pro");
|
{
|
||||||
|
// user not found or auth failed
|
||||||
|
|
||||||
|
SCNSettings.inst().user_id = -1;
|
||||||
|
SCNSettings.inst().user_key = "";
|
||||||
|
SCNSettings.inst().quota_curr = 0;
|
||||||
|
SCNSettings.inst().quota_max = 0;
|
||||||
|
SCNSettings.inst().promode_server = false;
|
||||||
|
SCNSettings.inst().fcm_token_server = "";
|
||||||
SCNSettings.inst().save();
|
SCNSettings.inst().save();
|
||||||
|
|
||||||
SCNApp.refreshAccountTab();
|
SCNApp.refreshAccountTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
e.printStackTrace();
|
Log.e("SC:info", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
} finally {
|
} finally {
|
||||||
SCNApp.runOnUiThread(() -> {
|
SCNApp.runOnUiThread(() -> {
|
||||||
@@ -271,7 +301,90 @@ public class ServerCommunication
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
e.printStackTrace();
|
Log.e("SC:info", e.toString());
|
||||||
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void requery(int id, String key, View loader)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(BASE_URL + "requery.php?user_id=" + id + "&user_key=" + key)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
client.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
Log.e("SC:requery", 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", r);
|
||||||
|
|
||||||
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
|
if (!json_bool(json, "success"))
|
||||||
|
{
|
||||||
|
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = json_int(json, "count");
|
||||||
|
JSONArray arr = json.getJSONArray("data");
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
JSONObject o = arr.getJSONObject(0);
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
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) {
|
||||||
|
Log.e("SC:info", 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:requery", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -289,7 +402,7 @@ public class ServerCommunication
|
|||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call call, IOException e) {
|
public void onFailure(Call call, IOException e) {
|
||||||
e.printStackTrace();
|
Log.e("SC:upgrade", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,21 +418,20 @@ public class ServerCommunication
|
|||||||
|
|
||||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
if (!json.getBoolean("success")) {
|
if (!json_bool(json, "success")) {
|
||||||
SCNApp.showToast(json.getString("message"), 4000);
|
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCNSettings.inst().user_id = json.getInt("user_id");
|
SCNSettings.inst().user_id = json_int(json, "user_id");
|
||||||
SCNSettings.inst().user_key = json.getString("user_key");
|
SCNSettings.inst().quota_curr = json_int(json, "quota");
|
||||||
SCNSettings.inst().quota_curr = json.getInt("quota");
|
SCNSettings.inst().quota_max = json_int(json, "quota_max");
|
||||||
SCNSettings.inst().quota_max = json.getInt("quota_max");
|
SCNSettings.inst().promode_server = json_bool(json, "is_pro");
|
||||||
SCNSettings.inst().promode_server = json.getBoolean("is_pro");
|
|
||||||
SCNSettings.inst().save();
|
SCNSettings.inst().save();
|
||||||
|
|
||||||
SCNApp.refreshAccountTab();
|
SCNApp.refreshAccountTab();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
Log.e("SC:upgrade", e.toString());
|
||||||
SCNApp.showToast("Communication with server failed", 4000);
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
} finally {
|
} finally {
|
||||||
SCNApp.runOnUiThread(() -> { if (loader != null) loader.setVisibility(View.GONE); });
|
SCNApp.runOnUiThread(() -> { if (loader != null) loader.setVisibility(View.GONE); });
|
||||||
@@ -334,4 +446,70 @@ public class ServerCommunication
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ack(int id, String key, CMessage msg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(BASE_URL + "ack.php?user_id=" + id + "&user_key=" + key + "&scn_msg_id=" + msg.SCN_ID)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
client.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
Log.e("SC:ack", e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@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", r);
|
||||||
|
|
||||||
|
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||||
|
|
||||||
|
if (!json_bool(json, "success")) SCNApp.showToast(json_str(json, "message"), 4000);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("SC:ack", e.toString());
|
||||||
|
SCNApp.showToast("Communication with server failed", 4000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.e("SC:ack", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean json_bool(JSONObject o, String key) throws JSONException
|
||||||
|
{
|
||||||
|
Object v = o.get(key);
|
||||||
|
if (v instanceof Integer) return ((int)v) != 0;
|
||||||
|
if (v instanceof Boolean) return ((boolean)v);
|
||||||
|
if (v instanceof String) return !Str.equals(((String)v), "0") && !Str.equals(((String)v), "false");
|
||||||
|
|
||||||
|
return o.getBoolean(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int json_int(JSONObject o, String key) throws JSONException
|
||||||
|
{
|
||||||
|
return o.getInt(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long json_lng(JSONObject o, String key) throws JSONException
|
||||||
|
{
|
||||||
|
return o.getLong(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String json_str(JSONObject o, String key) throws JSONException
|
||||||
|
{
|
||||||
|
return o.getString(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,42 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.service;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.view.MainActivity;
|
||||||
|
|
||||||
|
public class BroadcastReceiverService extends BroadcastReceiver
|
||||||
|
{
|
||||||
|
public static final int NOTIF_SHOW_MAIN = 10021;
|
||||||
|
public static final int NOTIF_STOP_SOUND = 10022;
|
||||||
|
public static final String ID_KEY = "com.blackforestbytes.simplecloudnotifier.BroadcastID";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
if (intent == null) return;
|
||||||
|
Bundle extras = intent.getExtras();
|
||||||
|
if (extras == null) return;
|
||||||
|
int notificationId = extras.getInt(ID_KEY, 0);
|
||||||
|
|
||||||
|
if (notificationId == 0) return;
|
||||||
|
else if (notificationId == NOTIF_SHOW_MAIN) showMain(context);
|
||||||
|
else if (notificationId == NOTIF_STOP_SOUND) stopNotificationSound();
|
||||||
|
else return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopNotificationSound()
|
||||||
|
{
|
||||||
|
SoundService.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showMain(Context ctxt)
|
||||||
|
{
|
||||||
|
SoundService.stop();
|
||||||
|
|
||||||
|
Intent intent = new Intent(ctxt, MainActivity.class);
|
||||||
|
ctxt.startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
@@ -8,6 +8,7 @@ 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;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.model.ServerCommunication;
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||||
import com.google.firebase.messaging.RemoteMessage;
|
import com.google.firebase.messaging.RemoteMessage;
|
||||||
|
|
||||||
@@ -36,9 +37,27 @@ public class FBMService extends FirebaseMessagingService
|
|||||||
String title = remoteMessage.getData().get("title");
|
String title = remoteMessage.getData().get("title");
|
||||||
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"));
|
||||||
|
|
||||||
CMessage msg = CMessageList.inst().add(time, title, content, prio);
|
recieveData(time, title, content, prio, scn_id, false);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.e("FB:Err", e.toString());
|
||||||
|
SCNApp.showToast("Recieved invalid message from server", Toast.LENGTH_LONG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
Log.w("FB::MessageReceived", "Recieved ack-ed message: " + scn_id);
|
||||||
|
if (alwaysAck) ServerCommunication.ack(SCNSettings.inst().user_id, SCNSettings.inst().user_key, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (SCNApp.isBackground())
|
if (SCNApp.isBackground())
|
||||||
{
|
{
|
||||||
@@ -48,11 +67,7 @@ public class FBMService extends FirebaseMessagingService
|
|||||||
{
|
{
|
||||||
NotificationService.inst().showForeground(msg);
|
NotificationService.inst().showForeground(msg);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception e)
|
ServerCommunication.ack(SCNSettings.inst().user_id, SCNSettings.inst().user_key, msg);
|
||||||
{
|
|
||||||
Log.e("FB:Err", e.toString());
|
|
||||||
SCNApp.showToast("Recieved invalid message from server", Toast.LENGTH_LONG);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -6,26 +6,31 @@ 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.Color;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.VibrationEffect;
|
||||||
|
import android.os.Vibrator;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.NotificationSettings;
|
import com.blackforestbytes.simplecloudnotifier.model.NotificationSettings;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.PriorityEnum;
|
import com.blackforestbytes.simplecloudnotifier.model.PriorityEnum;
|
||||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||||
import com.blackforestbytes.simplecloudnotifier.view.MainActivity;
|
import com.blackforestbytes.simplecloudnotifier.view.MainActivity;
|
||||||
|
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
public class NotificationService
|
public class NotificationService
|
||||||
{
|
{
|
||||||
private final static String CHANNEL_ID_LOW = "CHAN_BFB_SCN_MESSAGES_LOW";
|
private final static String CHANNEL_P0_ID = "CHAN_BFB_SCN_MESSAGES_P0";
|
||||||
private final static String CHANNEL_ID_NORM = "CHAN_BFB_SCN_MESSAGES_NORM";
|
private final static String CHANNEL_P1_ID = "CHAN_BFB_SCN_MESSAGES_P1";
|
||||||
private final static String CHANNEL_ID_HIGH = "CHAN_BFB_SCN_MESSAGES_HIGH";
|
private final static String CHANNEL_P2_ID = "CHAN_BFB_SCN_MESSAGES_P2";
|
||||||
|
|
||||||
private final static Object _lock = new Object();
|
private final static Object _lock = new Object();
|
||||||
private static NotificationService _inst = null;
|
private static NotificationService _inst = null;
|
||||||
@@ -40,10 +45,10 @@ public class NotificationService
|
|||||||
|
|
||||||
private NotificationService()
|
private NotificationService()
|
||||||
{
|
{
|
||||||
updateChannels();
|
createChannels();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateChannels()
|
private void createChannels()
|
||||||
{
|
{
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
|
||||||
|
|
||||||
@@ -51,81 +56,201 @@ public class NotificationService
|
|||||||
NotificationManager notifman = ctxt.getSystemService(NotificationManager.class);
|
NotificationManager notifman = ctxt.getSystemService(NotificationManager.class);
|
||||||
if (notifman == null) return;
|
if (notifman == null) return;
|
||||||
|
|
||||||
NotificationChannel channelLow = notifman.getNotificationChannel(CHANNEL_ID_LOW);
|
{
|
||||||
if (channelLow == null) notifman.createNotificationChannel(channelLow = new NotificationChannel(CHANNEL_ID_LOW, "Push notifications (low priority)", NotificationManager.IMPORTANCE_LOW));
|
NotificationChannel channel0 = notifman.getNotificationChannel(CHANNEL_P0_ID);
|
||||||
NotificationChannel channelNorm = notifman.getNotificationChannel(CHANNEL_ID_NORM);
|
if (channel0 == null)
|
||||||
if (channelNorm == null) notifman.createNotificationChannel(channelNorm = new NotificationChannel(CHANNEL_ID_NORM, "Push notifications (normal priority)", NotificationManager.IMPORTANCE_DEFAULT));
|
{
|
||||||
NotificationChannel channelHigh = notifman.getNotificationChannel(CHANNEL_ID_HIGH);
|
channel0 = new NotificationChannel(CHANNEL_P0_ID, "Push notifications (low priority)", NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
if (channelHigh == null) notifman.createNotificationChannel(channelHigh = new NotificationChannel(CHANNEL_ID_HIGH, "Push notifications (high priority)", NotificationManager.IMPORTANCE_HIGH));
|
channel0.setDescription("Push notifications from the server with low priority.\nGo to the in-app settings to configure ringtone, volume and vibrations");
|
||||||
|
channel0.setSound(null, null);
|
||||||
channelLow.setDescription("Messages from the API with priority set to low");
|
channel0.setVibrationPattern(null);
|
||||||
channelLow.enableLights(SCNSettings.inst().PriorityLow.EnableLED);
|
channel0.setLightColor(Color.BLUE);
|
||||||
channelLow.setLightColor(SCNSettings.inst().PriorityLow.LEDColor);
|
notifman.createNotificationChannel(channel0);
|
||||||
channelLow.enableVibration(SCNSettings.inst().PriorityLow.EnableVibration);
|
}
|
||||||
channelLow.setVibrationPattern(new long[]{200});
|
}
|
||||||
|
{
|
||||||
channelNorm.setDescription("Messages from the API with priority set to normal");
|
NotificationChannel channel1 = notifman.getNotificationChannel(CHANNEL_P1_ID);
|
||||||
channelNorm.enableLights(SCNSettings.inst().PriorityNorm.EnableLED);
|
if (channel1 == null)
|
||||||
channelNorm.setLightColor(SCNSettings.inst().PriorityNorm.LEDColor);
|
{
|
||||||
channelNorm.enableVibration(SCNSettings.inst().PriorityNorm.EnableVibration);
|
channel1 = new NotificationChannel(CHANNEL_P1_ID, "Push notifications (normal priority)", NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
channelNorm.setVibrationPattern(new long[]{200});
|
channel1.setDescription("Push notifications from the server with low priority.\nGo to the in-app settings to configure ringtone, volume and vibrations");
|
||||||
|
channel1.setSound(null, null);
|
||||||
channelHigh.setDescription("Messages from the API with priority set to high");
|
channel1.setVibrationPattern(null);
|
||||||
channelHigh.enableLights(SCNSettings.inst().PriorityHigh.EnableLED);
|
channel1.setLightColor(Color.BLUE);
|
||||||
channelHigh.setLightColor(SCNSettings.inst().PriorityHigh.LEDColor);
|
notifman.createNotificationChannel(channel1);
|
||||||
channelHigh.enableVibration(SCNSettings.inst().PriorityHigh.EnableVibration);
|
}
|
||||||
channelHigh.setVibrationPattern(new long[]{200});
|
}
|
||||||
channelLow.setBypassDnd(true);
|
{
|
||||||
channelLow.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
NotificationChannel channel2 = notifman.getNotificationChannel(CHANNEL_P2_ID);
|
||||||
|
if (channel2 == null)
|
||||||
|
{
|
||||||
|
channel2 = new NotificationChannel(CHANNEL_P1_ID, "Push notifications (high priority)", NotificationManager.IMPORTANCE_DEFAULT);
|
||||||
|
channel2.setDescription("Push notifications from the server with low priority.\nGo to the in-app settings to configure ringtone, volume and vibrations");
|
||||||
|
channel2.setSound(null, null);
|
||||||
|
channel2.setVibrationPattern(null);
|
||||||
|
channel2.setLightColor(Color.BLUE);
|
||||||
|
notifman.createNotificationChannel(channel2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showForeground(CMessage msg)
|
public void showForeground(CMessage msg)
|
||||||
{
|
{
|
||||||
SCNApp.showToast("Message recieved: " + msg.Title, Toast.LENGTH_LONG);
|
SCNApp.showToast("Message recieved: " + msg.Title, Toast.LENGTH_LONG);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
NotificationSettings ns = SCNSettings.inst().PriorityNorm;
|
||||||
|
switch (msg.Priority)
|
||||||
|
{
|
||||||
|
case LOW: ns = SCNSettings.inst().PriorityLow; break;
|
||||||
|
case NORMAL: ns = SCNSettings.inst().PriorityNorm; break;
|
||||||
|
case HIGH: ns = SCNSettings.inst().PriorityHigh; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundService.play(ns.EnableSound, ns.SoundSource, ns.ForceVolume, ns.ForceVolumeValue, false);
|
||||||
|
|
||||||
|
if (ns.EnableVibration)
|
||||||
|
{
|
||||||
|
Vibrator v = (Vibrator) SCNApp.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
v.vibrate(VibrationEffect.createOneShot(1500, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||||
|
} else {
|
||||||
|
v.vibrate(1500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showBackground(CMessage msg)
|
public void showBackground(CMessage msg)
|
||||||
{
|
{
|
||||||
Context ctxt = SCNApp.getContext();
|
Context ctxt = SCNApp.getContext();
|
||||||
|
|
||||||
String channel = CHANNEL_ID_NORM;
|
|
||||||
NotificationSettings ns = SCNSettings.inst().PriorityNorm;
|
NotificationSettings ns = SCNSettings.inst().PriorityNorm;
|
||||||
switch (msg.Priority)
|
switch (msg.Priority)
|
||||||
{
|
{
|
||||||
case LOW: ns = SCNSettings.inst().PriorityLow; channel = CHANNEL_ID_LOW; break;
|
case LOW: ns = SCNSettings.inst().PriorityLow; break;
|
||||||
case NORMAL: ns = SCNSettings.inst().PriorityNorm; channel = CHANNEL_ID_NORM; break;
|
case NORMAL: ns = SCNSettings.inst().PriorityNorm; break;
|
||||||
case HIGH: ns = SCNSettings.inst().PriorityHigh; channel = CHANNEL_ID_HIGH; break;
|
case HIGH: ns = SCNSettings.inst().PriorityHigh; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctxt, channel);
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
|
||||||
|
{
|
||||||
|
// old
|
||||||
|
showBackground_old(msg, ctxt, ns, msg.Priority);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// new
|
||||||
|
showBackground_new(msg, ctxt, ns, msg.Priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getChannel(PriorityEnum p)
|
||||||
|
{
|
||||||
|
switch (p)
|
||||||
|
{
|
||||||
|
case LOW: return CHANNEL_P0_ID;
|
||||||
|
case NORMAL: return CHANNEL_P1_ID;
|
||||||
|
case HIGH: return CHANNEL_P2_ID;
|
||||||
|
|
||||||
|
default: return CHANNEL_P0_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showBackground_old(CMessage msg, Context ctxt, NotificationSettings ns, PriorityEnum prio)
|
||||||
|
{
|
||||||
|
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctxt, getChannel(prio));
|
||||||
mBuilder.setSmallIcon(R.drawable.ic_bfb);
|
mBuilder.setSmallIcon(R.drawable.ic_bfb);
|
||||||
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);
|
mBuilder.setWhen(msg.Timestamp * 1000);
|
||||||
mBuilder.setAutoCancel(true);
|
mBuilder.setAutoCancel(true);
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
|
|
||||||
{
|
|
||||||
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);
|
||||||
if (msg.Priority == PriorityEnum.HIGH) mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
if (msg.Priority == PriorityEnum.HIGH) mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||||
if (ns.EnableVibration) mBuilder.setVibrate(new long[]{200});
|
if (ns.EnableVibration) mBuilder.setVibrate(new long[]{500});
|
||||||
if (ns.EnableLED) mBuilder.setLights(ns.LEDColor, 500, 500);
|
if (ns.EnableLED) mBuilder.setLights(ns.LEDColor, 500, 500);
|
||||||
}
|
|
||||||
|
|
||||||
if (ns.EnableSound && !ns.SoundSource.isEmpty())
|
if (ns.EnableSound && !ns.SoundSource.isEmpty() && !ns.RepeatSound) mBuilder.setSound(Uri.parse(ns.SoundSource), AudioManager.STREAM_NOTIFICATION);
|
||||||
{
|
|
||||||
mBuilder.setSound(Uri.parse(ns.SoundSource), AudioManager.STREAM_ALARM);
|
|
||||||
}
|
|
||||||
|
|
||||||
Intent intent = new Intent(ctxt, MainActivity.class);
|
Intent intent = new Intent(ctxt, MainActivity.class);
|
||||||
PendingIntent pi = PendingIntent.getActivity(ctxt, 0, intent, 0);
|
PendingIntent pi = PendingIntent.getActivity(ctxt, 0, intent, 0);
|
||||||
mBuilder.setContentIntent(pi);
|
mBuilder.setContentIntent(pi);
|
||||||
NotificationManager mNotificationManager = (NotificationManager) ctxt.getSystemService(Context.NOTIFICATION_SERVICE);
|
NotificationManager mNotificationManager = (NotificationManager) ctxt.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
|
if (ns.EnableSound && !ns.SoundSource.isEmpty() && ns.RepeatSound)
|
||||||
|
{
|
||||||
|
Intent intnt_stop = new Intent(SCNApp.getContext(), BroadcastReceiverService.class);
|
||||||
|
intnt_stop.putExtra(BroadcastReceiverService.ID_KEY, BroadcastReceiverService.NOTIF_STOP_SOUND);
|
||||||
|
PendingIntent pi_stop = PendingIntent.getBroadcast(SCNApp.getContext().getApplicationContext(), BroadcastReceiverService.NOTIF_STOP_SOUND, intnt_stop, 0);
|
||||||
|
mBuilder.addAction(new NotificationCompat.Action(-1, "Stop", pi_stop));
|
||||||
|
mBuilder.setDeleteIntent(pi_stop);
|
||||||
|
|
||||||
|
SoundService.play(ns.EnableSound, ns.SoundSource, ns.ForceVolume, ns.ForceVolumeValue, ns.RepeatSound);
|
||||||
|
}
|
||||||
|
|
||||||
Notification n = mBuilder.build();
|
Notification n = mBuilder.build();
|
||||||
if (ns.EnableSound && !ns.SoundSource.isEmpty() && ns.RepeatSound) n.flags |= Notification.FLAG_INSISTENT;
|
|
||||||
|
|
||||||
if (mNotificationManager != null) mNotificationManager.notify(0, n);
|
if (mNotificationManager != null) mNotificationManager.notify(0, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
|
private void showBackground_new(CMessage msg, Context ctxt, NotificationSettings ns, PriorityEnum prio)
|
||||||
|
{
|
||||||
|
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctxt, getChannel(prio));
|
||||||
|
mBuilder.setSmallIcon(R.drawable.ic_bfb);
|
||||||
|
mBuilder.setContentTitle(msg.Title);
|
||||||
|
mBuilder.setContentText(msg.Content);
|
||||||
|
mBuilder.setShowWhen(true);
|
||||||
|
mBuilder.setWhen(msg.Timestamp * 1000);
|
||||||
|
mBuilder.setAutoCancel(true);
|
||||||
|
|
||||||
|
if (ns.EnableLED) mBuilder.setLights(ns.LEDColor, 500, 500);
|
||||||
|
|
||||||
|
if (msg.Priority == PriorityEnum.LOW) mBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
|
||||||
|
if (msg.Priority == PriorityEnum.NORMAL) mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
||||||
|
if (msg.Priority == PriorityEnum.HIGH) mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||||
|
|
||||||
|
Intent intnt_click = new Intent(SCNApp.getContext(), BroadcastReceiverService.class);
|
||||||
|
intnt_click.putExtra(BroadcastReceiverService.ID_KEY, BroadcastReceiverService.NOTIF_SHOW_MAIN);
|
||||||
|
PendingIntent pi = PendingIntent.getBroadcast(ctxt, 0, intnt_click, 0);
|
||||||
|
mBuilder.setContentIntent(pi);
|
||||||
|
NotificationManager mNotificationManager = (NotificationManager) ctxt.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
if (mNotificationManager == null) return;
|
||||||
|
|
||||||
|
if (ns.EnableSound && !Str.isNullOrWhitespace(ns.SoundSource))
|
||||||
|
{
|
||||||
|
if (ns.RepeatSound)
|
||||||
|
{
|
||||||
|
Intent intnt_stop = new Intent(SCNApp.getContext(), BroadcastReceiverService.class);
|
||||||
|
intnt_stop.putExtra(BroadcastReceiverService.ID_KEY, BroadcastReceiverService.NOTIF_STOP_SOUND);
|
||||||
|
PendingIntent pi_stop = PendingIntent.getBroadcast(ctxt, BroadcastReceiverService.NOTIF_STOP_SOUND, intnt_stop, 0);
|
||||||
|
mBuilder.addAction(new NotificationCompat.Action(-1, "Stop", pi_stop));
|
||||||
|
mBuilder.setDeleteIntent(pi_stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundService.play(ns.EnableSound, ns.SoundSource, ns.ForceVolume, ns.ForceVolumeValue, ns.RepeatSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification n = mBuilder.build();
|
||||||
|
n.flags |= Notification.FLAG_AUTO_CANCEL;
|
||||||
|
|
||||||
|
mNotificationManager.notify(0, n);
|
||||||
|
|
||||||
|
if (ns.EnableVibration)
|
||||||
|
{
|
||||||
|
Vibrator v = (Vibrator) SCNApp.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
v.vibrate(VibrationEffect.createOneShot(1500, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (ns.EnableLED) { } // no LED in Android-O -- configure via Channel
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,56 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.service;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SoundService
|
||||||
|
{
|
||||||
|
private static MediaPlayer mpLast = null;
|
||||||
|
|
||||||
|
public static void play(boolean enableSound, String soundSource, boolean forceVolume, int forceVolumeValue, boolean loop)
|
||||||
|
{
|
||||||
|
if (!enableSound) return;
|
||||||
|
if (Str.isNullOrWhitespace(soundSource)) return;
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
if (forceVolume)
|
||||||
|
{
|
||||||
|
AudioManager aman = (AudioManager) SCNApp.getContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
int maxVolume = aman.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION);
|
||||||
|
aman.setStreamVolume(AudioManager.STREAM_NOTIFICATION, (int)(maxVolume * (forceVolumeValue / 100.0)), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MediaPlayer player = new MediaPlayer();
|
||||||
|
player.setAudioAttributes(new AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_NOTIFICATION).build());
|
||||||
|
player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
|
||||||
|
player.setDataSource(SCNApp.getContext(), Uri.parse(soundSource));
|
||||||
|
player.setLooping(loop);
|
||||||
|
player.setOnCompletionListener( mp -> { mp.stop(); mp.release(); });
|
||||||
|
player.setOnSeekCompleteListener(mp -> { mp.stop(); mp.release(); });
|
||||||
|
player.prepare();
|
||||||
|
player.start();
|
||||||
|
mpLast = player;
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
Log.e("Sound::play", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stop()
|
||||||
|
{
|
||||||
|
if (mpLast != null && mpLast.isPlaying()) { mpLast.stop(); mpLast.release(); mpLast = null; }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,77 @@
|
|||||||
|
package com.blackforestbytes.simplecloudnotifier.util;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.view.MessageAdapter;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
public class MessageAdapterTouchHelper extends ItemTouchHelper.SimpleCallback
|
||||||
|
{
|
||||||
|
private MessageAdapterTouchHelperListener listener;
|
||||||
|
|
||||||
|
public MessageAdapterTouchHelper(int dragDirs, int swipeDirs, MessageAdapterTouchHelperListener listener)
|
||||||
|
{
|
||||||
|
super(dragDirs, swipeDirs);
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)
|
||||||
|
{
|
||||||
|
if (viewHolder != null)
|
||||||
|
{
|
||||||
|
final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground;
|
||||||
|
|
||||||
|
getDefaultUIUtil().onSelected(foregroundView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)
|
||||||
|
{
|
||||||
|
final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground;
|
||||||
|
getDefaultUIUtil().onDrawOver(c, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder)
|
||||||
|
{
|
||||||
|
final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground;
|
||||||
|
getDefaultUIUtil().clearView(foregroundView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)
|
||||||
|
{
|
||||||
|
final View foregroundView = ((MessageAdapter.MessagePresenter) viewHolder).viewForeground;
|
||||||
|
|
||||||
|
getDefaultUIUtil().onDraw(c, recyclerView, foregroundView, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction)
|
||||||
|
{
|
||||||
|
listener.onSwiped(viewHolder, direction, viewHolder.getAdapterPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int convertToAbsoluteDirection(int flags, int layoutDirection)
|
||||||
|
{
|
||||||
|
return super.convertToAbsoluteDirection(flags, layoutDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MessageAdapterTouchHelperListener
|
||||||
|
{
|
||||||
|
void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,10 @@
|
|||||||
package com.blackforestbytes.simplecloudnotifier.view;
|
package com.blackforestbytes.simplecloudnotifier.view;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -21,6 +23,7 @@ import net.glxn.qrgen.android.QRCode;
|
|||||||
import net.glxn.qrgen.core.image.ImageType;
|
import net.glxn.qrgen.core.image.ImageType;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import static android.content.Context.CLIPBOARD_SERVICE;
|
import static android.content.Context.CLIPBOARD_SERVICE;
|
||||||
@@ -55,15 +58,47 @@ public class AccountFragment extends Fragment
|
|||||||
|
|
||||||
v.findViewById(R.id.btnAccountReset).setOnClickListener(cv ->
|
v.findViewById(R.id.btnAccountReset).setOnClickListener(cv ->
|
||||||
{
|
{
|
||||||
|
Activity a = getActivity();
|
||||||
|
if (a == null) return;
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(a);
|
||||||
|
|
||||||
|
builder.setTitle("Confirm");
|
||||||
|
builder.setMessage("Reset account key?");
|
||||||
|
|
||||||
|
builder.setPositiveButton("YES", (dialog, which) -> {
|
||||||
View lpnl = v.findViewById(R.id.loadingPanel);
|
View lpnl = v.findViewById(R.id.loadingPanel);
|
||||||
lpnl.setVisibility(View.VISIBLE);
|
lpnl.setVisibility(View.VISIBLE);
|
||||||
SCNSettings.inst().reset(lpnl);
|
SCNSettings.inst().reset(lpnl);
|
||||||
|
dialog.dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.setNegativeButton("NO", (dialog, which) -> dialog.dismiss());
|
||||||
|
|
||||||
|
AlertDialog alert = builder.create();
|
||||||
|
alert.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
v.findViewById(R.id.btnClearLocalStorage).setOnClickListener(cv ->
|
v.findViewById(R.id.btnClearLocalStorage).setOnClickListener(cv ->
|
||||||
{
|
{
|
||||||
|
Activity a = getActivity();
|
||||||
|
if (a == null) return;
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(a);
|
||||||
|
|
||||||
|
builder.setTitle("Confirm");
|
||||||
|
builder.setMessage("Clear local messages?");
|
||||||
|
|
||||||
|
builder.setPositiveButton("YES", (dialog, which) -> {
|
||||||
CMessageList.inst().clear();
|
CMessageList.inst().clear();
|
||||||
SCNApp.showToast("Notifications cleared", 1000);
|
SCNApp.showToast("Notifications cleared", 1000);
|
||||||
|
dialog.dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.setNegativeButton("NO", (dialog, which) -> dialog.dismiss());
|
||||||
|
|
||||||
|
AlertDialog alert = builder.create();
|
||||||
|
alert.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
v.findViewById(R.id.btnQR).setOnClickListener(cv ->
|
v.findViewById(R.id.btnQR).setOnClickListener(cv ->
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package com.blackforestbytes.simplecloudnotifier.view;
|
package com.blackforestbytes.simplecloudnotifier.view;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
|
||||||
import com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
@@ -18,6 +19,7 @@ import androidx.viewpager.widget.ViewPager;
|
|||||||
public class MainActivity extends AppCompatActivity
|
public class MainActivity extends AppCompatActivity
|
||||||
{
|
{
|
||||||
public TabAdapter adpTabs;
|
public TabAdapter adpTabs;
|
||||||
|
public RelativeLayout layoutRoot;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
@@ -28,6 +30,8 @@ public class MainActivity extends AppCompatActivity
|
|||||||
NotificationService.inst();
|
NotificationService.inst();
|
||||||
CMessageList.inst();
|
CMessageList.inst();
|
||||||
|
|
||||||
|
layoutRoot = findViewById(R.id.layoutRoot);
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
@@ -39,6 +43,22 @@ public class MainActivity extends AppCompatActivity
|
|||||||
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
|
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
|
||||||
tabLayout.setupWithViewPager(viewPager);
|
tabLayout.setupWithViewPager(viewPager);
|
||||||
|
|
||||||
|
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { /* */ }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageSelected(int position)
|
||||||
|
{
|
||||||
|
if (position != 2) adpTabs.tab3.onViewpagerHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageScrollStateChanged(int state) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
SCNApp.register(this);
|
SCNApp.register(this);
|
||||||
IABService.startup(this);
|
IABService.startup(this);
|
||||||
SCNSettings.inst().work(this);
|
SCNSettings.inst().work(this);
|
||||||
|
@@ -4,22 +4,36 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
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 java.lang.ref.WeakReference;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
public class MessageAdapter extends RecyclerView.Adapter
|
public class MessageAdapter extends RecyclerView.Adapter
|
||||||
{
|
{
|
||||||
private final View vNoElements;
|
private final View vNoElements;
|
||||||
|
private final LinearLayoutManager manLayout;
|
||||||
|
private final RecyclerView viewRecycler;
|
||||||
|
|
||||||
public MessageAdapter(View noElementsView)
|
private WeakHashMap<MessagePresenter, Boolean> viewHolders = new WeakHashMap<>();
|
||||||
|
|
||||||
|
public MessageAdapter(View noElementsView, LinearLayoutManager layout, RecyclerView recycler)
|
||||||
{
|
{
|
||||||
vNoElements = noElementsView;
|
vNoElements = noElementsView;
|
||||||
|
manLayout = layout;
|
||||||
|
viewRecycler = recycler;
|
||||||
CMessageList.inst().register(this);
|
CMessageList.inst().register(this);
|
||||||
|
|
||||||
vNoElements.setVisibility(getItemCount()>0 ? View.GONE : View.VISIBLE);
|
vNoElements.setVisibility(getItemCount()>0 ? View.GONE : View.VISIBLE);
|
||||||
@@ -36,9 +50,18 @@ public class MessageAdapter extends RecyclerView.Adapter
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position)
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position)
|
||||||
{
|
{
|
||||||
CMessage msg = CMessageList.inst().tryGet(position);
|
CMessage msg = CMessageList.inst().tryGetFromBack(position);
|
||||||
MessagePresenter view = (MessagePresenter) holder;
|
MessagePresenter view = (MessagePresenter) holder;
|
||||||
view.setMessage(msg);
|
view.setMessage(msg);
|
||||||
|
|
||||||
|
viewHolders.put(view, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder)
|
||||||
|
{
|
||||||
|
if (holder instanceof MessagePresenter) viewHolders.remove(holder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -59,13 +82,33 @@ public class MessageAdapter extends RecyclerView.Adapter
|
|||||||
vNoElements.setVisibility(getItemCount()>0 ? View.GONE : View.VISIBLE);
|
vNoElements.setVisibility(getItemCount()>0 ? View.GONE : View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MessagePresenter extends RecyclerView.ViewHolder implements View.OnClickListener
|
public void scrollToTop()
|
||||||
|
{
|
||||||
|
manLayout.smoothScrollToPosition(viewRecycler, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeItem(int position)
|
||||||
|
{
|
||||||
|
CMessageList.inst().remove(position);
|
||||||
|
notifyItemRemoved(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restoreItem(CMessage item, int position)
|
||||||
|
{
|
||||||
|
CMessageList.inst().insert(position, item);
|
||||||
|
notifyItemInserted(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessagePresenter extends RecyclerView.ViewHolder implements View.OnClickListener
|
||||||
{
|
{
|
||||||
private TextView tvTimestamp;
|
private TextView tvTimestamp;
|
||||||
private TextView tvTitle;
|
private TextView tvTitle;
|
||||||
private TextView tvMessage;
|
private TextView tvMessage;
|
||||||
private ImageView ivPriority;
|
private ImageView ivPriority;
|
||||||
|
|
||||||
|
public RelativeLayout viewForeground;
|
||||||
|
public RelativeLayout viewBackground;
|
||||||
|
|
||||||
private CMessage data;
|
private CMessage data;
|
||||||
|
|
||||||
MessagePresenter(View itemView)
|
MessagePresenter(View itemView)
|
||||||
@@ -75,7 +118,15 @@ public class MessageAdapter extends RecyclerView.Adapter
|
|||||||
tvTitle = itemView.findViewById(R.id.tvTitle);
|
tvTitle = itemView.findViewById(R.id.tvTitle);
|
||||||
tvMessage = itemView.findViewById(R.id.tvMessage);
|
tvMessage = itemView.findViewById(R.id.tvMessage);
|
||||||
ivPriority = itemView.findViewById(R.id.ivPriority);
|
ivPriority = itemView.findViewById(R.id.ivPriority);
|
||||||
|
viewForeground = itemView.findViewById(R.id.layoutFront);
|
||||||
|
viewBackground = itemView.findViewById(R.id.layoutBack);
|
||||||
|
|
||||||
itemView.setOnClickListener(this);
|
itemView.setOnClickListener(this);
|
||||||
|
tvTimestamp.setOnClickListener(this);
|
||||||
|
tvTitle.setOnClickListener(this);
|
||||||
|
tvMessage.setOnClickListener(this);
|
||||||
|
ivPriority.setOnClickListener(this);
|
||||||
|
viewForeground.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMessage(CMessage msg)
|
void setMessage(CMessage msg)
|
||||||
@@ -105,7 +156,16 @@ public class MessageAdapter extends RecyclerView.Adapter
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v)
|
public void onClick(View v)
|
||||||
{
|
{
|
||||||
//SCNApp.showToast(data.Title, Toast.LENGTH_LONG);
|
for (MessagePresenter holder : MessageAdapter.this.viewHolders.keySet())
|
||||||
|
{
|
||||||
|
if (holder == null) continue;
|
||||||
|
if (holder == this) continue;
|
||||||
|
if (holder.tvMessage == null) continue;
|
||||||
|
if (holder.tvMessage.getMaxLines() == 6) continue;
|
||||||
|
holder.tvMessage.setMaxLines(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
tvMessage.setMaxLines(9999);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,24 +1,32 @@
|
|||||||
package com.blackforestbytes.simplecloudnotifier.view;
|
package com.blackforestbytes.simplecloudnotifier.view;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
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 com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
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.google.android.gms.ads.doubleclick.PublisherAdRequest;
|
import com.google.android.gms.ads.doubleclick.PublisherAdRequest;
|
||||||
import com.google.android.gms.ads.doubleclick.PublisherAdView;
|
import com.google.android.gms.ads.doubleclick.PublisherAdView;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
public class NotificationsFragment extends Fragment
|
public class NotificationsFragment extends Fragment implements MessageAdapterTouchHelper.MessageAdapterTouchHelperListener
|
||||||
{
|
{
|
||||||
private PublisherAdView adView;
|
private PublisherAdView adView;
|
||||||
|
private MessageAdapter adpMessages;
|
||||||
|
|
||||||
public NotificationsFragment()
|
public NotificationsFragment()
|
||||||
{
|
{
|
||||||
@@ -31,8 +39,12 @@ public class NotificationsFragment extends Fragment
|
|||||||
View v = inflater.inflate(R.layout.fragment_notifications, container, false);
|
View v = inflater.inflate(R.layout.fragment_notifications, container, false);
|
||||||
|
|
||||||
RecyclerView rvMessages = v.findViewById(R.id.rvMessages);
|
RecyclerView rvMessages = v.findViewById(R.id.rvMessages);
|
||||||
rvMessages.setLayoutManager(new LinearLayoutManager(this.getContext(), RecyclerView.VERTICAL, true));
|
LinearLayoutManager lman = new LinearLayoutManager(this.getContext(), RecyclerView.VERTICAL, false);
|
||||||
rvMessages.setAdapter(new MessageAdapter(v.findViewById(R.id.tvNoElements)));
|
rvMessages.setLayoutManager(lman);
|
||||||
|
rvMessages.setAdapter(adpMessages = new MessageAdapter(v.findViewById(R.id.tvNoElements), lman, rvMessages));
|
||||||
|
|
||||||
|
ItemTouchHelper.SimpleCallback itemTouchHelperCallback = new MessageAdapterTouchHelper(0, ItemTouchHelper.LEFT, this);
|
||||||
|
new ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(rvMessages);
|
||||||
|
|
||||||
adView = v.findViewById(R.id.adBanner);
|
adView = v.findViewById(R.id.adBanner);
|
||||||
PublisherAdRequest adRequest = new PublisherAdRequest.Builder().build();
|
PublisherAdRequest adRequest = new PublisherAdRequest.Builder().build();
|
||||||
@@ -45,6 +57,25 @@ public class NotificationsFragment extends Fragment
|
|||||||
|
|
||||||
public void updateProState()
|
public void updateProState()
|
||||||
{
|
{
|
||||||
adView.setVisibility(IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE) != null ? View.GONE : View.VISIBLE);
|
if (adView != null) adView.setVisibility(IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE) != null ? View.GONE : View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction, int position)
|
||||||
|
{
|
||||||
|
if (viewHolder instanceof MessageAdapter.MessagePresenter)
|
||||||
|
{
|
||||||
|
final CMessage deletedItem = CMessageList.inst().tryGet(viewHolder.getAdapterPosition());
|
||||||
|
final int deletedIndex = viewHolder.getAdapterPosition();
|
||||||
|
|
||||||
|
String name = deletedItem.Title;
|
||||||
|
|
||||||
|
adpMessages.removeItem(viewHolder.getAdapterPosition());
|
||||||
|
|
||||||
|
Snackbar snackbar = Snackbar.make(SCNApp.getMainActivity().layoutRoot, name + " removed", Snackbar.LENGTH_LONG);
|
||||||
|
snackbar.setAction("UNDO", view -> adpMessages.restoreItem(deletedItem, deletedIndex));
|
||||||
|
snackbar.setActionTextColor(Color.YELLOW);
|
||||||
|
snackbar.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,16 @@
|
|||||||
package com.blackforestbytes.simplecloudnotifier.view;
|
package com.blackforestbytes.simplecloudnotifier.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.media.Ringtone;
|
||||||
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -11,18 +18,24 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
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 com.android.billingclient.api.Purchase;
|
import com.android.billingclient.api.Purchase;
|
||||||
import com.blackforestbytes.simplecloudnotifier.R;
|
import com.blackforestbytes.simplecloudnotifier.R;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.android.ThreadUtils;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.lambda.FI;
|
||||||
|
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||||
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.service.NotificationService;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import top.defaults.colorpicker.ColorPickerPopup;
|
import top.defaults.colorpicker.ColorPickerPopup;
|
||||||
@@ -45,6 +58,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
private View prefMsgLowLedColor_container;
|
private View prefMsgLowLedColor_container;
|
||||||
private ImageView prefMsgLowLedColor_value;
|
private ImageView prefMsgLowLedColor_value;
|
||||||
private Switch prefMsgLowEnableVibrations;
|
private Switch prefMsgLowEnableVibrations;
|
||||||
|
private Switch prefMsgLowForceVolume;
|
||||||
|
private SeekBar prefMsgLowVolume;
|
||||||
|
private ImageView prefMsgLowVolumeTest;
|
||||||
|
|
||||||
private Switch prefMsgNormEnableSound;
|
private Switch prefMsgNormEnableSound;
|
||||||
private TextView prefMsgNormRingtone_value;
|
private TextView prefMsgNormRingtone_value;
|
||||||
@@ -54,6 +70,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
private View prefMsgNormLedColor_container;
|
private View prefMsgNormLedColor_container;
|
||||||
private ImageView prefMsgNormLedColor_value;
|
private ImageView prefMsgNormLedColor_value;
|
||||||
private Switch prefMsgNormEnableVibrations;
|
private Switch prefMsgNormEnableVibrations;
|
||||||
|
private Switch prefMsgNormForceVolume;
|
||||||
|
private SeekBar prefMsgNormVolume;
|
||||||
|
private ImageView prefMsgNormVolumeTest;
|
||||||
|
|
||||||
private Switch prefMsgHighEnableSound;
|
private Switch prefMsgHighEnableSound;
|
||||||
private TextView prefMsgHighRingtone_value;
|
private TextView prefMsgHighRingtone_value;
|
||||||
@@ -63,9 +82,14 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
private View prefMsgHighLedColor_container;
|
private View prefMsgHighLedColor_container;
|
||||||
private ImageView prefMsgHighLedColor_value;
|
private ImageView prefMsgHighLedColor_value;
|
||||||
private Switch prefMsgHighEnableVibrations;
|
private Switch prefMsgHighEnableVibrations;
|
||||||
|
private Switch prefMsgHighForceVolume;
|
||||||
|
private SeekBar prefMsgHighVolume;
|
||||||
|
private ImageView prefMsgHighVolumeTest;
|
||||||
|
|
||||||
private int musicPickerSwitch = -1;
|
private int musicPickerSwitch = -1;
|
||||||
|
|
||||||
|
private MediaPlayer[] mPlayers = new MediaPlayer[3];
|
||||||
|
|
||||||
public SettingsFragment()
|
public SettingsFragment()
|
||||||
{
|
{
|
||||||
// Required empty public constructor
|
// Required empty public constructor
|
||||||
@@ -99,6 +123,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefMsgLowLedColor_value = v.findViewById(R.id.prefMsgLowLedColor_value);
|
prefMsgLowLedColor_value = v.findViewById(R.id.prefMsgLowLedColor_value);
|
||||||
prefMsgLowLedColor_container = v.findViewById(R.id.prefMsgLowLedColor_container);
|
prefMsgLowLedColor_container = v.findViewById(R.id.prefMsgLowLedColor_container);
|
||||||
prefMsgLowEnableVibrations = v.findViewById(R.id.prefMsgLowEnableVibrations);
|
prefMsgLowEnableVibrations = v.findViewById(R.id.prefMsgLowEnableVibrations);
|
||||||
|
prefMsgLowForceVolume = v.findViewById(R.id.prefMsgLowForceVolume);
|
||||||
|
prefMsgLowVolume = v.findViewById(R.id.prefMsgLowVolume);
|
||||||
|
prefMsgLowVolumeTest = v.findViewById(R.id.btnLowVolumeTest);
|
||||||
|
|
||||||
prefMsgNormEnableSound = v.findViewById(R.id.prefMsgNormEnableSound);
|
prefMsgNormEnableSound = v.findViewById(R.id.prefMsgNormEnableSound);
|
||||||
prefMsgNormRingtone_value = v.findViewById(R.id.prefMsgNormRingtone_value);
|
prefMsgNormRingtone_value = v.findViewById(R.id.prefMsgNormRingtone_value);
|
||||||
@@ -108,6 +135,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefMsgNormLedColor_value = v.findViewById(R.id.prefMsgNormLedColor_value);
|
prefMsgNormLedColor_value = v.findViewById(R.id.prefMsgNormLedColor_value);
|
||||||
prefMsgNormLedColor_container = v.findViewById(R.id.prefMsgNormLedColor_container);
|
prefMsgNormLedColor_container = v.findViewById(R.id.prefMsgNormLedColor_container);
|
||||||
prefMsgNormEnableVibrations = v.findViewById(R.id.prefMsgNormEnableVibrations);
|
prefMsgNormEnableVibrations = v.findViewById(R.id.prefMsgNormEnableVibrations);
|
||||||
|
prefMsgNormForceVolume = v.findViewById(R.id.prefMsgNormForceVolume);
|
||||||
|
prefMsgNormVolume = v.findViewById(R.id.prefMsgNormVolume);
|
||||||
|
prefMsgNormVolumeTest = v.findViewById(R.id.btnNormVolumeTest);
|
||||||
|
|
||||||
prefMsgHighEnableSound = v.findViewById(R.id.prefMsgHighEnableSound);
|
prefMsgHighEnableSound = v.findViewById(R.id.prefMsgHighEnableSound);
|
||||||
prefMsgHighRingtone_value = v.findViewById(R.id.prefMsgHighRingtone_value);
|
prefMsgHighRingtone_value = v.findViewById(R.id.prefMsgHighRingtone_value);
|
||||||
@@ -117,6 +147,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefMsgHighLedColor_value = v.findViewById(R.id.prefMsgHighLedColor_value);
|
prefMsgHighLedColor_value = v.findViewById(R.id.prefMsgHighLedColor_value);
|
||||||
prefMsgHighLedColor_container = v.findViewById(R.id.prefMsgHighLedColor_container);
|
prefMsgHighLedColor_container = v.findViewById(R.id.prefMsgHighLedColor_container);
|
||||||
prefMsgHighEnableVibrations = v.findViewById(R.id.prefMsgHighEnableVibrations);
|
prefMsgHighEnableVibrations = v.findViewById(R.id.prefMsgHighEnableVibrations);
|
||||||
|
prefMsgHighForceVolume = v.findViewById(R.id.prefMsgHighForceVolume);
|
||||||
|
prefMsgHighVolume = v.findViewById(R.id.prefMsgHighVolume);
|
||||||
|
prefMsgHighVolumeTest = v.findViewById(R.id.btnHighVolumeTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUI()
|
private void updateUI()
|
||||||
@@ -142,6 +175,12 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
if (prefMsgLowEnableLED.isChecked() != s.PriorityLow.EnableLED) prefMsgLowEnableLED.setChecked(s.PriorityLow.EnableLED);
|
if (prefMsgLowEnableLED.isChecked() != s.PriorityLow.EnableLED) prefMsgLowEnableLED.setChecked(s.PriorityLow.EnableLED);
|
||||||
prefMsgLowLedColor_value.setColorFilter(s.PriorityLow.LEDColor);
|
prefMsgLowLedColor_value.setColorFilter(s.PriorityLow.LEDColor);
|
||||||
if (prefMsgLowEnableVibrations.isChecked() != s.PriorityLow.EnableVibration) prefMsgLowEnableVibrations.setChecked(s.PriorityLow.EnableVibration);
|
if (prefMsgLowEnableVibrations.isChecked() != s.PriorityLow.EnableVibration) prefMsgLowEnableVibrations.setChecked(s.PriorityLow.EnableVibration);
|
||||||
|
if (prefMsgLowForceVolume.isChecked() != s.PriorityLow.ForceVolume) prefMsgLowForceVolume.setChecked(s.PriorityLow.ForceVolume);
|
||||||
|
if (prefMsgLowVolume.getMax() != 100) prefMsgLowVolume.setMax(100);
|
||||||
|
if (prefMsgLowVolume.getProgress() != s.PriorityLow.ForceVolumeValue) prefMsgLowVolume.setProgress(s.PriorityLow.ForceVolumeValue);
|
||||||
|
if (prefMsgLowVolume.isEnabled() != s.PriorityLow.ForceVolume) prefMsgLowVolume.setEnabled(s.PriorityLow.ForceVolume);
|
||||||
|
if (prefMsgLowVolumeTest.isEnabled() != s.PriorityLow.ForceVolume) prefMsgLowVolumeTest.setEnabled(s.PriorityLow.ForceVolume);
|
||||||
|
if (s.PriorityLow.ForceVolume) prefMsgLowVolumeTest.setColorFilter(null); else prefMsgLowVolumeTest.setColorFilter(Color.argb(150,200,200,200));
|
||||||
|
|
||||||
if (prefMsgNormEnableSound.isChecked() != s.PriorityNorm.EnableSound) prefMsgNormEnableSound.setChecked(s.PriorityNorm.EnableSound);
|
if (prefMsgNormEnableSound.isChecked() != s.PriorityNorm.EnableSound) prefMsgNormEnableSound.setChecked(s.PriorityNorm.EnableSound);
|
||||||
if (!prefMsgNormRingtone_value.getText().equals(s.PriorityNorm.SoundName)) prefMsgNormRingtone_value.setText(s.PriorityNorm.SoundName);
|
if (!prefMsgNormRingtone_value.getText().equals(s.PriorityNorm.SoundName)) prefMsgNormRingtone_value.setText(s.PriorityNorm.SoundName);
|
||||||
@@ -149,6 +188,12 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
if (prefMsgNormEnableLED.isChecked() != s.PriorityNorm.EnableLED) prefMsgNormEnableLED.setChecked(s.PriorityNorm.EnableLED);
|
if (prefMsgNormEnableLED.isChecked() != s.PriorityNorm.EnableLED) prefMsgNormEnableLED.setChecked(s.PriorityNorm.EnableLED);
|
||||||
prefMsgNormLedColor_value.setColorFilter(s.PriorityNorm.LEDColor);
|
prefMsgNormLedColor_value.setColorFilter(s.PriorityNorm.LEDColor);
|
||||||
if (prefMsgNormEnableVibrations.isChecked() != s.PriorityNorm.EnableVibration) prefMsgNormEnableVibrations.setChecked(s.PriorityNorm.EnableVibration);
|
if (prefMsgNormEnableVibrations.isChecked() != s.PriorityNorm.EnableVibration) prefMsgNormEnableVibrations.setChecked(s.PriorityNorm.EnableVibration);
|
||||||
|
if (prefMsgNormForceVolume.isChecked() != s.PriorityNorm.ForceVolume) prefMsgNormForceVolume.setChecked(s.PriorityNorm.ForceVolume);
|
||||||
|
if (prefMsgNormVolume.getMax() != 100) prefMsgNormVolume.setMax(100);
|
||||||
|
if (prefMsgNormVolume.getProgress() != s.PriorityNorm.ForceVolumeValue) prefMsgNormVolume.setProgress(s.PriorityNorm.ForceVolumeValue);
|
||||||
|
if (prefMsgNormVolume.isEnabled() != s.PriorityNorm.ForceVolume) prefMsgNormVolume.setEnabled(s.PriorityNorm.ForceVolume);
|
||||||
|
if (prefMsgNormVolumeTest.isEnabled() != s.PriorityNorm.ForceVolume) prefMsgNormVolumeTest.setEnabled(s.PriorityNorm.ForceVolume);
|
||||||
|
if (s.PriorityNorm.ForceVolume) prefMsgNormVolumeTest.setColorFilter(null); else prefMsgNormVolumeTest.setColorFilter(Color.argb(150,200,200,200));
|
||||||
|
|
||||||
if (prefMsgHighEnableSound.isChecked() != s.PriorityHigh.EnableSound) prefMsgHighEnableSound.setChecked(s.PriorityHigh.EnableSound);
|
if (prefMsgHighEnableSound.isChecked() != s.PriorityHigh.EnableSound) prefMsgHighEnableSound.setChecked(s.PriorityHigh.EnableSound);
|
||||||
if (!prefMsgHighRingtone_value.getText().equals(s.PriorityHigh.SoundName)) prefMsgHighRingtone_value.setText(s.PriorityHigh.SoundName);
|
if (!prefMsgHighRingtone_value.getText().equals(s.PriorityHigh.SoundName)) prefMsgHighRingtone_value.setText(s.PriorityHigh.SoundName);
|
||||||
@@ -156,6 +201,12 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
if (prefMsgHighEnableLED.isChecked() != s.PriorityHigh.EnableLED) prefMsgHighEnableLED.setChecked(s.PriorityHigh.EnableLED);
|
if (prefMsgHighEnableLED.isChecked() != s.PriorityHigh.EnableLED) prefMsgHighEnableLED.setChecked(s.PriorityHigh.EnableLED);
|
||||||
prefMsgHighLedColor_value.setColorFilter(s.PriorityHigh.LEDColor);
|
prefMsgHighLedColor_value.setColorFilter(s.PriorityHigh.LEDColor);
|
||||||
if (prefMsgHighEnableVibrations.isChecked() != s.PriorityHigh.EnableVibration) prefMsgHighEnableVibrations.setChecked(s.PriorityHigh.EnableVibration);
|
if (prefMsgHighEnableVibrations.isChecked() != s.PriorityHigh.EnableVibration) prefMsgHighEnableVibrations.setChecked(s.PriorityHigh.EnableVibration);
|
||||||
|
if (prefMsgHighForceVolume.isChecked() != s.PriorityHigh.ForceVolume) prefMsgHighForceVolume.setChecked(s.PriorityHigh.ForceVolume);
|
||||||
|
if (prefMsgHighVolume.getMax() != 100) prefMsgHighVolume.setMax(100);
|
||||||
|
if (prefMsgHighVolume.getProgress() != s.PriorityHigh.ForceVolumeValue) prefMsgHighVolume.setProgress(s.PriorityHigh.ForceVolumeValue);
|
||||||
|
if (prefMsgHighVolume.isEnabled() != s.PriorityHigh.ForceVolume) prefMsgHighVolume.setEnabled(s.PriorityHigh.ForceVolume);
|
||||||
|
if (prefMsgHighVolumeTest.isEnabled() != s.PriorityHigh.ForceVolume) prefMsgHighVolumeTest.setEnabled(s.PriorityHigh.ForceVolume);
|
||||||
|
if (s.PriorityHigh.ForceVolume) prefMsgHighVolumeTest.setColorFilter(null); else prefMsgHighVolumeTest.setColorFilter(Color.argb(150,200,200,200));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initListener()
|
private void initListener()
|
||||||
@@ -181,6 +232,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefMsgLowEnableLED.setOnCheckedChangeListener((a,b) -> { s.PriorityLow.EnableLED=b; saveAndUpdate(); });
|
prefMsgLowEnableLED.setOnCheckedChangeListener((a,b) -> { s.PriorityLow.EnableLED=b; saveAndUpdate(); });
|
||||||
prefMsgLowLedColor_container.setOnClickListener(a -> chooseLEDColorLow());
|
prefMsgLowLedColor_container.setOnClickListener(a -> chooseLEDColorLow());
|
||||||
prefMsgLowEnableVibrations.setOnCheckedChangeListener((a,b) -> { s.PriorityLow.EnableVibration=b; saveAndUpdate(); });
|
prefMsgLowEnableVibrations.setOnCheckedChangeListener((a,b) -> { s.PriorityLow.EnableVibration=b; saveAndUpdate(); });
|
||||||
|
prefMsgLowForceVolume.setOnCheckedChangeListener((a,b) -> { s.PriorityLow.ForceVolume=b; saveAndUpdate(); });
|
||||||
|
prefMsgLowVolume.setOnSeekBarChangeListener(FI.SeekBarChanged((a,b,c) -> { if (c) { s.PriorityLow.ForceVolumeValue=b; saveAndUpdate(); updateVolume(0, b); } }));
|
||||||
|
prefMsgLowVolumeTest.setOnClickListener((v) -> { if (s.PriorityLow.ForceVolume) playTestSound(0, prefMsgLowVolumeTest, s.PriorityLow.SoundSource, s.PriorityLow.ForceVolumeValue); });
|
||||||
|
|
||||||
prefMsgNormEnableSound.setOnCheckedChangeListener((a,b) -> { s.PriorityNorm.EnableSound=b; saveAndUpdate(); });
|
prefMsgNormEnableSound.setOnCheckedChangeListener((a,b) -> { s.PriorityNorm.EnableSound=b; saveAndUpdate(); });
|
||||||
prefMsgNormRingtone_container.setOnClickListener(a -> chooseRingtoneNorm());
|
prefMsgNormRingtone_container.setOnClickListener(a -> chooseRingtoneNorm());
|
||||||
@@ -188,6 +242,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefMsgNormEnableLED.setOnCheckedChangeListener((a,b) -> { s.PriorityNorm.EnableLED=b; saveAndUpdate(); });
|
prefMsgNormEnableLED.setOnCheckedChangeListener((a,b) -> { s.PriorityNorm.EnableLED=b; saveAndUpdate(); });
|
||||||
prefMsgNormLedColor_container.setOnClickListener(a -> chooseLEDColorNorm());
|
prefMsgNormLedColor_container.setOnClickListener(a -> chooseLEDColorNorm());
|
||||||
prefMsgNormEnableVibrations.setOnCheckedChangeListener((a,b) -> { s.PriorityNorm.EnableVibration=b; saveAndUpdate(); });
|
prefMsgNormEnableVibrations.setOnCheckedChangeListener((a,b) -> { s.PriorityNorm.EnableVibration=b; saveAndUpdate(); });
|
||||||
|
prefMsgNormForceVolume.setOnCheckedChangeListener((a,b) -> { s.PriorityNorm.ForceVolume=b; saveAndUpdate(); });
|
||||||
|
prefMsgNormVolume.setOnSeekBarChangeListener(FI.SeekBarChanged((a,b,c) -> { if (c) { s.PriorityNorm.ForceVolumeValue=b; saveAndUpdate(); updateVolume(1, b); } }));
|
||||||
|
prefMsgNormVolumeTest.setOnClickListener((v) -> { if (s.PriorityNorm.ForceVolume) playTestSound(1, prefMsgNormVolumeTest, s.PriorityNorm.SoundSource, s.PriorityNorm.ForceVolumeValue); });
|
||||||
|
|
||||||
prefMsgHighEnableSound.setOnCheckedChangeListener((a,b) -> { s.PriorityHigh.EnableSound=b; saveAndUpdate(); });
|
prefMsgHighEnableSound.setOnCheckedChangeListener((a,b) -> { s.PriorityHigh.EnableSound=b; saveAndUpdate(); });
|
||||||
prefMsgHighRingtone_container.setOnClickListener(a -> chooseRingtoneHigh());
|
prefMsgHighRingtone_container.setOnClickListener(a -> chooseRingtoneHigh());
|
||||||
@@ -195,13 +252,78 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
prefMsgHighEnableLED.setOnCheckedChangeListener((a,b) -> { s.PriorityHigh.EnableLED=b; saveAndUpdate(); });
|
prefMsgHighEnableLED.setOnCheckedChangeListener((a,b) -> { s.PriorityHigh.EnableLED=b; saveAndUpdate(); });
|
||||||
prefMsgHighLedColor_container.setOnClickListener(a -> chooseLEDColorHigh());
|
prefMsgHighLedColor_container.setOnClickListener(a -> chooseLEDColorHigh());
|
||||||
prefMsgHighEnableVibrations.setOnCheckedChangeListener((a,b) -> { s.PriorityHigh.EnableVibration=b; saveAndUpdate(); });
|
prefMsgHighEnableVibrations.setOnCheckedChangeListener((a,b) -> { s.PriorityHigh.EnableVibration=b; saveAndUpdate(); });
|
||||||
|
prefMsgHighForceVolume.setOnCheckedChangeListener((a,b) -> { s.PriorityHigh.ForceVolume=b; saveAndUpdate(); });
|
||||||
|
prefMsgHighVolume.setOnSeekBarChangeListener(FI.SeekBarChanged((a,b,c) -> { if (c) { s.PriorityHigh.ForceVolumeValue=b; saveAndUpdate(); updateVolume(2, b); } }));
|
||||||
|
prefMsgHighVolumeTest.setOnClickListener((v) -> { if (s.PriorityHigh.ForceVolume) playTestSound(2, prefMsgHighVolumeTest, s.PriorityHigh.SoundSource, s.PriorityHigh.ForceVolumeValue); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateVolume(int idx, int volume)
|
||||||
|
{
|
||||||
|
if (mPlayers[idx] != null && mPlayers[idx].isPlaying())
|
||||||
|
{
|
||||||
|
AudioManager aman = (AudioManager) SCNApp.getContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
int maxVolume = aman.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION);
|
||||||
|
aman.setStreamVolume(AudioManager.STREAM_NOTIFICATION, (int)(maxVolume * (volume / 100.0)), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopSound(final int idx, final ImageView iv)
|
||||||
|
{
|
||||||
|
if (mPlayers[idx] != null && mPlayers[idx].isPlaying())
|
||||||
|
{
|
||||||
|
mPlayers[idx].stop();
|
||||||
|
mPlayers[idx].release();
|
||||||
|
iv.setImageResource(R.drawable.ic_play);
|
||||||
|
mPlayers[idx] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playTestSound(final int idx, final ImageView iv, String src, int volume)
|
||||||
|
{
|
||||||
|
if (mPlayers[idx] != null && mPlayers[idx].isPlaying())
|
||||||
|
{
|
||||||
|
mPlayers[idx].stop();
|
||||||
|
mPlayers[idx].release();
|
||||||
|
iv.setImageResource(R.drawable.ic_play);
|
||||||
|
mPlayers[idx] = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Str.isNullOrWhitespace(src)) return;
|
||||||
|
if (volume == 0) return;
|
||||||
|
|
||||||
|
Context ctxt = getContext();
|
||||||
|
if (ctxt == null) return;
|
||||||
|
|
||||||
|
iv.setImageResource(R.drawable.ic_pause);
|
||||||
|
|
||||||
|
AudioManager aman = (AudioManager) SCNApp.getContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
int maxVolume = aman.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION);
|
||||||
|
aman.setStreamVolume(AudioManager.STREAM_NOTIFICATION, (int)(maxVolume * (volume / 100.0)), 0);
|
||||||
|
|
||||||
|
MediaPlayer player = mPlayers[idx] = new MediaPlayer();
|
||||||
|
player.setAudioAttributes(new AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_NOTIFICATION).build());
|
||||||
|
player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
player.setDataSource(ctxt, Uri.parse(src));
|
||||||
|
player.setLooping(false);
|
||||||
|
player.setOnCompletionListener( mp -> SCNApp.runOnUiThread(() -> { mp.stop(); iv.setImageResource(R.drawable.ic_play); mPlayers[idx]=null; mp.release(); }));
|
||||||
|
player.setOnSeekCompleteListener(mp -> SCNApp.runOnUiThread(() -> { mp.stop(); iv.setImageResource(R.drawable.ic_play); mPlayers[idx]=null; mp.release(); }));
|
||||||
|
player.prepare();
|
||||||
|
player.start();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
Log.e("SFRAG:play", e.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveAndUpdate()
|
private void saveAndUpdate()
|
||||||
{
|
{
|
||||||
SCNSettings.inst().save();
|
SCNSettings.inst().save();
|
||||||
updateUI();
|
updateUI();
|
||||||
NotificationService.inst().updateChannels();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUpgradeAccount()
|
private void onUpgradeAccount()
|
||||||
@@ -213,9 +335,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
{
|
{
|
||||||
Purchase p = IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE);
|
Purchase p = IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE);
|
||||||
|
|
||||||
prefUpgradeAccount.setVisibility( p != null ? View.GONE : View.VISIBLE);
|
if (prefUpgradeAccount != null) prefUpgradeAccount.setVisibility( p != null ? View.GONE : View.VISIBLE);
|
||||||
prefUpgradeAccount_info.setVisibility(p != null ? View.GONE : View.VISIBLE);
|
if (prefUpgradeAccount_info != null) prefUpgradeAccount_info.setVisibility(p != null ? View.GONE : View.VISIBLE);
|
||||||
prefUpgradeAccount_msg.setVisibility( p != null ? View.VISIBLE : View.GONE );
|
if (prefUpgradeAccount_msg != null) prefUpgradeAccount_msg.setVisibility( p != null ? View.VISIBLE : View.GONE );
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getCacheSizeIndex(int value)
|
private int getCacheSizeIndex(int value)
|
||||||
@@ -233,7 +355,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
UltimateMusicPicker ump = new UltimateMusicPicker();
|
UltimateMusicPicker ump = new UltimateMusicPicker();
|
||||||
ump.windowTitle("Choose notification sound");
|
ump.windowTitle("Choose notification sound");
|
||||||
ump.removeSilent();
|
ump.removeSilent();
|
||||||
ump.streamType(AudioManager.STREAM_ALARM);
|
ump.streamType(AudioManager.STREAM_NOTIFICATION);
|
||||||
ump.ringtone();
|
ump.ringtone();
|
||||||
ump.notification();
|
ump.notification();
|
||||||
ump.alarm();
|
ump.alarm();
|
||||||
@@ -248,7 +370,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
UltimateMusicPicker ump = new UltimateMusicPicker();
|
UltimateMusicPicker ump = new UltimateMusicPicker();
|
||||||
ump.windowTitle("Choose notification sound");
|
ump.windowTitle("Choose notification sound");
|
||||||
ump.removeSilent();
|
ump.removeSilent();
|
||||||
ump.streamType(AudioManager.STREAM_ALARM);
|
ump.streamType(AudioManager.STREAM_NOTIFICATION);
|
||||||
ump.ringtone();
|
ump.ringtone();
|
||||||
ump.notification();
|
ump.notification();
|
||||||
ump.alarm();
|
ump.alarm();
|
||||||
@@ -263,7 +385,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
UltimateMusicPicker ump = new UltimateMusicPicker();
|
UltimateMusicPicker ump = new UltimateMusicPicker();
|
||||||
ump.windowTitle("Choose notification sound");
|
ump.windowTitle("Choose notification sound");
|
||||||
ump.removeSilent();
|
ump.removeSilent();
|
||||||
ump.streamType(AudioManager.STREAM_ALARM);
|
ump.streamType(AudioManager.STREAM_NOTIFICATION);
|
||||||
ump.ringtone();
|
ump.ringtone();
|
||||||
ump.notification();
|
ump.notification();
|
||||||
ump.alarm();
|
ump.alarm();
|
||||||
@@ -356,4 +478,11 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
|||||||
{
|
{
|
||||||
musicPickerSwitch = -1;
|
musicPickerSwitch = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onViewpagerHide()
|
||||||
|
{
|
||||||
|
stopSound(0, prefMsgLowVolumeTest);
|
||||||
|
stopSound(1, prefMsgNormVolumeTest);
|
||||||
|
stopSound(2, prefMsgHighVolumeTest);
|
||||||
|
}
|
||||||
}
|
}
|
16
android/app/src/main/res/drawable/ic_pause.xml
Normal file
16
android/app/src/main/res/drawable/ic_pause.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<vector
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportHeight="438.536"
|
||||||
|
android:viewportWidth="438.536"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF3F51B5"
|
||||||
|
android:pathData="M164.453,0H18.276C13.324,0 9.041,1.807 5.425,5.424C1.808,9.04 0.001,13.322 0.001,18.271v401.991c0,4.948 1.807,9.233 5.424,12.847c3.619,3.617 7.902,5.428 12.851,5.428h146.181c4.949,0 9.231,-1.811 12.847,-5.428c3.617,-3.613 5.424,-7.898 5.424,-12.847V18.271c0,-4.952 -1.807,-9.231 -5.428,-12.847C173.685,1.807 169.402,0 164.453,0z"/>
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF3F51B5"
|
||||||
|
android:pathData="M433.113,5.424C429.496,1.807 425.215,0 420.267,0H274.086c-4.949,0 -9.237,1.807 -12.847,5.424c-3.621,3.615 -5.432,7.898 -5.432,12.847v401.991c0,4.948 1.811,9.233 5.432,12.847c3.609,3.617 7.897,5.428 12.847,5.428h146.181c4.948,0 9.229,-1.811 12.847,-5.428c3.614,-3.613 5.421,-7.898 5.421,-12.847V18.271C438.534,13.319 436.73,9.04 433.113,5.424z"/>
|
||||||
|
|
||||||
|
</vector>
|
12
android/app/src/main/res/drawable/ic_play.xml
Normal file
12
android/app/src/main/res/drawable/ic_play.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<vector
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="41.999"
|
||||||
|
android:viewportWidth="41.999"
|
||||||
|
android:width="24dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF3F51B5"
|
||||||
|
android:pathData="M36.068,20.176l-29,-20C6.761,-0.035 6.363,-0.057 6.035,0.114C5.706,0.287 5.5,0.627 5.5,0.999v40c0,0.372 0.206,0.713 0.535,0.886c0.146,0.076 0.306,0.114 0.465,0.114c0.199,0 0.397,-0.06 0.568,-0.177l29,-20c0.271,-0.187 0.432,-0.494 0.432,-0.823S36.338,20.363 36.068,20.176z"/>
|
||||||
|
|
||||||
|
</vector>
|
16
android/app/src/main/res/drawable/ic_trash.xml
Normal file
16
android/app/src/main/res/drawable/ic_trash.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<vector
|
||||||
|
android:height="24dp"
|
||||||
|
android:width="24dp"
|
||||||
|
android:viewportHeight="53"
|
||||||
|
android:viewportWidth="53"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M42.943,6H33.5V3c0,-1.654 -1.346,-3 -3,-3h-8c-1.654,0 -3,1.346 -3,3v3h-9.443C8.096,6 6.5,7.596 6.5,9.557V14h2h36h2V9.557C46.5,7.596 44.904,6 42.943,6zM31.5,6h-10V3c0,-0.552 0.449,-1 1,-1h8c0.551,0 1,0.448 1,1V6z"/>
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M8.5,49.271C8.5,51.327 10.173,53 12.229,53h28.541c2.057,0 3.729,-1.673 3.729,-3.729V16h-36V49.271z"/>
|
||||||
|
|
||||||
|
</vector>
|
12
android/app/src/main/res/drawable/ic_volume.xml
Normal file
12
android/app/src/main/res/drawable/ic_volume.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<vector
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="459"
|
||||||
|
android:viewportWidth="459"
|
||||||
|
android:width="24dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF757575"
|
||||||
|
android:pathData="M0,153v153h102l127.5,127.5v-408L102,153H0zM344.25,229.5c0,-45.9 -25.5,-84.15 -63.75,-102v204C318.75,313.65 344.25,275.4 344.25,229.5zM280.5,5.1v53.55C354.45,81.6 408,147.899 408,229.5S354.45,377.4 280.5,400.35V453.9C382.5,430.949 459,339.15 459,229.5C459,119.85 382.5,28.049 280.5,5.1z"/>
|
||||||
|
|
||||||
|
</vector>
|
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
android:id="@+id/layoutRoot"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@@ -4,7 +4,6 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:ignore="TooManyViews"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".view.SettingsFragment">
|
tools:context=".view.SettingsFragment">
|
||||||
@@ -33,23 +32,14 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<Switch
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
android:id="@+id/prefAppEnabled"
|
android:id="@+id/prefAppEnabled"
|
||||||
android:text="@string/str_enabled"
|
android:text="@string/str_enabled"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:minHeight="48dp" />
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -67,7 +57,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvLocalCacheSize"
|
android:id="@+id/tvLocalCacheSize"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/str_localcachesize"
|
android:text="@string/str_localcachesize"
|
||||||
android:textColor="#000"
|
android:textColor="#000"
|
||||||
@@ -102,6 +92,7 @@
|
|||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center|center"
|
||||||
android:minHeight="48dp">
|
android:minHeight="48dp">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -151,23 +142,14 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgLowEnableSound"
|
android:id="@+id/prefMsgLowEnableSound"
|
||||||
android:text="@string/str_msg_enablesound"
|
android:text="@string/str_msg_enablesound"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"/>
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -176,20 +158,15 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/prefMsgLowRingtone_container"
|
android:id="@+id/prefMsgLowRingtone_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvMsgLowRingtone"
|
android:id="@+id/tvMsgLowRingtone"
|
||||||
@@ -206,9 +183,8 @@
|
|||||||
android:spinnerMode="dialog"
|
android:spinnerMode="dialog"
|
||||||
android:text="Whatever"
|
android:text="Whatever"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -217,22 +193,67 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgLowRepeatSound"
|
android:id="@+id/prefMsgLowRepeatSound"
|
||||||
android:text="@string/str_repeatnotificationsound"
|
android:text="@string/str_repeatnotificationsound"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/prefMsgLowForceVolume"
|
||||||
|
android:text="@string/str_forcevolume"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:columnCount="3"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icnLowVolume"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/volume_icon"
|
||||||
|
android:src="@drawable/ic_volume"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/prefMsgLowVolume"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@+id/btnLowVolumeTest"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/icnLowVolume"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnLowVolumeTest"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_play"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:contentDescription="@string/play_test_sound" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -242,23 +263,14 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgLowEnableLED"
|
android:id="@+id/prefMsgLowEnableLED"
|
||||||
android:text="@string/str_enable_led"
|
android:text="@string/str_enable_led"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -308,23 +320,15 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgLowEnableVibrations"
|
android:id="@+id/prefMsgLowEnableVibrations"
|
||||||
android:text="@string/str_enable_vibration"
|
android:text="@string/str_enable_vibration"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -349,23 +353,14 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgNormEnableSound"
|
android:id="@+id/prefMsgNormEnableSound"
|
||||||
android:text="@string/str_msg_enablesound"
|
android:text="@string/str_msg_enablesound"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -374,20 +369,15 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/prefMsgNormRingtone_container"
|
android:id="@+id/prefMsgNormRingtone_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tvMsgNormRingtone"
|
android:id="@+id/tvMsgNormRingtone"
|
||||||
@@ -406,6 +396,58 @@
|
|||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/prefMsgNormForceVolume"
|
||||||
|
android:text="@string/str_forcevolume"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:columnCount="3"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icnNormVolume"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/volume_icon"
|
||||||
|
android:src="@drawable/ic_volume"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/prefMsgNormVolume"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnNormVolumeTest"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/icnNormVolume"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnNormVolumeTest"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_play"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:contentDescription="@string/play_test_sound" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -415,23 +457,14 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgNormRepeatSound"
|
android:id="@+id/prefMsgNormRepeatSound"
|
||||||
android:text="@string/str_repeatnotificationsound"
|
android:text="@string/str_repeatnotificationsound"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -440,23 +473,14 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgNormEnableLED"
|
android:id="@+id/prefMsgNormEnableLED"
|
||||||
android:text="@string/str_enable_led"
|
android:text="@string/str_enable_led"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -506,23 +530,14 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgNormEnableVibrations"
|
android:id="@+id/prefMsgNormEnableVibrations"
|
||||||
android:text="@string/str_enable_vibration"
|
android:text="@string/str_enable_vibration"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -547,23 +562,14 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgHighEnableSound"
|
android:id="@+id/prefMsgHighEnableSound"
|
||||||
android:text="@string/str_msg_enablesound"
|
android:text="@string/str_msg_enablesound"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -572,18 +578,15 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/prefMsgHighRingtone_container"
|
android:id="@+id/prefMsgHighRingtone_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
@@ -604,6 +607,51 @@
|
|||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/prefMsgHighForceVolume"
|
||||||
|
android:text="@string/str_forcevolume"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:columnCount="3"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_marginEnd="4dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icnHighVolume"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/volume_icon"
|
||||||
|
android:src="@drawable/ic_volume"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/prefMsgHighVolume"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/btnHighVolumeTest"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/icnHighVolume"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnHighVolumeTest"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_play"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:contentDescription="@string/play_test_sound" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -613,23 +661,14 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgHighRepeatSound"
|
android:id="@+id/prefMsgHighRepeatSound"
|
||||||
android:text="@string/str_repeatnotificationsound"
|
android:text="@string/str_repeatnotificationsound"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -638,23 +677,14 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgHighEnableLED"
|
android:id="@+id/prefMsgHighEnableLED"
|
||||||
android:text="@string/str_enable_led"
|
android:text="@string/str_enable_led"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -704,23 +734,14 @@
|
|||||||
android:layout_marginTop="2dp"
|
android:layout_marginTop="2dp"
|
||||||
android:background="#c0c0c0"/>
|
android:background="#c0c0c0"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_marginStart="4dp"
|
|
||||||
android:layout_marginEnd="4dp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:minHeight="48dp">
|
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
android:id="@+id/prefMsgHighEnableVibrations"
|
android:id="@+id/prefMsgHighEnableVibrations"
|
||||||
android:text="@string/str_enable_vibration"
|
android:text="@string/str_enable_vibration"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:layout_marginStart="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginEnd="4dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@@ -1,9 +1,43 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/layoutBack"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_margin="@dimen/card_margin"
|
||||||
|
android:background="@color/bg_row_background">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/delete_icon"
|
||||||
|
android:layout_width="@dimen/ic_delete"
|
||||||
|
android:layout_height="@dimen/ic_delete"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginRight="@dimen/padd_10"
|
||||||
|
android:src="@drawable/ic_trash"
|
||||||
|
android:contentDescription="@string/delete" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginRight="@dimen/padd_10"
|
||||||
|
android:layout_toLeftOf="@id/delete_icon"
|
||||||
|
android:text="@string/delete"
|
||||||
|
android:textColor="#fff"
|
||||||
|
android:textSize="13dp" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/layoutFront"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/card_view"
|
android:id="@+id/card_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -55,8 +89,8 @@
|
|||||||
app:layout_constraintRight_toLeftOf="@+id/ivPriority"
|
app:layout_constraintRight_toLeftOf="@+id/ivPriority"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_margin="4sp"
|
android:layout_margin="4sp"
|
||||||
android:ellipsize="none"
|
android:ellipsize="end"
|
||||||
android:maxLines="32"
|
android:maxLines="6"
|
||||||
android:scrollHorizontally="false"
|
android:scrollHorizontally="false"
|
||||||
|
|
||||||
android:text="asdasd asdasd asdasd a" />
|
android:text="asdasd asdasd asdasd a" />
|
||||||
@@ -78,4 +112,6 @@
|
|||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
</LinearLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
@@ -7,4 +7,6 @@
|
|||||||
<color name="colorHeaderForeground">#FFFFFF</color>
|
<color name="colorHeaderForeground">#FFFFFF</color>
|
||||||
|
|
||||||
<color name="colorBlack">#000</color>
|
<color name="colorBlack">#000</color>
|
||||||
|
|
||||||
|
<color name="bg_row_background">#fa315b</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -2,4 +2,8 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<dimen name="card_margin">5dp</dimen>
|
<dimen name="card_margin">5dp</dimen>
|
||||||
<dimen name="card_album_radius">0dp</dimen>
|
<dimen name="card_album_radius">0dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="padd_10">10dp</dimen>
|
||||||
|
<dimen name="ic_delete">30dp</dimen>
|
||||||
|
<dimen name="thumbnail">90dp</dimen>
|
||||||
</resources>
|
</resources>
|
@@ -18,16 +18,20 @@
|
|||||||
<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 notifications locally</string>
|
||||||
<string name="str_header_prio0">Notifications (low priority)</string>
|
<string name="str_header_prio0">Notifications (priority 0 - Low)</string>
|
||||||
<string name="str_header_prio1">Notifications (normal priority)</string>
|
<string name="str_header_prio1">Notifications (priority 1 - Normal)</string>
|
||||||
<string name="str_header_prio2">Notifications (high priority)</string>
|
<string name="str_header_prio2">Notifications (priority 2 - High)</string>
|
||||||
<string name="str_msg_enablesound">Enable notification sound</string>
|
<string name="str_msg_enablesound">Enable notification sound</string>
|
||||||
<string name="str_notificationsound">Notification sound</string>
|
<string name="str_notificationsound">Notification sound</string>
|
||||||
<string name="str_repeatnotificationsound">Repeat notification sound</string>
|
<string name="str_repeatnotificationsound">Repeat notification sound</string>
|
||||||
|
<string name="str_forcevolume">Automatically set the volume</string>
|
||||||
<string name="str_enable_led">Enable notification light</string>
|
<string name="str_enable_led">Enable notification light</string>
|
||||||
<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_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="play_test_sound">Play test sound</string>
|
||||||
|
<string name="delete">DELETE</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
#Sun Nov 11 19:37:57 CET 2018
|
#Mon Nov 12 18:26:41 CET 2018
|
||||||
VERSION_NAME=0.0.5
|
VERSION_NAME=0.0.7
|
||||||
VERSION_CODE=5
|
VERSION_CODE=7
|
||||||
|
BIN
data/icon_web.pdn
Normal file
BIN
data/icon_web.pdn
Normal file
Binary file not shown.
@@ -8,13 +8,21 @@
|
|||||||
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.png"/>
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.ico"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mainpnl">
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
|
||||||
<a href="/index.php" class="button bordered" id="tr_link">Send</a>
|
|
||||||
|
|
||||||
<a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
<div id="copyinfo">
|
||||||
|
<a tabindex="-1" href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
||||||
|
<a tabindex="-1" href="https://www.mikescher.com">made by Mike Schwörer</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="mainpnl">
|
||||||
|
<a tabindex="-1" href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
||||||
|
<a tabindex="-1" href="/index.php" class="button bordered" id="tr_link">Send</a>
|
||||||
|
|
||||||
|
<a tabindex="-1" href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
||||||
|
|
||||||
<p>Get your user-id and user-key from the app and send notifications to your phone by performing a POST request against <code>https://simplecloudnotifier.blackforestbytes.com/send.php</code></p>
|
<p>Get your user-id and user-key from the app and send notifications to your phone by performing a POST request against <code>https://simplecloudnotifier.blackforestbytes.com/send.php</code></p>
|
||||||
<pre>curl \
|
<pre>curl \
|
||||||
@@ -32,12 +40,8 @@
|
|||||||
--data "title={message_title}" \
|
--data "title={message_title}" \
|
||||||
https://scn.blackforestbytes.com/send.php</pre>
|
https://scn.blackforestbytes.com/send.php</pre>
|
||||||
|
|
||||||
<a href="/index_more.php" class="button bordered tertiary" style="float: right; min-width: 100px; text-align: center">More</a>
|
<a href="/api_more.php" class="button bordered tertiary" style="float: right; min-width: 100px; text-align: center">More</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="copyinfo">
|
|
||||||
<a href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
2
web/api/.gitignore
vendored
Normal file
2
web/api/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
config.php
|
||||||
|
.verify_accesstoken
|
46
web/api/ack.php
Normal file
46
web/api/ack.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?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 ack 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']));
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('UPDATE messages SET ack=1 WHERE scn_message_id=:smid AND sender_user_id=:uid');
|
||||||
|
$stmt->execute(['smid' => $scn_msg_id, 'uid' => $user_id]);
|
||||||
|
|
||||||
|
api_return(200,
|
||||||
|
[
|
||||||
|
'success' => true,
|
||||||
|
'prev_ack' => $datas[0]['ack'],
|
||||||
|
'new_ack' => 1,
|
||||||
|
'message' => 'ok'
|
||||||
|
]);
|
@@ -15,7 +15,7 @@ $user_key = $INPUT['user_key'];
|
|||||||
|
|
||||||
$pdo = getDatabase();
|
$pdo = getDatabase();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, is_pro, quota_day FROM users WHERE user_id = :uid LIMIT 1');
|
$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]);
|
$stmt->execute(['uid' => $user_id]);
|
||||||
|
|
||||||
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
@@ -26,18 +26,26 @@ if ($data === null) die(json_encode(['success' => false, 'errid'=>202, 'message'
|
|||||||
if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'errid'=>203, 'message' => 'UserID 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']));
|
if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'errid'=>204, 'message' => 'Authentification failed']));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT COUNT(*) FROM messages WHERE ack=0 AND sender_user_id=:uid');
|
||||||
|
$stmt->execute(['uid' => $user_id]);
|
||||||
|
$nack_count = $stmt->fetch(PDO::FETCH_NUM);
|
||||||
|
|
||||||
|
|
||||||
$quota = $data['quota_today'];
|
$quota = $data['quota_today'];
|
||||||
$is_pro = $data['is_pro'];
|
$is_pro = $data['is_pro'];
|
||||||
|
|
||||||
if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $quota=0;
|
if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $quota=0;
|
||||||
|
|
||||||
echo json_encode(
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
|
'message' => 'ok',
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
'quota' => $quota,
|
'quota' => $quota,
|
||||||
'quota_max' => Statics::quota_max($is_pro),
|
'quota_max' => Statics::quota_max($is_pro),
|
||||||
'is_pro' => $is_pro,
|
'is_pro' => $is_pro,
|
||||||
'message' => 'ok'
|
'fcm_token_set' => ($data['fcm_token'] != null),
|
||||||
|
'unack_count' => $nack_count,
|
||||||
]);
|
]);
|
||||||
return 0;
|
|
@@ -2,12 +2,39 @@
|
|||||||
|
|
||||||
include('lib/httpful.phar');
|
include('lib/httpful.phar');
|
||||||
|
|
||||||
|
class ERR
|
||||||
|
{
|
||||||
|
const NO_ERROR = 0000;
|
||||||
|
|
||||||
|
const MISSING_UID = 1101;
|
||||||
|
const MISSING_TOK = 1102;
|
||||||
|
const MISSING_TITLE = 1103;
|
||||||
|
const INVALID_PRIO = 1104;
|
||||||
|
const REQ_METHOD = 1105;
|
||||||
|
|
||||||
|
const NO_TITLE = 1201;
|
||||||
|
const TITLE_TOO_LONG = 1202;
|
||||||
|
const CONTENT_TOO_LONG = 1203;
|
||||||
|
const USR_MSG_ID_TOO_LONG = 1204;
|
||||||
|
|
||||||
|
const USER_NOT_FOUND = 1301;
|
||||||
|
const USER_AUTH_FAILED = 1302;
|
||||||
|
|
||||||
|
const NO_DEVICE_LINKED = 1401;
|
||||||
|
|
||||||
|
const QUOTA_REACHED = 2101;
|
||||||
|
|
||||||
|
const FIREBASE_COM_FAILED = 9901;
|
||||||
|
const FIREBASE_COM_ERRORED = 9902;
|
||||||
|
const INTERNAL_EXCEPTION = 9903;
|
||||||
|
}
|
||||||
|
|
||||||
class Statics
|
class Statics
|
||||||
{
|
{
|
||||||
public static $DB = NULL;
|
public static $DB = NULL;
|
||||||
public static $CFG = NULL;
|
public static $CFG = NULL;
|
||||||
|
|
||||||
public static function quota_max($is_pro) { return $is_pro ? 1000 : 100; }
|
public static function quota_max($is_pro) { return $is_pro ? 1000 : 50; }
|
||||||
}
|
}
|
||||||
|
|
||||||
function getConfig()
|
function getConfig()
|
||||||
@@ -123,7 +150,7 @@ function sendPOST($url, $body, $header)
|
|||||||
|
|
||||||
if ($response->code != 200) throw new Exception("Repsponse code: " . $response->code);
|
if ($response->code != 200) throw new Exception("Repsponse code: " . $response->code);
|
||||||
|
|
||||||
return $response->body;
|
return $response->raw_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyOrderToken($tok)
|
function verifyOrderToken($tok)
|
||||||
@@ -136,26 +163,25 @@ function verifyOrderToken($tok)
|
|||||||
$product = getConfig()['verify_api']['product_id'];
|
$product = getConfig()['verify_api']['product_id'];
|
||||||
$acctoken = getConfig()['verify_api']['accesstoken'];
|
$acctoken = getConfig()['verify_api']['accesstoken'];
|
||||||
|
|
||||||
if ($acctoken == '') $acctoken = refreshVerifyToken();
|
if ($acctoken == '' || $acctoken == null || $acctoken == false) $acctoken = refreshVerifyToken();
|
||||||
|
|
||||||
$url = 'https://www.googleapis.com/androidpublisher/v3/applications/'.$package.'/purchases/products/'.$product.'/tokens/'.$tok.'?access_token='.$acctoken;
|
$url = 'https://www.googleapis.com/androidpublisher/v3/applications/'.$package.'/purchases/products/'.$product.'/tokens/'.$tok.'?access_token='.$acctoken;
|
||||||
|
$response = $builder = \Httpful\Request::get($url)->send();
|
||||||
|
$obj = json_decode($response->raw_body, true);
|
||||||
|
|
||||||
$json = sendPOST($url, "", []);
|
if ($response->code != 401 && ($obj === null || $obj === false))
|
||||||
$obj = json_decode($json);
|
|
||||||
|
|
||||||
if ($obj === null || $obj === false)
|
|
||||||
{
|
{
|
||||||
reportError('verify-token returned NULL');
|
reportError('verify-token returned NULL');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($obj['error']) && isset($obj['error']['code']) && $obj['error']['code'] == 401) // "Invalid Credentials" -- refresh acces_token
|
if ($response->code == 401 || isset($obj['error']) && isset($obj['error']['code']) && $obj['error']['code'] == 401) // "Invalid Credentials" -- refresh acces_token
|
||||||
{
|
{
|
||||||
$acctoken = refreshVerifyToken();
|
$acctoken = refreshVerifyToken();
|
||||||
|
|
||||||
$url = 'https://www.googleapis.com/androidpublisher/v3/applications/'.$package.'/purchases/products/'.$product.'/tokens/'.$tok.'?access_token='.$acctoken;
|
$url = 'https://www.googleapis.com/androidpublisher/v3/applications/'.$package.'/purchases/products/'.$product.'/tokens/'.$tok.'?access_token='.$acctoken;
|
||||||
$json = sendPOST($url, "", []);
|
$response = $builder = \Httpful\Request::get($url)->send();
|
||||||
$obj = json_decode($json);
|
$obj = json_decode($response->raw_body, true);
|
||||||
|
|
||||||
if ($obj === null || $obj === false)
|
if ($obj === null || $obj === false)
|
||||||
{
|
{
|
||||||
@@ -185,28 +211,34 @@ function refreshVerifyToken()
|
|||||||
'&client_secret='.getConfig()['verify_api']['clientsecret'];
|
'&client_secret='.getConfig()['verify_api']['clientsecret'];
|
||||||
|
|
||||||
$json = sendPOST($url, "", []);
|
$json = sendPOST($url, "", []);
|
||||||
$obj = json_decode($json);
|
$obj = json_decode($json, true);
|
||||||
file_put_contents('.verify_accesstoken', $obj['access_token']);
|
file_put_contents('.verify_accesstoken', $obj['access_token']);
|
||||||
|
|
||||||
return $obj->access_token;
|
return $obj['access_token'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $http_code
|
||||||
|
* @param array $message
|
||||||
|
*/
|
||||||
function api_return($http_code, $message)
|
function api_return($http_code, $message)
|
||||||
{
|
{
|
||||||
http_response_code($http_code);
|
http_response_code($http_code);
|
||||||
echo $message;
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode($message);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param String $str
|
* @param String $str
|
||||||
* @param String[] $path
|
* @param String[] $path
|
||||||
|
* @return mixed|null
|
||||||
*/
|
*/
|
||||||
function try_json($str, $path)
|
function try_json($str, $path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$o = json_decode($str);
|
$o = json_decode($str, true);
|
||||||
foreach ($path as $p) $o = $o[$p];
|
foreach ($path as $p) $o = $o[$p];
|
||||||
return $o;
|
return $o;
|
||||||
}
|
}
|
||||||
@@ -215,3 +247,15 @@ function try_json($str, $path)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#################################################################################################################
|
||||||
|
|
||||||
|
if (getConfig()['global']['prod']) {
|
||||||
|
ini_set('display_errors', 0);
|
||||||
|
ini_set('log_errors', 1);
|
||||||
|
} else {
|
||||||
|
error_reporting(E_STRICT);
|
||||||
|
ini_set('display_errors', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#################################################################################################################
|
@@ -15,16 +15,30 @@ $user_key = generateRandomAuthKey();
|
|||||||
|
|
||||||
$pdo = getDatabase();
|
$pdo = getDatabase();
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
if ($ispro)
|
if ($ispro)
|
||||||
{
|
{
|
||||||
if (!verifyOrderToken($pro_token)) die(json_encode(['success' => false, 'message' => 'Purchase token could not be verified']));
|
if (!verifyOrderToken($pro_token))
|
||||||
|
{
|
||||||
|
$pdo->rollBack();
|
||||||
|
die(json_encode(['success' => false, 'message' => 'Purchase token could not be verified']));
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('UPDATE users SET is_pro=0, pro_token=NULL WHERE user_id <> :uid AND pro_token = :ptk');
|
||||||
|
$stmt->execute(['uid' => $user_id, 'ptk' => $pro_token]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('INSERT INTO users (user_key, fcm_token, is_pro, pro_token, timestamp_accessed) VALUES (:key, :token, :bpro, :spro, NOW())');
|
$stmt = $pdo->prepare('INSERT INTO users (user_key, fcm_token, is_pro, pro_token, timestamp_accessed) VALUES (:key, :token, :bpro, :spro, NOW())');
|
||||||
$stmt->execute(['key' => $user_key, 'token' => $fcmtoken, 'bpro' => $ispro, 'spro' => $ispro ? $pro_token : null]);
|
$stmt->execute(['key' => $user_key, 'token' => $fcmtoken, 'bpro' => $ispro, 'spro' => $ispro ? $pro_token : null]);
|
||||||
$user_id = $pdo->lastInsertId('user_id');
|
$user_id = $pdo->lastInsertId('user_id');
|
||||||
|
|
||||||
echo json_encode(
|
$stmt = $pdo->prepare('UPDATE users SET fcm_token=NULL WHERE user_id <> :uid AND fcm_token=:ft');
|
||||||
|
$stmt->execute(['uid' => $user_id, 'ft' => $fcm_token]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
@@ -34,5 +48,3 @@ echo json_encode(
|
|||||||
'is_pro' => $ispro,
|
'is_pro' => $ispro,
|
||||||
'message' => 'New user registered'
|
'message' => 'New user registered'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return 0;
|
|
56
web/api/requery.php
Normal file
56
web/api/requery.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?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]]']));
|
||||||
|
|
||||||
|
$user_id = $INPUT['user_id'];
|
||||||
|
$user_key = $INPUT['user_key'];
|
||||||
|
|
||||||
|
//----------------------
|
||||||
|
|
||||||
|
$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 ack=0 AND sender_user_id=:uid ORDER BY `timestamp` DESC LIMIT 16');
|
||||||
|
$stmt->execute(['uid' => $user_id]);
|
||||||
|
$nonacks_sql = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$nonacks = [];
|
||||||
|
|
||||||
|
foreach ($nonacks_sql as $nack)
|
||||||
|
{
|
||||||
|
$nonacks []=
|
||||||
|
[
|
||||||
|
'title' => $nack['title'],
|
||||||
|
'body' => $nack['content'],
|
||||||
|
'priority' => $nack['priority'],
|
||||||
|
'timestamp' => $nack['timestamp'],
|
||||||
|
'usr_msg_id' => $nack['usr_message_id'],
|
||||||
|
'scn_msg_id' => $nack['scn_message_id'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
api_return(200,
|
||||||
|
[
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'ok',
|
||||||
|
'count' => count($nonacks),
|
||||||
|
'data' => $nonacks,
|
||||||
|
]);
|
@@ -1,3 +1,4 @@
|
|||||||
|
DROP TABLE IF EXISTS `users`;
|
||||||
CREATE TABLE `users`
|
CREATE TABLE `users`
|
||||||
(
|
(
|
||||||
`user_id` INT(11) NOT NULL AUTO_INCREMENT,
|
`user_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
@@ -16,19 +17,21 @@ CREATE TABLE `users`
|
|||||||
PRIMARY KEY (`user_id`)
|
PRIMARY KEY (`user_id`)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `messages`;
|
||||||
CREATE TABLE `messages`
|
CREATE TABLE `messages`
|
||||||
(
|
(
|
||||||
`scn_message_id` INT(11) NOT NULL AUTO_INCREMENT,
|
`scn_message_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
`sender_user_id` INT(11) NOT NULL,
|
`sender_user_id` INT(11) NOT NULL,
|
||||||
|
|
||||||
`timestamp` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`timestamp` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`ack` BIT NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
`title` VARCHAR(256) NOT NULL,
|
`title` VARCHAR(256) NOT NULL,
|
||||||
`content` VARCHAR(12288) NULL,
|
`content` VARCHAR(12288) NULL,
|
||||||
`priority` INT(11) NOT NULL,
|
`priority` INT(11) NOT NULL,
|
||||||
|
|
||||||
`fcn_message_id` VARCHAR(256) NOT NULL,
|
`fcm_message_id` VARCHAR(256) NULL,
|
||||||
`usr_message_id` VARCHAR(256) NULL,
|
`usr_message_id` VARCHAR(256) NULL,
|
||||||
|
|
||||||
PRIMARY KEY (`scn_message_id`)
|
PRIMARY KEY (`scn_message_id`)
|
||||||
)
|
);
|
@@ -34,10 +34,12 @@ $new_userkey = generateRandomAuthKey();
|
|||||||
|
|
||||||
if ($fcm_token === null)
|
if ($fcm_token === null)
|
||||||
{
|
{
|
||||||
|
// only gen new user_secret
|
||||||
|
|
||||||
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), user_key=:at WHERE user_id = :uid');
|
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), user_key=:at WHERE user_id = :uid');
|
||||||
$stmt->execute(['uid' => $user_id, 'at' => $new_userkey]);
|
$stmt->execute(['uid' => $user_id, 'at' => $new_userkey]);
|
||||||
|
|
||||||
echo json_encode(
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
@@ -47,14 +49,18 @@ if ($fcm_token === null)
|
|||||||
'is_pro' => $is_pro,
|
'is_pro' => $is_pro,
|
||||||
'message' => 'user updated'
|
'message' => 'user updated'
|
||||||
]);
|
]);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// update fcm and gen new user_secret
|
||||||
|
|
||||||
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), fcm_token=:ft, user_key=:at WHERE user_id = :uid');
|
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), fcm_token=:ft, user_key=:at WHERE user_id = :uid');
|
||||||
$stmt->execute(['uid' => $user_id, 'ft' => $fcm_token, 'at' => $new_userkey]);
|
$stmt->execute(['uid' => $user_id, 'ft' => $fcm_token, 'at' => $new_userkey]);
|
||||||
|
|
||||||
echo json_encode(
|
$stmt = $pdo->prepare('UPDATE users SET fcm_token=NULL WHERE user_id <> :uid AND fcm_token=:ft');
|
||||||
|
$stmt->execute(['uid' => $user_id, 'ft' => $fcm_token]);
|
||||||
|
|
||||||
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
@@ -64,5 +70,4 @@ else
|
|||||||
'is_pro' => $is_pro,
|
'is_pro' => $is_pro,
|
||||||
'message' => 'user updated'
|
'message' => 'user updated'
|
||||||
]);
|
]);
|
||||||
return 0;
|
|
||||||
}
|
}
|
@@ -45,17 +45,15 @@ if ($ispro)
|
|||||||
$stmt = $pdo->prepare('UPDATE users SET is_pro=0, pro_token=NULL WHERE user_id <> :uid AND pro_token = :ptk');
|
$stmt = $pdo->prepare('UPDATE users SET is_pro=0, pro_token=NULL WHERE user_id <> :uid AND pro_token = :ptk');
|
||||||
$stmt->execute(['uid' => $user_id, 'ptk' => $pro_token]);
|
$stmt->execute(['uid' => $user_id, 'ptk' => $pro_token]);
|
||||||
|
|
||||||
echo json_encode(
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
'user_key' => $new_userkey,
|
'quota' => $data['quota_today'],
|
||||||
'quota' => $data['quota'],
|
|
||||||
'quota_max'=> Statics::quota_max(true),
|
'quota_max'=> Statics::quota_max(true),
|
||||||
'is_pro' => true,
|
'is_pro' => true,
|
||||||
'message' => 'user updated'
|
'message' => 'user updated'
|
||||||
]);
|
]);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -64,15 +62,13 @@ else
|
|||||||
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), is_pro=0, pro_token=NULL WHERE user_id = :uid');
|
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), is_pro=0, pro_token=NULL WHERE user_id = :uid');
|
||||||
$stmt->execute(['uid' => $user_id]);
|
$stmt->execute(['uid' => $user_id]);
|
||||||
|
|
||||||
echo json_encode(
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
'user_key' => $new_userkey,
|
'quota' => $data['quota_today'],
|
||||||
'quota' => $data['quota'],
|
|
||||||
'quota_max'=> Statics::quota_max(false),
|
'quota_max'=> Statics::quota_max(false),
|
||||||
'is_pro' => false,
|
'is_pro' => false,
|
||||||
'message' => 'user updated'
|
'message' => 'user updated'
|
||||||
]);
|
]);
|
||||||
return 0;
|
|
||||||
}
|
}
|
@@ -8,13 +8,21 @@
|
|||||||
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.png"/>
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.ico"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mainpnl">
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
|
||||||
<a href="/index.php" class="button bordered" id="tr_link">Send</a>
|
|
||||||
|
|
||||||
<a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
<div id="copyinfo">
|
||||||
|
<a tabindex="-1" href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
||||||
|
<a tabindex="-1" href="https://www.mikescher.com">made by Mike Schwörer</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="mainpnl">
|
||||||
|
<a tabindex="-1" href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
||||||
|
<a tabindex="-1" href="/index.php" class="button bordered" id="tr_link">Send</a>
|
||||||
|
|
||||||
|
<a tabindex="-1" href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
||||||
|
|
||||||
<h2>Introduction</h2>
|
<h2>Introduction</h2>
|
||||||
<div class="section">
|
<div class="section">
|
||||||
@@ -69,7 +77,6 @@
|
|||||||
"canonical_ids":0,
|
"canonical_ids":0,
|
||||||
"results": [{"message_id":"0:10000000000000000000000000000000d"}]
|
"results": [{"message_id":"0:10000000000000000000000000000000d"}]
|
||||||
},
|
},
|
||||||
"messagecount":623,
|
|
||||||
"quota":17,
|
"quota":17,
|
||||||
"quota_max":100
|
"quota_max":100
|
||||||
}</pre>
|
}</pre>
|
||||||
@@ -100,6 +107,10 @@
|
|||||||
<td data-label="Statuscode">403 (Forbidden)</td>
|
<td data-label="Statuscode">403 (Forbidden)</td>
|
||||||
<td data-label="Explanation">The user has exceeded its daily quota - wait 24 hours or upgrade your account</td>
|
<td data-label="Explanation">The user has exceeded its daily quota - wait 24 hours or upgrade your account</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td data-label="Statuscode">412 (Precondition Failed)</td>
|
||||||
|
<td data-label="Explanation">There is no device connected with this account - open the app and press the refresh button in the account tab</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td data-label="Statuscode">500 (Internal Server Error)</td>
|
<td data-label="Statuscode">500 (Internal Server Error)</td>
|
||||||
<td data-label="Explanation">There was an internal error while sending your data - try again later</td>
|
<td data-label="Explanation">There was an internal error while sending your data - try again later</td>
|
||||||
@@ -176,11 +187,7 @@
|
|||||||
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>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="copyinfo">
|
|
||||||
<a href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@@ -86,13 +86,10 @@ body
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: -999;
|
//z-index: -999;
|
||||||
}
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
#copyinfo a:hover
|
text-align: right;
|
||||||
{
|
|
||||||
font-family: "Courier New", monospace;
|
|
||||||
color: #00F;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#copyinfo a,
|
#copyinfo a,
|
||||||
@@ -102,6 +99,14 @@ body
|
|||||||
font-family: "Courier New", monospace;
|
font-family: "Courier New", monospace;
|
||||||
color: #AAA;
|
color: #AAA;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#copyinfo a:hover
|
||||||
|
{
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
color: #0288D1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tr_link
|
#tr_link
|
||||||
@@ -193,6 +198,11 @@ input::-webkit-inner-spin-button {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fullcenterflex .card
|
||||||
|
{
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
a.card,
|
a.card,
|
||||||
a.card:active,
|
a.card:active,
|
||||||
a.card:visited,
|
a.card:visited,
|
||||||
|
BIN
web/favicon.ico
Normal file
BIN
web/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
BIN
web/favicon.png
Normal file
BIN
web/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 90 KiB |
@@ -9,14 +9,22 @@
|
|||||||
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.png"/>
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.ico"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<div id="copyinfo">
|
||||||
|
<a tabindex="-1" href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
||||||
|
<a tabindex="-1" href="https://www.mikescher.com">made by Mike Schwörer</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form id="mainpnl">
|
<form id="mainpnl">
|
||||||
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
<a tabindex="-1" href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
||||||
<a href="/index_api.php" class="button bordered" id="tr_link">API</a>
|
<a tabindex="-1" href="/api.php" class="button bordered" id="tr_link">API</a>
|
||||||
|
|
||||||
<a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
<a tabindex="-1" href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
||||||
|
|
||||||
<div class="row responsive-label">
|
<div class="row responsive-label">
|
||||||
<div class="col-sm-12 col-md-3"><label for="uid" class="doc">UserID</label></div>
|
<div class="col-sm-12 col-md-3"><label for="uid" class="doc">UserID</label></div>
|
||||||
@@ -55,10 +63,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div id="copyinfo">
|
|
||||||
<a href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/js/logic.js" type="text/javascript" ></script>
|
<script src="/js/logic.js" type="text/javascript" ></script>
|
||||||
<script src="/js/toastify.js"></script>
|
<script src="/js/toastify.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
@@ -55,7 +55,7 @@ function send()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
window.location.href =
|
window.location.href =
|
||||||
'/index_sent.php' +
|
'/message_sent.php' +
|
||||||
'?ok=' + 1 +
|
'?ok=' + 1 +
|
||||||
'&message_count=' + resp.messagecount +
|
'&message_count=' + resp.messagecount +
|
||||||
'"a=' + resp.quota +
|
'"a=' + resp.quota +
|
||||||
|
@@ -8,9 +8,15 @@
|
|||||||
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
<!--<link rel="stylesheet" href="/css/mini-dark.min.css">-->
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.png"/>
|
||||||
|
<link rel="icon" type="image/png" href="/favicon.ico"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<div id="copyinfo">
|
||||||
|
<a tabindex="-1" href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
||||||
|
<a tabindex="-1" href="https://www.mikescher.com">made by Mike Schwörer</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="mainpnl">
|
<div id="mainpnl">
|
||||||
|
|
||||||
@@ -39,16 +45,12 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
<a tabindex="-1" href="https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier" class="button bordered" id="tl_link"><span class="icn-google-play"></span></a>
|
||||||
<a href="/index.php" class="button bordered" id="tr_link">Send</a>
|
<a tabindex="-1" href="/index.php" class="button bordered" id="tr_link">Send</a>
|
||||||
|
|
||||||
<a href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
<a tabindex="-1" href="/" class="linkcaption"><h1>Simple Cloud Notifier</h1></a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="copyinfo">
|
|
||||||
<a href="https://www.blackforestbytes.com">© blackforestbytes</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
84
web/send.php
84
web/send.php
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
include_once 'model.php';
|
include_once 'api/model.php';
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -9,11 +9,13 @@ try
|
|||||||
//sleep(1);
|
//sleep(1);
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') api_return(400, ['success' => false, 'error' => ERR::REQ_METHOD, 'errhighlight' => -1, 'message' => 'Invalid request method (must be POST)']);
|
||||||
|
|
||||||
$INPUT = array_merge($_GET, $_POST);
|
$INPUT = array_merge($_GET, $_POST);
|
||||||
|
|
||||||
if (!isset($INPUT['user_id'])) api_return(400, json_encode(['success' => false, 'error' => 1101, 'errhighlight' => 101, 'message' => 'Missing parameter [[user_id]]']));
|
if (!isset($INPUT['user_id'])) api_return(400, ['success' => false, 'error' => ERR::MISSING_UID, 'errhighlight' => 101, 'message' => 'Missing parameter [[user_id]]']);
|
||||||
if (!isset($INPUT['user_key'])) api_return(400, json_encode(['success' => false, 'error' => 1102, 'errhighlight' => 102, 'message' => 'Missing parameter [[user_token]]']));
|
if (!isset($INPUT['user_key'])) api_return(400, ['success' => false, 'error' => ERR::MISSING_TOK, 'errhighlight' => 102, 'message' => 'Missing parameter [[user_token]]']);
|
||||||
if (!isset($INPUT['title'])) api_return(400, json_encode(['success' => false, 'error' => 1103, 'errhighlight' => 103, 'message' => 'Missing parameter [[title]]']));
|
if (!isset($INPUT['title'])) api_return(400, ['success' => false, 'error' => ERR::MISSING_TITLE, 'errhighlight' => 103, 'message' => 'Missing parameter [[title]]']);
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -27,11 +29,12 @@ try
|
|||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
if ($priority !== '0' && $priority !== '1' && $priority !== '2') api_return(400, json_encode(['success' => false, 'error' => 1104, '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, json_encode(['success' => false, 'error' => 1201, '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, json_encode(['success' => false, 'error' => 1202, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)']));
|
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, json_encode(['success' => false, 'error' => 1203, 'errhighlight' => 104, 'message' => 'Content too long (10000 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)']);
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -41,18 +44,23 @@ 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' => 1301, 'errhighlight' => 101, 'message' => 'User not found']));
|
if (count($datas)<=0) die(json_encode(['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, json_encode(['success' => false, 'error' => 1301, '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, json_encode(['success' => false, 'error' => 1302, '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, json_encode(['success' => false, 'error' => 1303, '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']);
|
||||||
|
|
||||||
$fcm = $data['fcm_token'];
|
$fcm = $data['fcm_token'];
|
||||||
|
|
||||||
$new_quota = $data['quota_today'] + 1;
|
$new_quota = $data['quota_today'] + 1;
|
||||||
if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $new_quota=1;
|
if ($data['quota_day'] === null || $data['quota_day'] !== date("Y-m-d")) $new_quota=1;
|
||||||
if ($new_quota > Statics::quota_max($data['is_pro'])) api_return(403, json_encode(['success' => false, 'error' => 2101, 'errhighlight' => -1, 'message' => 'Daily quota reached ('.Statics::quota_max($data['is_pro']).')']));
|
if ($new_quota > Statics::quota_max($data['is_pro'])) api_return(403, ['success' => false, 'error' => ERR::QUOTA_REACHED, 'errhighlight' => -1, 'message' => 'Daily quota reached ('.Statics::quota_max($data['is_pro']).')']);
|
||||||
|
|
||||||
|
if ($fcm == null || $fcm == '' || $fcm == false)
|
||||||
|
{
|
||||||
|
api_return(412, ['success' => false, 'error' => ERR::NO_DEVICE_LINKED, 'errhighlight' => -1, 'message' => 'No device linked with this account']);
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -63,7 +71,7 @@ try
|
|||||||
|
|
||||||
if (count($stmt->fetchAll(PDO::FETCH_ASSOC))>0)
|
if (count($stmt->fetchAll(PDO::FETCH_ASSOC))>0)
|
||||||
{
|
{
|
||||||
api_return(200, json_encode(
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'message' => 'Message already sent',
|
'message' => 'Message already sent',
|
||||||
@@ -73,12 +81,28 @@ try
|
|||||||
'quota' => $data['quota_today'],
|
'quota' => $data['quota_today'],
|
||||||
'is_pro' => $data['is_pro'],
|
'is_pro' => $data['is_pro'],
|
||||||
'quota_max' => Statics::quota_max($data['is_pro']),
|
'quota_max' => Statics::quota_max($data['is_pro']),
|
||||||
]));
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO messages (sender_user_id, title, content, priority, fcm_message_id, usr_message_id) VALUES (:suid, :t, :c, :p, :fmid, :umid)');
|
||||||
|
$stmt->execute(
|
||||||
|
[
|
||||||
|
'suid' => $user_id,
|
||||||
|
't' => $message,
|
||||||
|
'c' => $content,
|
||||||
|
'p' => $priority,
|
||||||
|
'fmid' => null,
|
||||||
|
'umid' => $usrmsgid,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$scn_msg_id = $pdo->lastInsertId();
|
||||||
|
|
||||||
$url = "https://fcm.googleapis.com/fcm/send";
|
$url = "https://fcm.googleapis.com/fcm/send";
|
||||||
$payload = json_encode(
|
$payload = json_encode(
|
||||||
[
|
[
|
||||||
@@ -97,6 +121,7 @@ try
|
|||||||
'priority' => $priority,
|
'priority' => $priority,
|
||||||
'timestamp' => time(),
|
'timestamp' => time(),
|
||||||
'usr_msg_id' => $usrmsgid,
|
'usr_msg_id' => $usrmsgid,
|
||||||
|
'scn_msg_id' => $scn_msg_id,
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
$header=
|
$header=
|
||||||
@@ -112,32 +137,30 @@ try
|
|||||||
if (try_json($httpresult, ['success']) != 1)
|
if (try_json($httpresult, ['success']) != 1)
|
||||||
{
|
{
|
||||||
reportError("FCM communication failed (success_1 <> true)\n\n".$httpresult);
|
reportError("FCM communication failed (success_1 <> true)\n\n".$httpresult);
|
||||||
api_return(403, json_encode(['success' => false, 'error' => 9902, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.']));
|
$pdo->rollBack();
|
||||||
|
api_return(500, ['success' => false, 'error' => ERR::FIREBASE_COM_ERRORED, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e)
|
catch (Exception $e)
|
||||||
{
|
{
|
||||||
reportError("FCM communication failed", $e);
|
reportError("FCM communication failed", $e);
|
||||||
api_return(403, json_encode(['success' => false, 'error' => 9901, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.'."\n\n".'Exception: ' . $e->getMessage()]));
|
$pdo->rollBack();
|
||||||
|
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]);
|
||||||
|
|
||||||
$stmt = $pdo->prepare('INSERT INTO messages (sender_user_id, title, content, priority, fcn_message_id, usr_message_id) VALUES (:suid, :t, :c, :p, :fmid, :umid)');
|
$stmt = $pdo->prepare('UPDATE messages SET fcm_message_id=:fmid WHERE scn_message_id=:smid');
|
||||||
$stmt->execute(
|
$stmt->execute([ 'fmid' => try_json($httpresult, ['results', 0, 'message_id']), 'smid' => $scn_msg_id ]);
|
||||||
[
|
|
||||||
'suid' => $user_id,
|
|
||||||
't' => $message,
|
|
||||||
'c' => $content,
|
|
||||||
'p' => $priority,
|
|
||||||
'fmid' => try_json($httpresult, ['results', 'message_id']),
|
|
||||||
'umid' => $usrmsgid,
|
|
||||||
]);
|
|
||||||
|
|
||||||
api_return(200, json_encode(
|
$pdo->commit();
|
||||||
|
|
||||||
|
api_return(200,
|
||||||
[
|
[
|
||||||
'success' => true,
|
'success' => true,
|
||||||
|
'error' => ERR::NO_ERROR,
|
||||||
|
'errhighlight' => -1,
|
||||||
'message' => 'Message sent',
|
'message' => 'Message sent',
|
||||||
'suppress_send' => false,
|
'suppress_send' => false,
|
||||||
'response' => $httpresult,
|
'response' => $httpresult,
|
||||||
@@ -145,9 +168,12 @@ try
|
|||||||
'quota' => $new_quota,
|
'quota' => $new_quota,
|
||||||
'is_pro' => $data['is_pro'],
|
'is_pro' => $data['is_pro'],
|
||||||
'quota_max' => Statics::quota_max($data['is_pro']),
|
'quota_max' => Statics::quota_max($data['is_pro']),
|
||||||
]));
|
'scn_msg_id' => $scn_msg_id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
catch (Exception $mex)
|
catch (Exception $mex)
|
||||||
{
|
{
|
||||||
reportError("Root try-catch triggered", $mex);
|
reportError("Root try-catch triggered", $mex);
|
||||||
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||||
|
api_return(500, ['success' => false, 'error' => ERR::INTERNAL_EXCEPTION, 'errhighlight' => -1, 'message' => 'PHP script threw exception.'."\n\n".'Exception: ' . $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user