14 Commits

Author SHA1 Message Date
4655d688c9 README 2018-11-18 17:19:15 +01:00
8263c0ad95 phone image 2018-11-18 17:12:44 +01:00
a701afd09b OWA tracking 2018-11-18 03:34:13 +01:00
jenkins
1e02d8c01f [Jenkins] Increment version 2018-11-18 03:24:46 +01:00
e4651375aa fix qr url 2018-11-18 03:23:22 +01:00
jenkins
afce4c6391 [Jenkins] Increment version 2018-11-18 00:15:21 +01:00
e95d0cb010 added disable warning 2018-11-18 00:13:36 +01:00
f717355519 use "messages" everywhere instead of "notifications" 2018-11-18 00:11:30 +01:00
3368e514ca red quota icon if OOQ 2018-11-18 00:02:00 +01:00
9dca27177f fixed js logic for errors 2018-11-17 23:59:57 +01:00
c63274f7a9 show subtext on android-o 2018-11-17 23:48:39 +01:00
6c2d2d2345 fixed requery only getting first message 2018-11-17 22:51:02 +01:00
a6fbaa192f config example 2018-11-17 19:28:44 +01:00
jenkins
a01f156535 [Jenkins] Increment version 2018-11-17 19:00:13 +01:00
25 changed files with 160 additions and 30 deletions

22
README.md Normal file
View File

@@ -0,0 +1,22 @@
SimpleCloudNotifier [![Get it in Google Play](data/README/badge_google.png)](https://play.google.com/store/apps/details?id=com.blackforestbytes.simplecloudnotifier)
===================
> SimpleCloudNotifier is an app to display messages that you can send to your phone with simple POST requests.
>
> After you start the app it generates a UserID and a UserSecret.
> Now you can send your message to https://simplecloudnotifier.blackforestbytes.com/send.php and a notification will be pushed to your phone.
> (see https://simplecloudnotifier.blackforestbytes.com/ for an example with curl)
>
>
> Use it to
> - send yourself automated messages from cron jobs
> - notify yourself when long-running scripts finish
> - send server error messages directly to your phone
> - integrate with other online services
>
> The possibilities are endless*
>
> \* Disclaimer: Developer does not actually guarantee endless possibilities
![](store/screenshot_1.png) ![](store/screenshot_2.png) ![](store/screenshot_3.png)

View File

@@ -97,4 +97,6 @@ public class SCNApp extends Application implements LifecycleObserver
{
isBackground = false;
}
}
}
//TODO TabLayout indicator does not corretly animate when directly clicking on tabs

View File

@@ -163,10 +163,12 @@ public class SCNSettings
return user_id>=0 && user_key != null && !user_key.isEmpty();
}
public String createOnlineURL()
public String createOnlineURL(boolean longurl)
{
if (!isConnected()) return ServerCommunication.BASE_URL + "index.php";
return ServerCommunication.BASE_URL + "index.php?preset_user_id="+user_id+"&preset_user_key="+user_key;
String base = longurl ? ServerCommunication.PAGE_URL_LONG : ServerCommunication.PAGE_URL_SHORT;
if (!isConnected()) return base;
return base + "index.php?preset_user_id="+user_id+"&preset_user_key="+user_key;
}
public void setServerToken(String token, View loader)

View File

@@ -27,7 +27,9 @@ import okhttp3.ResponseBody;
public class ServerCommunication
{
public static final String BASE_URL = /*SCNApp.LOCAL_DEBUG ? "http://localhost:1010/" : */"https://scn.blackforestbytes.com/api/";
public static final String PAGE_URL_LONG = "https://simplecloudnotifier.blackforestbytes.com/";
public static final String PAGE_URL_SHORT = "https://scn.blackforestbytes.com/";
public static final String BASE_URL = "https://scn.blackforestbytes.com/api/";
private static final OkHttpClient client = new OkHttpClient();
@@ -346,7 +348,7 @@ public class ServerCommunication
JSONArray arr = json.getJSONArray("data");
for (int i = 0; i < count; i++)
{
JSONObject o = arr.getJSONObject(0);
JSONObject o = arr.getJSONObject(i);
long time = json_lng(o, "timestamp");
String title = json_str(o, "title");

View File

@@ -174,8 +174,7 @@ public class NotificationService
mBuilder.setWhen(msg.Timestamp * 1000);
mBuilder.setAutoCancel(true);
mBuilder.setCategory(Notification.CATEGORY_MESSAGE);
mBuilder.setStyle(new NotificationCompat.InboxStyle());
mBuilder.setGroup(prio.toString());
mBuilder.setGroup("com.blackforestbytes.simplecloudnotifier.notifications.group."+prio.toString());
if (msg.Priority == PriorityEnum.LOW) mBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
if (msg.Priority == PriorityEnum.NORMAL) mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
@@ -218,8 +217,7 @@ public class NotificationService
mBuilder.setWhen(msg.Timestamp * 1000);
mBuilder.setAutoCancel(true);
mBuilder.setCategory(Notification.CATEGORY_MESSAGE);
mBuilder.setStyle(new NotificationCompat.InboxStyle());
mBuilder.setGroup(prio.toString());
mBuilder.setGroup("com.blackforestbytes.simplecloudnotifier.notifications.group."+prio.toString());
if (ns.EnableLED) mBuilder.setLights(ns.LEDColor, 500, 500);
@@ -251,7 +249,7 @@ public class NotificationService
Notification n = mBuilder.build();
n.flags |= Notification.FLAG_AUTO_CANCEL;
mNotificationManager.notify(0, n);
mNotificationManager.notify((int)msg.SCN_ID, n);
if (ns.EnableVibration)
{

View File

@@ -6,12 +6,14 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.blackforestbytes.simplecloudnotifier.R;
@@ -91,7 +93,7 @@ public class AccountFragment extends Fragment
builder.setPositiveButton("YES", (dialog, which) -> {
CMessageList.inst().clear();
SCNApp.showToast("Notifications cleared", 1000);
SCNApp.showToast("Messages cleared", 1000);
dialog.dismiss();
});
@@ -103,7 +105,7 @@ public class AccountFragment extends Fragment
v.findViewById(R.id.btnQR).setOnClickListener(cv ->
{
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(SCNSettings.inst().createOnlineURL()));
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(SCNSettings.inst().createOnlineURL(true)));
startActivity(browserIntent);
});
@@ -126,10 +128,11 @@ public class AccountFragment extends Fragment
public void updateUI(View v)
{
if (v == null) return;
TextView tvUserID = v.findViewById(R.id.tvUserID);
TextView tvUserKey = v.findViewById(R.id.tvUserKey);
TextView tvQuota = v.findViewById(R.id.tvQuota);
ImageButton btnQR = v.findViewById(R.id.btnQR);
TextView tvUserID = v.findViewById(R.id.tvUserID);
TextView tvUserKey = v.findViewById(R.id.tvUserKey);
TextView tvQuota = v.findViewById(R.id.tvQuota);
ImageView ivQuota = v.findViewById(R.id.ic_img_quota);
ImageButton btnQR = v.findViewById(R.id.btnQR);
SCNSettings s = SCNSettings.inst();
@@ -138,7 +141,8 @@ public class AccountFragment extends Fragment
tvUserID.setText(String.valueOf(s.user_id));
tvUserKey.setText(s.user_key);
tvQuota.setText(String.format("%d / %d", s.quota_curr, s.quota_max));
btnQR.setImageBitmap(QRCode.from(s.createOnlineURL()).to(ImageType.PNG).withSize(512, 512).bitmap());
btnQR.setImageBitmap(QRCode.from(s.createOnlineURL(false)).to(ImageType.PNG).withSize(512, 512).bitmap());
ivQuota.setColorFilter(s.quota_curr>=s.quota_max ? Color.rgb(200, 0, 0) : Color.rgb(128, 128, 128));
}
else
{
@@ -146,6 +150,7 @@ public class AccountFragment extends Fragment
tvUserKey.setText(R.string.str_not_connected);
tvQuota.setText(R.string.str_not_connected);
btnQR.setImageResource(R.drawable.qr_default);
ivQuota.setColorFilter(0x80_80_80);
}
}
}

View File

@@ -22,6 +22,7 @@ import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import com.android.billingclient.api.Purchase;
import com.blackforestbytes.simplecloudnotifier.R;
@@ -216,7 +217,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
{
SCNSettings s = SCNSettings.inst();
prefAppEnabled.setOnCheckedChangeListener((a,b) -> { s.Enabled=b; saveAndUpdate(); });
prefAppEnabled.setOnCheckedChangeListener((a,b) -> { boolean prev=s.Enabled; s.Enabled=b; saveAndUpdate(); updateEnabled(prev, b); });
prefEnableDeleteSwipe.setOnCheckedChangeListener((a,b) -> { s.EnableDeleteSwipe=b; saveAndUpdate(); });
prefLocalCacheSize.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
@@ -261,6 +262,18 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
prefMsgHighVolumeTest.setOnClickListener((v) -> { if (s.PriorityHigh.ForceVolume) playTestSound(2, prefMsgHighVolumeTest, s.PriorityHigh.SoundSource, s.PriorityHigh.ForceVolumeValue); });
}
private void updateEnabled(boolean prev, boolean now)
{
if (!prev && now)
{
SCNApp.showToast("SimpleCloudNotifier is now enabled", Toast.LENGTH_SHORT);
}
else if (prev && !now)
{
SCNApp.showToast("SimpleCloudNotifier is now disabled\nYou won't recieve new messages.", Toast.LENGTH_LONG);
}
}
private void updateVolume(int idx, int volume)
{
if (mPlayers[idx] != null && mPlayers[idx].isPlaying())

View File

@@ -35,7 +35,7 @@ public class TabAdapter extends FragmentStatePagerAdapter {
{
switch (position)
{
case 0: return "Notifications";
case 0: return "Messages";
case 1: return "Account";
case 2: return "Settings";
default: return null;

View File

@@ -11,13 +11,13 @@
<string name="ic_img_fuel_desc">Icon Fuel</string>
<string name="str_qr_code">QR Code</string>
<string name="str_reset_account">Reset Account</string>
<string name="no_notifications">No notifications</string>
<string name="no_notifications">No messages</string>
<string name="str_not_connected">not connected</string>
<string name="str_reload">reload</string>
<string name="desc_priority_icon">Priority icon</string>
<string name="str_common_settings">Common Settings</string>
<string name="str_enabled">Enabled</string>
<string name="str_localcachesize">Remember the last x notifications locally</string>
<string name="str_localcachesize">Remember the last x messages locally</string>
<string name="str_header_prio0">Notifications (priority 0 - Low)</string>
<string name="str_header_prio1">Notifications (priority 1 - Normal)</string>
<string name="str_header_prio2">Notifications (priority 2 - High)</string>

View File

@@ -1,3 +1,3 @@
#Sat Nov 17 17:19:33 CET 2018
VERSION_NAME=0.0.10
VERSION_CODE=10
#Sun Nov 18 03:24:23 CET 2018
VERSION_NAME=0.0.13
VERSION_CODE=13

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
data/README/badge_apple.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
data/phone.pdn Normal file

Binary file not shown.

BIN
data/phone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@@ -1,13 +1,13 @@
SimpleCloudNotifier is a app to display messages that you can send to your phone with a simple POST request to the right URL.
After you start the app it generates a userID and a private key.
After you start the app it generates a UserID and a UserSecret.
Now you can send your message to https://simplecloudnotifier.blackforestbytes.com/send.php and a notification will be pushed to your phone.
(see https://simplecloudnotifier.blackforestbytes.com/ for an example with curl)
Use it to
- send yourself automated messages from cron jobs
- notify youreself when long-running scripts finish
- notify yourself when long-running scripts finish
- send server error messages directly to your phone
- integrate with other online services

View File

@@ -1,5 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<?php
if (file_exists('/var/www/openwebanalytics/owa_php.php'))
{
require_once('/var/www/openwebanalytics/owa_php.php');
$owa = new owa_php();
$owa->setSiteId('6386b0efc00d2e84ef642525345e1207');
$owa->setPageTitle('API (Short)');
$owa->trackPageView();
}
?>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/css/mini-default.min.css"> <!-- https://minicss.org/docs -->

View File

@@ -0,0 +1,56 @@
<?php
// insert your values here and rename to config.php
return
[
'global' =>
[
'prod' => true,
],
'database' =>
[
'host' => '?',
'database' => '?',
'user' => '?',
'password' => '?',
],
'firebase' =>
[
'type' => 'service_account',
'project_id' => '?',
'private_key_id' => '???',
'client_email' => '???.iam.gserviceaccount.com',
'client_id' => '???',
'auth_uri' => 'https://accounts.google.com/o/oauth2/auth',
'token_uri' => 'https://oauth2.googleapis.com/token',
'auth_provider_x509_cert_url' => 'https://www.googleapis.com/oauth2/v1/certs',
'client_x509_cert_url' => 'https://www.googleapis.com/robot/v1/metadata/x509/???f.iam.gserviceaccount.com',
'private_key' => "-----BEGIN PRIVATE KEY-----\n"
. "??????????\n"
. "-----END PRIVATE KEY-----\n",
'server_key' => '????',
],
'verify_api' =>
[
'package_name' => 'com.blackforestbytes.simplecloudnotifier',
'product_id' => '???',
'clientid' => '???.apps.googleusercontent.com',
'clientsecret' => '???',
'accesstoken' => file_exists('.verify_accesstoken') ? file_get_contents('.verify_accesstoken') : '',
'refreshtoken' => '???',
'scope' => 'https://www.googleapis.com/auth/androidpublisher',
],
'error_reporting' =>
[
'send-mail' => true,
'email-error-target' => '???@???.com',
'email-error-sender' => '???@???.com',
],
];

View File

@@ -1,5 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<?php
if (file_exists('/var/www/openwebanalytics/owa_php.php'))
{
require_once('/var/www/openwebanalytics/owa_php.php');
$owa = new owa_php();
$owa->setSiteId('6386b0efc00d2e84ef642525345e1207');
$owa->setPageTitle('API (Long)');
$owa->trackPageView();
}
?>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/css/mini-default.min.css"> <!-- https://minicss.org/docs -->

View File

@@ -1,5 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<?php
if (file_exists('/var/www/openwebanalytics/owa_php.php'))
{
require_once('/var/www/openwebanalytics/owa_php.php');
$owa = new owa_php();
$owa->setSiteId('6386b0efc00d2e84ef642525345e1207');
$owa->setPageTitle('Index');
$owa->trackPageView();
}
?>
<head>
<meta charset="utf-8">
<title>Simple Cloud Notifications</title>

View File

@@ -34,10 +34,10 @@ function send()
if (xhr.readyState !== 4) return;
console.log('Status: ' + xhr.status);
if (xhr.status === 200)
if (xhr.status === 200 || xhr.status === 401 || xhr.status === 403 || xhr.status === 412)
{
let resp = JSON.parse(xhr.responseText);
if (!resp.success)
if (!resp.success || xhr.status !== 200)
{
if (resp.errhighlight === 101) uid.classList.add('input-invalid');
if (resp.errhighlight === 102) key.classList.add('input-invalid');

View File

@@ -42,7 +42,7 @@ try
$stmt->execute(['uid' => $user_id]);
$datas = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($datas)<=0) die(json_encode(['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']));
if (count($datas)<=0) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']);
$data = $datas[0];
if ($data === null) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'User not found']);