Add Push Notifications feature for iOS and Android.
|
After Width: | Height: | Size: 351 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 204 B |
|
After Width: | Height: | Size: 292 B |
|
After Width: | Height: | Size: 341 B |
|
After Width: | Height: | Size: 337 B |
|
After Width: | Height: | Size: 1 KiB |
|
After Width: | Height: | Size: 543 B |
|
After Width: | Height: | Size: 928 B |
|
After Width: | Height: | Size: 915 B |
BIN
examples/PushNotificationsDemo/BinaryResources/sounds/isntit.caf
Normal file
BIN
examples/PushNotificationsDemo/BinaryResources/sounds/isntit.mp3
Normal file
BIN
examples/PushNotificationsDemo/BinaryResources/sounds/served.caf
Normal file
BIN
examples/PushNotificationsDemo/BinaryResources/sounds/served.mp3
Normal file
BIN
examples/PushNotificationsDemo/BinaryResources/sounds/solemn.caf
Normal file
BIN
examples/PushNotificationsDemo/BinaryResources/sounds/solemn.mp3
Normal file
228
examples/PushNotificationsDemo/JuceLibraryCode/AppConfig.h
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
There's a section below where you can add your own custom code safely, and the
|
||||
Projucer will preserve the contents of that block, but the best way to change
|
||||
any of these definitions is by using the Projucer's project settings.
|
||||
|
||||
Any commented-out settings will assume their default values.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//==============================================================================
|
||||
// [BEGIN_USER_CODE_SECTION]
|
||||
|
||||
// (You can add your own code in this section, and the Projucer will not overwrite it)
|
||||
|
||||
// [END_USER_CODE_SECTION]
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
In accordance with the terms of the JUCE 5 End-Use License Agreement, the
|
||||
JUCE Code in SECTION A cannot be removed, changed or otherwise rendered
|
||||
ineffective unless you have a JUCE Indie or Pro license, or are using JUCE
|
||||
under the GPL v3 license.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
// BEGIN SECTION A
|
||||
|
||||
#ifndef JUCE_DISPLAY_SPLASH_SCREEN
|
||||
#define JUCE_DISPLAY_SPLASH_SCREEN 0
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_REPORT_APP_USAGE
|
||||
#define JUCE_REPORT_APP_USAGE 0
|
||||
#endif
|
||||
|
||||
|
||||
// END SECTION A
|
||||
|
||||
#define JUCE_USE_DARK_SPLASH_SCREEN 1
|
||||
|
||||
//==============================================================================
|
||||
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_audio_devices 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_audio_formats 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_audio_processors 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_core 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_cryptography 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_data_structures 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_events 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_graphics 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_gui_basics 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_gui_extra 1
|
||||
#define JUCE_MODULE_AVAILABLE_juce_opengl 1
|
||||
|
||||
#define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1
|
||||
|
||||
//==============================================================================
|
||||
// juce_audio_devices flags:
|
||||
|
||||
#ifndef JUCE_ASIO
|
||||
//#define JUCE_ASIO 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_WASAPI
|
||||
//#define JUCE_WASAPI 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_WASAPI_EXCLUSIVE
|
||||
//#define JUCE_WASAPI_EXCLUSIVE 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_DIRECTSOUND
|
||||
//#define JUCE_DIRECTSOUND 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_ALSA
|
||||
//#define JUCE_ALSA 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_JACK
|
||||
//#define JUCE_JACK 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_ANDROID_OPENSLES
|
||||
//#define JUCE_USE_ANDROID_OPENSLES 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_WINRT_MIDI
|
||||
//#define JUCE_USE_WINRT_MIDI 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// juce_audio_formats flags:
|
||||
|
||||
#ifndef JUCE_USE_FLAC
|
||||
//#define JUCE_USE_FLAC 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_OGGVORBIS
|
||||
//#define JUCE_USE_OGGVORBIS 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_MP3AUDIOFORMAT
|
||||
//#define JUCE_USE_MP3AUDIOFORMAT 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_LAME_AUDIO_FORMAT
|
||||
//#define JUCE_USE_LAME_AUDIO_FORMAT 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_WINDOWS_MEDIA_FORMAT
|
||||
//#define JUCE_USE_WINDOWS_MEDIA_FORMAT 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// juce_audio_processors flags:
|
||||
|
||||
#ifndef JUCE_PLUGINHOST_VST
|
||||
//#define JUCE_PLUGINHOST_VST 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_PLUGINHOST_VST3
|
||||
//#define JUCE_PLUGINHOST_VST3 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_PLUGINHOST_AU
|
||||
//#define JUCE_PLUGINHOST_AU 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// juce_core flags:
|
||||
|
||||
#ifndef JUCE_FORCE_DEBUG
|
||||
//#define JUCE_FORCE_DEBUG 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_LOG_ASSERTIONS
|
||||
//#define JUCE_LOG_ASSERTIONS 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_CHECK_MEMORY_LEAKS
|
||||
//#define JUCE_CHECK_MEMORY_LEAKS 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
//#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_INCLUDE_ZLIB_CODE
|
||||
//#define JUCE_INCLUDE_ZLIB_CODE 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_CURL
|
||||
//#define JUCE_USE_CURL 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
|
||||
//#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES
|
||||
//#define JUCE_ALLOW_STATIC_NULL_VARIABLES 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// juce_events flags:
|
||||
|
||||
#ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK
|
||||
//#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// juce_graphics flags:
|
||||
|
||||
#ifndef JUCE_USE_COREIMAGE_LOADER
|
||||
//#define JUCE_USE_COREIMAGE_LOADER 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_DIRECTWRITE
|
||||
//#define JUCE_USE_DIRECTWRITE 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// juce_gui_basics flags:
|
||||
|
||||
#ifndef JUCE_ENABLE_REPAINT_DEBUGGING
|
||||
//#define JUCE_ENABLE_REPAINT_DEBUGGING 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_XSHM
|
||||
//#define JUCE_USE_XSHM 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_XRENDER
|
||||
//#define JUCE_USE_XRENDER 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_USE_XCURSOR
|
||||
//#define JUCE_USE_XCURSOR 1
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
// juce_gui_extra flags:
|
||||
|
||||
#ifndef JUCE_WEB_BROWSER
|
||||
//#define JUCE_WEB_BROWSER 1
|
||||
#endif
|
||||
|
||||
#ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR
|
||||
//#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR 1
|
||||
#endif
|
||||
//==============================================================================
|
||||
#ifndef JUCE_STANDALONE_APPLICATION
|
||||
#if defined(JucePlugin_Name) && defined(JucePlugin_Build_Standalone)
|
||||
#define JUCE_STANDALONE_APPLICATION JucePlugin_Build_Standalone
|
||||
#else
|
||||
#define JUCE_STANDALONE_APPLICATION 1
|
||||
#endif
|
||||
#endif
|
||||
9501
examples/PushNotificationsDemo/JuceLibraryCode/BinaryData.cpp
Normal file
80
examples/PushNotificationsDemo/JuceLibraryCode/BinaryData.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* =========================================================================================
|
||||
|
||||
This is an auto-generated file: Any edits you make may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace BinaryData
|
||||
{
|
||||
extern const char* ic_stat_name_png;
|
||||
const int ic_stat_name_pngSize = 351;
|
||||
|
||||
extern const char* ic_stat_name2_png;
|
||||
const int ic_stat_name2_pngSize = 204;
|
||||
|
||||
extern const char* ic_stat_name3_png;
|
||||
const int ic_stat_name3_pngSize = 292;
|
||||
|
||||
extern const char* ic_stat_name4_png;
|
||||
const int ic_stat_name4_pngSize = 341;
|
||||
|
||||
extern const char* ic_stat_name5_png;
|
||||
const int ic_stat_name5_pngSize = 337;
|
||||
|
||||
extern const char* ic_stat_name6_png;
|
||||
const int ic_stat_name6_pngSize = 1059;
|
||||
|
||||
extern const char* ic_stat_name7_png;
|
||||
const int ic_stat_name7_pngSize = 543;
|
||||
|
||||
extern const char* ic_stat_name8_png;
|
||||
const int ic_stat_name8_pngSize = 928;
|
||||
|
||||
extern const char* ic_stat_name9_png;
|
||||
const int ic_stat_name9_pngSize = 915;
|
||||
|
||||
extern const char* ic_stat_name10_png;
|
||||
const int ic_stat_name10_pngSize = 1156;
|
||||
|
||||
extern const char* demonstrative_caf;
|
||||
const int demonstrative_cafSize = 190178;
|
||||
|
||||
extern const char* demonstrative_mp3;
|
||||
const int demonstrative_mp3Size = 127059;
|
||||
|
||||
extern const char* isntit_caf;
|
||||
const int isntit_cafSize = 20654;
|
||||
|
||||
extern const char* isntit_mp3;
|
||||
const int isntit_mp3Size = 11284;
|
||||
|
||||
extern const char* jinglebellssms_caf;
|
||||
const int jinglebellssms_cafSize = 116568;
|
||||
|
||||
extern const char* jinglebellssms_mp3;
|
||||
const int jinglebellssms_mp3Size = 24116;
|
||||
|
||||
extern const char* served_caf;
|
||||
const int served_cafSize = 13922;
|
||||
|
||||
extern const char* served_mp3;
|
||||
const int served_mp3Size = 6687;
|
||||
|
||||
extern const char* solemn_caf;
|
||||
const int solemn_cafSize = 114902;
|
||||
|
||||
extern const char* solemn_mp3;
|
||||
const int solemn_mp3Size = 75650;
|
||||
|
||||
// Points to the start of a list of resource names.
|
||||
extern const char* namedResourceList[];
|
||||
|
||||
// Number of elements in the namedResourceList array.
|
||||
const int namedResourceListSize = 20;
|
||||
|
||||
// If you provide the name of one of the binary resource variables above, this function will
|
||||
// return the corresponding data and its size (or a null pointer if the name isn't found).
|
||||
const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes) throw();
|
||||
}
|
||||
45
examples/PushNotificationsDemo/JuceLibraryCode/JuceHeader.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
This is the header file that your files should include in order to get all the
|
||||
JUCE library headers. You should avoid including the JUCE headers directly in
|
||||
your own source files, because that wouldn't pick up the correct configuration
|
||||
options for your app.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AppConfig.h"
|
||||
|
||||
#include <juce_audio_basics/juce_audio_basics.h>
|
||||
#include <juce_audio_devices/juce_audio_devices.h>
|
||||
#include <juce_audio_formats/juce_audio_formats.h>
|
||||
#include <juce_audio_processors/juce_audio_processors.h>
|
||||
#include <juce_core/juce_core.h>
|
||||
#include <juce_cryptography/juce_cryptography.h>
|
||||
#include <juce_data_structures/juce_data_structures.h>
|
||||
#include <juce_events/juce_events.h>
|
||||
#include <juce_graphics/juce_graphics.h>
|
||||
#include <juce_gui_basics/juce_gui_basics.h>
|
||||
#include <juce_gui_extra/juce_gui_extra.h>
|
||||
#include <juce_opengl/juce_opengl.h>
|
||||
|
||||
#include "BinaryData.h"
|
||||
|
||||
#if ! DONT_SET_USING_JUCE_NAMESPACE
|
||||
// If your code uses a lot of JUCE classes, then this will obviously save you
|
||||
// a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
|
||||
using namespace juce;
|
||||
#endif
|
||||
|
||||
#if ! JUCE_DONT_DECLARE_PROJECTINFO
|
||||
namespace ProjectInfo
|
||||
{
|
||||
const char* const projectName = "PushNotificationsDemo";
|
||||
const char* const versionString = "1.0.0";
|
||||
const int versionNumber = 0x10000;
|
||||
}
|
||||
#endif
|
||||
12
examples/PushNotificationsDemo/JuceLibraryCode/ReadMe.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
Important Note!!
|
||||
================
|
||||
|
||||
The purpose of this folder is to contain files that are auto-generated by the Projucer,
|
||||
and ALL files in this folder will be mercilessly DELETED and completely re-written whenever
|
||||
the Projucer saves your project.
|
||||
|
||||
Therefore, it's a bad idea to make any manual changes to the files in here, or to
|
||||
put any of your own files in here if you don't want to lose them. (Of course you may choose
|
||||
to add the folder's contents to your version-control system so that you can re-merge your own
|
||||
modifications after the Projucer has saved its changes).
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_basics/juce_audio_basics.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_basics/juce_audio_basics.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_devices/juce_audio_devices.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_devices/juce_audio_devices.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_formats/juce_audio_formats.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_formats/juce_audio_formats.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_processors/juce_audio_processors.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_audio_processors/juce_audio_processors.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_core/juce_core.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_core/juce_core.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_cryptography/juce_cryptography.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_cryptography/juce_cryptography.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_data_structures/juce_data_structures.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_data_structures/juce_data_structures.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_events/juce_events.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_events/juce_events.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_graphics/juce_graphics.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_graphics/juce_graphics.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_gui_basics/juce_gui_basics.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_gui_basics/juce_gui_basics.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_gui_extra/juce_gui_extra.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_gui_extra/juce_gui_extra.mm>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_opengl/juce_opengl.cpp>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
|
||||
IMPORTANT! This file is auto-generated each time you save your
|
||||
project - if you alter its contents, your changes may be overwritten!
|
||||
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <juce_opengl/juce_opengl.mm>
|
||||
161
examples/PushNotificationsDemo/PushNotificationsDemo.jucer
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<JUCERPROJECT id="SS6MsF" name="PushNotificationsDemo" displaySplashScreen="0"
|
||||
reportAppUsage="0" splashScreenColour="Dark" projectType="guiapp"
|
||||
version="1.0.0" bundleIdentifier="com.juce.pushnotificationsdemo"
|
||||
includeBinaryInAppConfig="1" cppLanguageStandard="11" jucerVersion="5.1.2">
|
||||
<MAINGROUP id="VaJRhp" name="PushNotificationsDemo">
|
||||
<GROUP id="{712B2C90-FAC6-CCF3-F8F9-ED82411AF5ED}" name="BinaryResources">
|
||||
<GROUP id="{DBF05B65-21C4-E232-D005-149CC3FD4CD6}" name="images">
|
||||
<FILE id="vPFlgX" name="ic_stat_name.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name.png"/>
|
||||
<FILE id="cFrr9F" name="ic_stat_name2.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name2.png"/>
|
||||
<FILE id="d6aZX5" name="ic_stat_name3.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name3.png"/>
|
||||
<FILE id="nkb99Z" name="ic_stat_name4.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name4.png"/>
|
||||
<FILE id="y7x7U0" name="ic_stat_name5.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name5.png"/>
|
||||
<FILE id="IVufcJ" name="ic_stat_name6.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name6.png"/>
|
||||
<FILE id="yYDjas" name="ic_stat_name7.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name7.png"/>
|
||||
<FILE id="uB2QTS" name="ic_stat_name8.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name8.png"/>
|
||||
<FILE id="Jgbx8i" name="ic_stat_name9.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name9.png"/>
|
||||
<FILE id="Q2zkvf" name="ic_stat_name10.png" compile="0" resource="1"
|
||||
file="BinaryResources/images/ic_stat_name10.png"/>
|
||||
</GROUP>
|
||||
<GROUP id="{D7B3F6B4-2E9A-E281-831A-2B67D6D4C4A0}" name="sounds">
|
||||
<FILE id="il8LpK" name="demonstrative.caf" compile="0" resource="1"
|
||||
file="BinaryResources/sounds/demonstrative.caf"/>
|
||||
<FILE id="aUWCPt" name="demonstrative.mp3" compile="0" resource="1"
|
||||
file="BinaryResources/sounds/demonstrative.mp3"/>
|
||||
<FILE id="PWlDpi" name="isntit.caf" compile="0" resource="1" file="BinaryResources/sounds/isntit.caf"/>
|
||||
<FILE id="nbNoVQ" name="isntit.mp3" compile="0" resource="1" file="BinaryResources/sounds/isntit.mp3"/>
|
||||
<FILE id="AheEYO" name="jinglebellssms.caf" compile="0" resource="1"
|
||||
file="BinaryResources/sounds/jinglebellssms.caf"/>
|
||||
<FILE id="WeQemY" name="jinglebellssms.mp3" compile="0" resource="1"
|
||||
file="BinaryResources/sounds/jinglebellssms.mp3"/>
|
||||
<FILE id="TmLrYM" name="served.caf" compile="0" resource="1" file="BinaryResources/sounds/served.caf"/>
|
||||
<FILE id="Ad45fH" name="served.mp3" compile="0" resource="1" file="BinaryResources/sounds/served.mp3"/>
|
||||
<FILE id="qH4XUR" name="solemn.caf" compile="0" resource="1" file="BinaryResources/sounds/solemn.caf"/>
|
||||
<FILE id="cwrEXS" name="solemn.mp3" compile="0" resource="1" file="BinaryResources/sounds/solemn.mp3"/>
|
||||
</GROUP>
|
||||
</GROUP>
|
||||
<GROUP id="{1AF8C966-743E-3F06-189C-AADD83767CB4}" name="Source">
|
||||
<FILE id="f0GZqm" name="MainComponent.cpp" compile="1" resource="0"
|
||||
file="Source/MainComponent.cpp"/>
|
||||
<FILE id="p0ifBx" name="MainComponent.h" compile="0" resource="0" file="Source/MainComponent.h"/>
|
||||
<FILE id="nD1eGt" name="Main.cpp" compile="1" resource="0" file="Source/Main.cpp"/>
|
||||
</GROUP>
|
||||
</MAINGROUP>
|
||||
<EXPORTFORMATS>
|
||||
<XCODE_IPHONE targetFolder="Builds/iOS" iosScreenOrientation="portraitlandscape"
|
||||
iosPushNotifications="1" extraCompilerFlags="-pedantic -Werror -Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion -F../../../../3rd_party/FacebookSDKs-iOS-4 -F../../../../3rd_party/Firebase_ios_sdk/Analytics -F../../../../3rd_party/Firebase_ios_sdk/Messaging"
|
||||
customXcodeResourceFolders="./BinaryResources/sounds">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="PushNotificationsDemo"/>
|
||||
<CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="PushNotificationsDemo"/>
|
||||
</CONFIGURATIONS>
|
||||
<MODULEPATHS>
|
||||
<MODULEPATH id="juce_core" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_events" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_graphics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_data_structures" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_extra" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_cryptography" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_devices" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_formats" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_processors" path="../Repos/roli-software/JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</XCODE_IPHONE>
|
||||
<ANDROIDSTUDIO targetFolder="Builds/Android" androidSDKPath="" androidNDKPath=""
|
||||
androidEnableRemoteNotifications="1" androidRemoteNotificationsConfigFile="../google-services.json"
|
||||
extraCompilerFlags="-pedantic -Werror -Wall -Wshadow -Wno-missing-field-initializers -Wshadow -Wshorten-64-to-32 -Wstrict-aliasing -Wuninitialized -Wunused-parameter -Wconversion -Wsign-compare -Wint-conversion -Woverloaded-virtual -Wreorder -Wconstant-conversion -Wsign-conversion -F../../../../3rd_party/FacebookSDKs-iOS-4 -F../../../../3rd_party/Firebase_ios_sdk/Analytics -F../../../../3rd_party/Firebase_ios_sdk/Messaging"
|
||||
androidVibratePermissionNeeded="1" androidMinimumSDK="26">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION name="Debug" androidArchitectures="armeabi x86" isDebug="1" optimisation="1"
|
||||
targetName="PushNotificationsDemo" androidAdditionalRawValueResources="../BinaryResources/sounds/demonstrative.mp3 ../BinaryResources/sounds/isntit.mp3 ../BinaryResources/sounds/jinglebellssms.mp3 ../BinaryResources/sounds/served.mp3 ../BinaryResources/sounds/solemn.mp3 ../BinaryResources/images/ic_stat_name.png ../BinaryResources/images/ic_stat_name2.png ../BinaryResources/images/ic_stat_name3.png ../BinaryResources/images/ic_stat_name4.png ../BinaryResources/images/ic_stat_name5.png ../BinaryResources/images/ic_stat_name6.png ../BinaryResources/images/ic_stat_name7.png ../BinaryResources/images/ic_stat_name8.png ../BinaryResources/images/ic_stat_name9.png ../BinaryResources/images/ic_stat_name10.png"/>
|
||||
<CONFIGURATION name="Release" androidArchitectures="" isDebug="0" optimisation="3"
|
||||
targetName="PushNotificationsDemo" androidAdditionalRawValueResources="../BinaryResources/sounds/demonstrative.mp3 ../BinaryResources/sounds/isntit.mp3 ../BinaryResources/sounds/jinglebellssms.mp3 ../BinaryResources/sounds/served.mp3 ../BinaryResources/sounds/solemn.mp3 ../BinaryResources/images/ic_stat_name.png ../BinaryResources/images/ic_stat_name2.png ../BinaryResources/images/ic_stat_name3.png ../BinaryResources/images/ic_stat_name4.png ../BinaryResources/images/ic_stat_name5.png ../BinaryResources/images/ic_stat_name6.png ../BinaryResources/images/ic_stat_name7.png ../BinaryResources/images/ic_stat_name8.png ../BinaryResources/images/ic_stat_name9.png ../BinaryResources/images/ic_stat_name10.png"/>
|
||||
</CONFIGURATIONS>
|
||||
<MODULEPATHS>
|
||||
<MODULEPATH id="juce_core" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_events" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_graphics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_data_structures" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_extra" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_cryptography" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_opengl" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_devices" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_formats" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_processors" path="../Repos/roli-software/JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</ANDROIDSTUDIO>
|
||||
<XCODE_MAC targetFolder="Builds/MacOSX">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="PushNotificationsDemo"/>
|
||||
<CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="PushNotificationsDemo"/>
|
||||
</CONFIGURATIONS>
|
||||
<MODULEPATHS>
|
||||
<MODULEPATH id="juce_opengl" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_extra" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_graphics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_events" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_data_structures" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_cryptography" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_core" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_processors" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_formats" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_devices" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</XCODE_MAC>
|
||||
<VS2015 targetFolder="Builds/VisualStudio2015">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
|
||||
isDebug="1" optimisation="1" targetName="PushNotificationsDemo"/>
|
||||
<CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
|
||||
isDebug="0" optimisation="3" targetName="PushNotificationsDemo"/>
|
||||
</CONFIGURATIONS>
|
||||
<MODULEPATHS>
|
||||
<MODULEPATH id="juce_opengl" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_extra" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_gui_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_graphics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_events" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_data_structures" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_cryptography" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_core" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_processors" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_formats" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_devices" path="../Repos/roli-software/JUCE/modules"/>
|
||||
<MODULEPATH id="juce_audio_basics" path="../Repos/roli-software/JUCE/modules"/>
|
||||
</MODULEPATHS>
|
||||
</VS2015>
|
||||
</EXPORTFORMATS>
|
||||
<MODULES>
|
||||
<MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_core" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_cryptography" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_events" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
<MODULE id="juce_opengl" showAllCode="1" useLocalCopy="0" useGlobalPath="1"/>
|
||||
</MODULES>
|
||||
<JUCEOPTIONS/>
|
||||
</JUCERPROJECT>
|
||||
96
examples/PushNotificationsDemo/Source/Main.cpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../JuceLibraryCode/JuceHeader.h"
|
||||
#include "MainComponent.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class PushNotificationsDemoApplication : public JUCEApplication
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
PushNotificationsDemoApplication() {}
|
||||
|
||||
const String getApplicationName() override { return ProjectInfo::projectName; }
|
||||
const String getApplicationVersion() override { return ProjectInfo::versionString; }
|
||||
bool moreThanOneInstanceAllowed() override { return true; }
|
||||
|
||||
//==============================================================================
|
||||
void initialise (const String& commandLine) override
|
||||
{
|
||||
ignoreUnused (commandLine);
|
||||
|
||||
mainWindow = new MainWindow (getApplicationName());
|
||||
}
|
||||
|
||||
void shutdown() override
|
||||
{
|
||||
mainWindow = nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void systemRequestedQuit() override
|
||||
{
|
||||
quit();
|
||||
}
|
||||
|
||||
void anotherInstanceStarted (const String& commandLine) override
|
||||
{
|
||||
ignoreUnused (commandLine);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class MainWindow : public DocumentWindow
|
||||
{
|
||||
public:
|
||||
MainWindow (String name) : DocumentWindow (name,
|
||||
Desktop::getInstance().getDefaultLookAndFeel()
|
||||
.findColour (ResizableWindow::backgroundColourId),
|
||||
DocumentWindow::allButtons)
|
||||
{
|
||||
setUsingNativeTitleBar (true);
|
||||
setContentOwned (new MainContentComponent(), true);
|
||||
|
||||
centreWithSize (getWidth(), getHeight());
|
||||
setVisible (true);
|
||||
}
|
||||
|
||||
void closeButtonPressed() override
|
||||
{
|
||||
JUCEApplication::getInstance()->systemRequestedQuit();
|
||||
}
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
|
||||
};
|
||||
|
||||
private:
|
||||
ScopedPointer<MainWindow> mainWindow;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
START_JUCE_APPLICATION (PushNotificationsDemoApplication)
|
||||
628
examples/PushNotificationsDemo/Source/MainComponent.cpp
Normal file
|
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "MainComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
MainContentComponent::MainContentComponent()
|
||||
{
|
||||
#if JUCE_ANDROID || JUCE_IOS
|
||||
addAndMakeVisible (headerLabel);
|
||||
addAndMakeVisible (mainTabs);
|
||||
addAndMakeVisible (sendButton);
|
||||
#else
|
||||
addAndMakeVisible (notAvailableYetLabel);
|
||||
#endif
|
||||
|
||||
headerLabel.setJustificationType (Justification::centred);
|
||||
notAvailableYetLabel.setJustificationType (Justification::centred);
|
||||
|
||||
const auto colour = getLookAndFeel().findColour (ResizableWindow::backgroundColourId);
|
||||
localNotificationsTabs.addTab ("Req. params", colour, &requiredParamsView, false);
|
||||
localNotificationsTabs.addTab ("Opt. params1", colour, &optionalParamsOneView, false);
|
||||
#if JUCE_ANDROID
|
||||
localNotificationsTabs.addTab ("Opt. params2", colour, &optionalParamsTwoView, false);
|
||||
localNotificationsTabs.addTab ("Opt. params3", colour, &optionalParamsThreeView, false);
|
||||
#endif
|
||||
localNotificationsTabs.addTab ("Aux. actions", colour, &auxActionsView, false);
|
||||
|
||||
mainTabs.addTab ("Local", colour, &localNotificationsTabs, false);
|
||||
mainTabs.addTab ("Remote", colour, &remoteView, false);
|
||||
|
||||
const auto userArea = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
|
||||
#if JUCE_ANDROID || JUCE_IOS
|
||||
setSize (userArea.getWidth(), userArea.getHeight());
|
||||
#else
|
||||
setSize (userArea.getWidth() / 2, userArea.getHeight() / 2);
|
||||
#endif
|
||||
|
||||
sendButton.addListener (this);
|
||||
auxActionsView.getDeliveredNotificationsButton .addListener (this);
|
||||
auxActionsView.removeDeliveredNotifWithIdButton.addListener (this);
|
||||
auxActionsView.removeAllDeliveredNotifsButton .addListener (this);
|
||||
#if JUCE_IOS
|
||||
auxActionsView.getPendingNotificationsButton .addListener (this);
|
||||
auxActionsView.removePendingNotifWithIdButton.addListener (this);
|
||||
auxActionsView.removeAllPendingNotifsButton .addListener (this);
|
||||
#endif
|
||||
|
||||
remoteView.getDeviceTokenButton .addListener (this);
|
||||
remoteView.sendRemoteMessageButton .addListener (this);
|
||||
remoteView.subscribeToSportsButton .addListener (this);
|
||||
remoteView.unsubscribeFromSportsButton.addListener (this);
|
||||
|
||||
optionalParamsThreeView.accentColourButton.addListener (this);
|
||||
optionalParamsThreeView.ledColourButton .addListener (this);
|
||||
|
||||
jassert (PushNotifications::getInstance()->areNotificationsEnabled());
|
||||
|
||||
PushNotifications::getInstance()->addListener (this);
|
||||
|
||||
#if JUCE_IOS
|
||||
optionalParamsOneView.fireInComboBox.addListener (this);
|
||||
PushNotifications::getInstance()->requestPermissionsWithSettings (getIosSettings());
|
||||
#elif JUCE_ANDROID
|
||||
PushNotifications::ChannelGroup cg { "demoGroup", "demo group" };
|
||||
PushNotifications::getInstance()->setupChannels ({{ cg }}, getAndroidChannels());
|
||||
#endif
|
||||
}
|
||||
|
||||
MainContentComponent::~MainContentComponent()
|
||||
{
|
||||
PushNotifications::getInstance()->removeListener (this);
|
||||
}
|
||||
|
||||
void MainContentComponent::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
|
||||
}
|
||||
|
||||
void MainContentComponent::resized()
|
||||
{
|
||||
auto bounds = getLocalBounds().reduced (getWidth() / 20, getHeight() / 40);
|
||||
|
||||
headerLabel.setBounds (bounds.removeFromTop (bounds.proportionOfHeight (0.1f)));
|
||||
|
||||
mainTabs.setBounds (bounds.removeFromTop (bounds.proportionOfHeight (0.8f)));
|
||||
|
||||
sendButton.setBounds (bounds);
|
||||
|
||||
notAvailableYetLabel.setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
void MainContentComponent::buttonClicked (Button* b)
|
||||
{
|
||||
if (b == &sendButton)
|
||||
sendLocalNotification();
|
||||
else if (b == &optionalParamsThreeView.accentColourButton)
|
||||
setupAccentColour();
|
||||
else if (b == &optionalParamsThreeView.ledColourButton)
|
||||
setupLedColour();
|
||||
else if (b == &auxActionsView.getDeliveredNotificationsButton)
|
||||
getDeliveredNotifications();
|
||||
else if (b == &auxActionsView.removeDeliveredNotifWithIdButton)
|
||||
PushNotifications::getInstance()->removeDeliveredNotification (auxActionsView.deliveredNotifIdentifier.getText());
|
||||
else if (b == &auxActionsView.removeAllDeliveredNotifsButton)
|
||||
PushNotifications::getInstance()->removeAllDeliveredNotifications();
|
||||
#if JUCE_IOS
|
||||
else if (b == &auxActionsView.getPendingNotificationsButton)
|
||||
PushNotifications::getInstance()->getPendingLocalNotifications();
|
||||
else if (b == &auxActionsView.removePendingNotifWithIdButton)
|
||||
PushNotifications::getInstance()->removePendingLocalNotification (auxActionsView.pendingNotifIdentifier.getText());
|
||||
else if (b == &auxActionsView.removeAllPendingNotifsButton)
|
||||
PushNotifications::getInstance()->removeAllPendingLocalNotifications();
|
||||
#endif
|
||||
else if (b == &remoteView.getDeviceTokenButton)
|
||||
{
|
||||
String token = PushNotifications::getInstance()->getDeviceToken();
|
||||
|
||||
DBG ("token = " + token);
|
||||
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Device token", token);
|
||||
}
|
||||
#if JUCE_ANDROID
|
||||
else if (b == &remoteView.sendRemoteMessageButton)
|
||||
{
|
||||
StringPairArray data;
|
||||
data.set ("key1", "value1");
|
||||
data.set ("key2", "value2");
|
||||
|
||||
static int id = 100;
|
||||
PushNotifications::getInstance()->sendUpstreamMessage ("872047750958",
|
||||
"com.juce.pushnotificationsdemo",
|
||||
String (id++),
|
||||
"standardType",
|
||||
3600,
|
||||
data);
|
||||
|
||||
}
|
||||
else if (b == &remoteView.subscribeToSportsButton)
|
||||
{
|
||||
PushNotifications::getInstance()->subscribeToTopic ("sports");
|
||||
}
|
||||
else if (b == &remoteView.unsubscribeFromSportsButton)
|
||||
{
|
||||
PushNotifications::getInstance()->unsubscribeFromTopic ("sports");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainContentComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
|
||||
{
|
||||
#if JUCE_IOS
|
||||
if (comboBoxThatHasChanged == &optionalParamsOneView.fireInComboBox)
|
||||
{
|
||||
const bool repeatsAllowed = optionalParamsOneView.fireInComboBox.getSelectedItemIndex() >= 6;
|
||||
|
||||
optionalParamsOneView.repeatButton.setEnabled (repeatsAllowed);
|
||||
|
||||
if (! repeatsAllowed)
|
||||
optionalParamsOneView.repeatButton.setToggleState (false, NotificationType::sendNotification);
|
||||
}
|
||||
#else
|
||||
ignoreUnused (comboBoxThatHasChanged);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainContentComponent::sendLocalNotification()
|
||||
{
|
||||
PushNotifications::Notification n;
|
||||
|
||||
fillRequiredParams (n);
|
||||
fillOptionalParamsOne (n);
|
||||
#if JUCE_ANDROID
|
||||
fillOptionalParamsTwo (n);
|
||||
fillOptionalParamsThree (n);
|
||||
#endif
|
||||
|
||||
if (! n.isValid())
|
||||
{
|
||||
#if JUCE_IOS
|
||||
String requiredFields = "identifier (from iOS 10), title, body and category";
|
||||
#elif JUCE_ANDROID
|
||||
String requiredFields = "channel ID (from Android O), title, body and icon";
|
||||
#else
|
||||
String requiredFields = "all required fields";
|
||||
#endif
|
||||
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Incorrect notifications setup",
|
||||
"Please make sure that "
|
||||
+ requiredFields + " are set.");
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PushNotifications::getInstance()->sendLocalNotification (n);
|
||||
}
|
||||
|
||||
void MainContentComponent::fillRequiredParams (PushNotifications::Notification& n)
|
||||
{
|
||||
n.identifier = requiredParamsView.identifierEditor.getText();
|
||||
n.title = requiredParamsView.titleEditor.getText();
|
||||
n.body = requiredParamsView.bodyEditor.getText();
|
||||
#if JUCE_IOS
|
||||
n.category = requiredParamsView.categories[requiredParamsView.categoryComboBox.getSelectedItemIndex()];
|
||||
#elif JUCE_ANDROID
|
||||
if (requiredParamsView.iconComboBox.getSelectedItemIndex() == 0)
|
||||
n.icon = "ic_stat_name";
|
||||
else if (requiredParamsView.iconComboBox.getSelectedItemIndex() == 1)
|
||||
n.icon = "ic_stat_name2";
|
||||
else if (requiredParamsView.iconComboBox.getSelectedItemIndex() == 2)
|
||||
n.icon = "ic_stat_name3";
|
||||
else if (requiredParamsView.iconComboBox.getSelectedItemIndex() == 3)
|
||||
n.icon = "ic_stat_name4";
|
||||
else
|
||||
n.icon = "ic_stat_name5";
|
||||
|
||||
// Note: this is not strictly speaking required param, just doing it here because it is the fastest way!
|
||||
n.publicVersion = new PushNotifications::Notification();
|
||||
n.publicVersion->identifier = "blahblahblah";
|
||||
n.publicVersion->title = "Public title!";
|
||||
n.publicVersion->body = "Public body!";
|
||||
n.publicVersion->icon = n.icon;
|
||||
|
||||
#if __ANDROID_API__ >= 26
|
||||
n.channelId = String (requiredParamsView.channelIdComboBox.getSelectedItemIndex() + 1);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainContentComponent::fillOptionalParamsOne (PushNotifications::Notification& n)
|
||||
{
|
||||
n.subtitle = optionalParamsOneView.subtitleEditor.getText();
|
||||
n.badgeNumber = optionalParamsOneView.badgeNumberComboBox.getSelectedItemIndex();
|
||||
|
||||
if (optionalParamsOneView.soundToPlayComboBox.getSelectedItemIndex() > 0)
|
||||
n.soundToPlay = URL (optionalParamsOneView.soundToPlayComboBox.getItemText (optionalParamsOneView.soundToPlayComboBox.getSelectedItemIndex()));
|
||||
|
||||
n.properties = JSON::parse (optionalParamsOneView.propertiesEditor.getText());
|
||||
|
||||
#if JUCE_IOS
|
||||
n.triggerIntervalSec = double (optionalParamsOneView.fireInComboBox.getSelectedItemIndex() * 10);
|
||||
n.repeat = optionalParamsOneView.repeatButton.getToggleState();
|
||||
#elif JUCE_ANDROID
|
||||
if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 1)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name6_png, BinaryData::ic_stat_name6_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 2)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name7_png, BinaryData::ic_stat_name7_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 3)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name8_png, BinaryData::ic_stat_name8_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 4)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name9_png, BinaryData::ic_stat_name9_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 5)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name10_png, BinaryData::ic_stat_name10_pngSize);
|
||||
|
||||
n.badgeIconType = (PushNotifications::Notification::BadgeIconType) optionalParamsOneView.badgeIconComboBox.getSelectedItemIndex();
|
||||
n.tickerText = optionalParamsOneView.tickerTextEditor.getText();
|
||||
|
||||
n.shouldAutoCancel = optionalParamsOneView.autoCancelButton.getToggleState();
|
||||
n.alertOnlyOnce = optionalParamsOneView.alertOnlyOnceButton.getToggleState();
|
||||
|
||||
if (optionalParamsOneView.actionsComboBox.getSelectedItemIndex() == 1)
|
||||
{
|
||||
PushNotifications::Notification::Action a, a2;
|
||||
a .style = PushNotifications::Notification::Action::button;
|
||||
a2.style = PushNotifications::Notification::Action::button;
|
||||
a .title = "Ok";
|
||||
a2.title = "Cancel";
|
||||
n.actions.add (a);
|
||||
n.actions.add (a2);
|
||||
}
|
||||
else if (optionalParamsOneView.actionsComboBox.getSelectedItemIndex() == 2)
|
||||
{
|
||||
PushNotifications::Notification::Action a, a2;
|
||||
a .title = "Ok";
|
||||
a2.title = "Cancel";
|
||||
a .style = PushNotifications::Notification::Action::button;
|
||||
a2.style = PushNotifications::Notification::Action::button;
|
||||
a .icon = "ic_stat_name4";
|
||||
a2.icon = "ic_stat_name5";
|
||||
n.actions.add (a);
|
||||
n.actions.add (a2);
|
||||
}
|
||||
else if (optionalParamsOneView.actionsComboBox.getSelectedItemIndex() == 3)
|
||||
{
|
||||
PushNotifications::Notification::Action a, a2;
|
||||
a .title = "Input Text Here";
|
||||
a2.title = "No";
|
||||
a .style = PushNotifications::Notification::Action::text;
|
||||
a2.style = PushNotifications::Notification::Action::button;
|
||||
a .icon = "ic_stat_name4";
|
||||
a2.icon = "ic_stat_name5";
|
||||
a.textInputPlaceholder = "placeholder text ...";
|
||||
n.actions.add (a);
|
||||
n.actions.add (a2);
|
||||
}
|
||||
else if (optionalParamsOneView.actionsComboBox.getSelectedItemIndex() == 4)
|
||||
{
|
||||
PushNotifications::Notification::Action a, a2;
|
||||
a .title = "Input Text Here";
|
||||
a2.title = "No";
|
||||
a .style = PushNotifications::Notification::Action::text;
|
||||
a2.style = PushNotifications::Notification::Action::button;
|
||||
a .icon = "ic_stat_name4";
|
||||
a2.icon = "ic_stat_name5";
|
||||
a.textInputPlaceholder = "placeholder text ...";
|
||||
a.allowedResponses.add ("Response 1");
|
||||
a.allowedResponses.add ("Response 2");
|
||||
a.allowedResponses.add ("Response 3");
|
||||
n.actions.add (a);
|
||||
n.actions.add (a2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainContentComponent::fillOptionalParamsTwo (PushNotifications::Notification& n)
|
||||
{
|
||||
using Notification = PushNotifications::Notification;
|
||||
|
||||
Notification::Progress progress;
|
||||
progress.max = optionalParamsTwoView.progressMaxComboBox.getSelectedItemIndex() * 10;
|
||||
progress.current = optionalParamsTwoView.progressCurrentComboBox.getSelectedItemIndex() * 10;
|
||||
progress.indeterminate = optionalParamsTwoView.progressIndeterminateButton.getToggleState();
|
||||
|
||||
n.progress = progress;
|
||||
n.person = optionalParamsTwoView.personEditor.getText();
|
||||
n.type = Notification::Type (optionalParamsTwoView.categoryComboBox.getSelectedItemIndex());
|
||||
n.priority = Notification::Priority (optionalParamsTwoView.priorityComboBox.getSelectedItemIndex() - 2);
|
||||
n.lockScreenAppearance = Notification::LockScreenAppearance (optionalParamsTwoView.lockScreenVisibilityComboBox.getSelectedItemIndex() - 1);
|
||||
n.groupId = optionalParamsTwoView.groupIdEditor.getText();
|
||||
n.groupSortKey = optionalParamsTwoView.sortKeyEditor.getText();
|
||||
n.groupSummary = optionalParamsTwoView.groupSummaryButton.getToggleState();
|
||||
n.groupAlertBehaviour = Notification::GroupAlertBehaviour (optionalParamsTwoView.groupAlertBehaviourComboBox.getSelectedItemIndex());
|
||||
}
|
||||
|
||||
void MainContentComponent::fillOptionalParamsThree (PushNotifications::Notification& n)
|
||||
{
|
||||
n.accentColour = optionalParamsThreeView.accentColourButton.findColour (TextButton::buttonColourId, false);
|
||||
n.ledColour = optionalParamsThreeView.ledColourButton .findColour (TextButton::buttonColourId, false);
|
||||
|
||||
using Notification = PushNotifications::Notification;
|
||||
Notification::LedBlinkPattern ledBlinkPattern;
|
||||
ledBlinkPattern.msToBeOn = optionalParamsThreeView.ledMsToBeOnComboBox .getSelectedItemIndex() * 200;
|
||||
ledBlinkPattern.msToBeOff = optionalParamsThreeView.ledMsToBeOffComboBox.getSelectedItemIndex() * 200;
|
||||
n.ledBlinkPattern = ledBlinkPattern;
|
||||
|
||||
Array<int> vibrationPattern;
|
||||
|
||||
if (optionalParamsThreeView.vibratorMsToBeOnComboBox .getSelectedItemIndex() > 0 &&
|
||||
optionalParamsThreeView.vibratorMsToBeOffComboBox.getSelectedItemIndex() > 0)
|
||||
{
|
||||
vibrationPattern.add (optionalParamsThreeView.vibratorMsToBeOffComboBox.getSelectedItemIndex() * 500);
|
||||
vibrationPattern.add (optionalParamsThreeView.vibratorMsToBeOnComboBox .getSelectedItemIndex() * 500);
|
||||
vibrationPattern.add (2 * optionalParamsThreeView.vibratorMsToBeOffComboBox.getSelectedItemIndex() * 500);
|
||||
vibrationPattern.add (2 * optionalParamsThreeView.vibratorMsToBeOnComboBox .getSelectedItemIndex() * 500);
|
||||
}
|
||||
|
||||
n.vibrationPattern = vibrationPattern;
|
||||
|
||||
n.localOnly = optionalParamsThreeView.localOnlyButton.getToggleState();
|
||||
n.ongoing = optionalParamsThreeView.ongoingButton.getToggleState();
|
||||
n.timestampVisibility = Notification::TimestampVisibility (optionalParamsThreeView.timestampVisibilityComboBox.getSelectedItemIndex());
|
||||
|
||||
if (optionalParamsThreeView.timeoutAfterComboBox.getSelectedItemIndex() > 0)
|
||||
{
|
||||
auto index = optionalParamsThreeView.timeoutAfterComboBox.getSelectedItemIndex();
|
||||
n.timeoutAfterMs = index * 1000 + 4000;
|
||||
}
|
||||
}
|
||||
|
||||
void MainContentComponent::setupAccentColour()
|
||||
{
|
||||
optionalParamsThreeView.accentColourSelector = new ColourSelector();
|
||||
optionalParamsThreeView.accentColourSelector->setName ("accent colour");
|
||||
optionalParamsThreeView.accentColourSelector->setCurrentColour (optionalParamsThreeView.accentColourButton.findColour (TextButton::buttonColourId));
|
||||
optionalParamsThreeView.accentColourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
|
||||
optionalParamsThreeView.accentColourSelector->setSize (200, 200);
|
||||
optionalParamsThreeView.accentColourSelector->addComponentListener (this);
|
||||
optionalParamsThreeView.accentColourSelector->addChangeListener (this);
|
||||
|
||||
CallOutBox::launchAsynchronously (optionalParamsThreeView.accentColourSelector, optionalParamsThreeView.accentColourButton.getScreenBounds(), nullptr);
|
||||
}
|
||||
|
||||
void MainContentComponent::setupLedColour()
|
||||
{
|
||||
optionalParamsThreeView.ledColourSelector = new ColourSelector();
|
||||
optionalParamsThreeView.ledColourSelector->setName ("led colour");
|
||||
optionalParamsThreeView.ledColourSelector->setCurrentColour (optionalParamsThreeView.ledColourButton.findColour (TextButton::buttonColourId));
|
||||
optionalParamsThreeView.ledColourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
|
||||
optionalParamsThreeView.ledColourSelector->setSize (200, 200);
|
||||
optionalParamsThreeView.ledColourSelector->addComponentListener (this);
|
||||
optionalParamsThreeView.ledColourSelector->addChangeListener (this);
|
||||
|
||||
CallOutBox::launchAsynchronously (optionalParamsThreeView.ledColourSelector, optionalParamsThreeView.accentColourButton.getScreenBounds(), nullptr);
|
||||
}
|
||||
|
||||
void MainContentComponent::changeListenerCallback (ChangeBroadcaster* source)
|
||||
{
|
||||
if (source == optionalParamsThreeView.accentColourSelector)
|
||||
{
|
||||
Colour c = optionalParamsThreeView.accentColourSelector->getCurrentColour();
|
||||
optionalParamsThreeView.accentColourButton.setColour (TextButton::buttonColourId, c);
|
||||
}
|
||||
else if (source == optionalParamsThreeView.ledColourSelector)
|
||||
{
|
||||
Colour c = optionalParamsThreeView.ledColourSelector->getCurrentColour();
|
||||
optionalParamsThreeView.ledColourButton.setColour (TextButton::buttonColourId, c);
|
||||
}
|
||||
}
|
||||
|
||||
void MainContentComponent::componentBeingDeleted (Component& component)
|
||||
{
|
||||
if (&component == optionalParamsThreeView.accentColourSelector)
|
||||
optionalParamsThreeView.accentColourSelector = nullptr;
|
||||
else if (&component == optionalParamsThreeView.ledColourSelector)
|
||||
optionalParamsThreeView.ledColourSelector = nullptr;
|
||||
}
|
||||
|
||||
void MainContentComponent::handleNotification (bool isLocalNotification, const PushNotifications::Notification& n)
|
||||
{
|
||||
ignoreUnused (isLocalNotification);
|
||||
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Received notification",
|
||||
"ID: " + n.identifier
|
||||
+ ", title: " + n.title
|
||||
+ ", body: " + n.body);
|
||||
}
|
||||
|
||||
void MainContentComponent::handleNotificationAction (bool isLocalNotification,
|
||||
const PushNotifications::Notification& n,
|
||||
const String& actionIdentifier,
|
||||
const String& optionalResponse)
|
||||
{
|
||||
ignoreUnused (isLocalNotification);
|
||||
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Received notification action",
|
||||
"ID: " + n.identifier
|
||||
+ ", title: " + n.title
|
||||
+ ", body: " + n.body
|
||||
+ ", action: " + actionIdentifier
|
||||
+ ", optionalResponse: " + optionalResponse);
|
||||
|
||||
PushNotifications::getInstance()->removeDeliveredNotification (n.identifier);
|
||||
}
|
||||
|
||||
void MainContentComponent::localNotificationDismissedByUser (const PushNotifications::Notification& n)
|
||||
{
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Notification dismissed by a user",
|
||||
"ID: " + n.identifier
|
||||
+ ", title: " + n.title
|
||||
+ ", body: " + n.body);
|
||||
}
|
||||
|
||||
void MainContentComponent::getDeliveredNotifications()
|
||||
{
|
||||
PushNotifications::getInstance()->getDeliveredNotifications();
|
||||
}
|
||||
|
||||
void MainContentComponent::deliveredNotificationsListReceived (const Array<PushNotifications::Notification>& notifs)
|
||||
{
|
||||
String text = "Received notifications: ";
|
||||
|
||||
for (const auto& n : notifs)
|
||||
text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), ";
|
||||
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Received notification list", text);
|
||||
}
|
||||
|
||||
void MainContentComponent::pendingLocalNotificationsListReceived (const Array<PushNotifications::Notification>& notifs)
|
||||
{
|
||||
String text = "Pending notifications: ";
|
||||
|
||||
for (const auto& n : notifs)
|
||||
text << "(" << n.identifier << ", " << n.title << ", " << n.body << "), ";
|
||||
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Pending notification list", text);
|
||||
}
|
||||
|
||||
void MainContentComponent::deviceTokenRefreshed (const String& token)
|
||||
{
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Device token refreshed",
|
||||
token);
|
||||
}
|
||||
|
||||
#if JUCE_ANDROID
|
||||
void MainContentComponent::remoteNotificationsDeleted()
|
||||
{
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Remote notifications deleted",
|
||||
"Some of the pending messages were removed!");
|
||||
}
|
||||
|
||||
void MainContentComponent::upstreamMessageSent (const String& messageId)
|
||||
{
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Upstream message sent",
|
||||
"Message id: " + messageId);
|
||||
}
|
||||
|
||||
void MainContentComponent::upstreamMessageSendingError (const String& messageId, const String& error)
|
||||
{
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Upstream message sending error",
|
||||
"Message id: " + messageId
|
||||
+ "\nerror: " + error);
|
||||
}
|
||||
|
||||
Array<PushNotifications::Channel> MainContentComponent::getAndroidChannels()
|
||||
{
|
||||
using Channel = PushNotifications::Channel;
|
||||
|
||||
Channel ch1, ch2, ch3;
|
||||
|
||||
ch1.identifier = "1";
|
||||
ch1.name = "HighImportance";
|
||||
ch1.importance = PushNotifications::Channel::max;
|
||||
ch1.lockScreenAppearance = PushNotifications::Notification::showCompletely;
|
||||
ch1.description = "High Priority Channel for important stuff";
|
||||
ch1.groupId = "demoGroup";
|
||||
ch1.ledColour = Colours::red;
|
||||
ch1.bypassDoNotDisturb = true;
|
||||
ch1.canShowBadge = true;
|
||||
ch1.enableLights = true;
|
||||
ch1.enableVibration = true;
|
||||
ch1.soundToPlay = URL ("demonstrative");
|
||||
ch1.vibrationPattern = { 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200 };
|
||||
|
||||
ch2.identifier = "2";
|
||||
ch2.name = "MediumImportance";
|
||||
ch2.importance = PushNotifications::Channel::normal;
|
||||
ch2.lockScreenAppearance = PushNotifications::Notification::showPartially;
|
||||
ch2.description = "Medium Priority Channel for standard stuff";
|
||||
ch2.groupId = "demoGroup";
|
||||
ch2.ledColour = Colours::yellow;
|
||||
ch2.canShowBadge = true;
|
||||
ch2.enableLights = true;
|
||||
ch2.enableVibration = true;
|
||||
ch2.soundToPlay = URL ("default_os_sound");
|
||||
ch2.vibrationPattern = { 1000, 1000 };
|
||||
|
||||
ch3.identifier = "3";
|
||||
ch3.name = "LowImportance";
|
||||
ch3.importance = PushNotifications::Channel::min;
|
||||
ch3.lockScreenAppearance = PushNotifications::Notification::dontShow;
|
||||
ch3.description = "Low Priority Channel for silly stuff";
|
||||
ch3.groupId = "demoGroup";
|
||||
|
||||
return { ch1, ch2, ch3 };
|
||||
}
|
||||
|
||||
#elif JUCE_IOS
|
||||
PushNotifications::Settings MainContentComponent::getIosSettings()
|
||||
{
|
||||
using Action = PushNotifications::Settings::Action;
|
||||
using Category = PushNotifications::Settings::Category;
|
||||
|
||||
Action okAction;
|
||||
okAction.identifier = "okAction";
|
||||
okAction.title = "OK!";
|
||||
okAction.style = Action::button;
|
||||
okAction.triggerInBackground = true;
|
||||
|
||||
Action cancelAction;
|
||||
cancelAction.identifier = "cancelAction";
|
||||
cancelAction.title = "Cancel";
|
||||
cancelAction.style = Action::button;
|
||||
cancelAction.triggerInBackground = true;
|
||||
cancelAction.destructive = true;
|
||||
|
||||
Action textAction;
|
||||
textAction.identifier = "textAction";
|
||||
textAction.title = "Enter text";
|
||||
textAction.style = Action::text;
|
||||
textAction.triggerInBackground = true;
|
||||
textAction.destructive = false;
|
||||
textAction.textInputButtonText = "Ok";
|
||||
textAction.textInputPlaceholder = "Enter text...";
|
||||
|
||||
Category okCategory;
|
||||
okCategory.identifier = "okCategory";
|
||||
okCategory.actions = { okAction };
|
||||
|
||||
Category okCancelCategory;
|
||||
okCancelCategory.identifier = "okCancelCategory";
|
||||
okCancelCategory.actions = { okAction, cancelAction };
|
||||
|
||||
Category textCategory;
|
||||
textCategory.identifier = "textCategory";
|
||||
textCategory.actions = { textAction };
|
||||
textCategory.sendDismissAction = true;
|
||||
|
||||
PushNotifications::Settings settings;
|
||||
settings.allowAlert = true;
|
||||
settings.allowBadge = true;
|
||||
settings.allowSound = true;
|
||||
settings.categories = { okCategory, okCancelCategory, textCategory };
|
||||
|
||||
return settings;
|
||||
}
|
||||
#endif
|
||||
658
examples/PushNotificationsDemo/Source/MainComponent.h
Normal file
|
|
@ -0,0 +1,658 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../JuceLibraryCode/JuceHeader.h"
|
||||
|
||||
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class MainContentComponent : public Component,
|
||||
private Button::Listener,
|
||||
private ComboBox::Listener,
|
||||
private ChangeListener,
|
||||
private ComponentListener,
|
||||
private PushNotifications::Listener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
MainContentComponent();
|
||||
~MainContentComponent();
|
||||
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
void buttonClicked (Button*) override;
|
||||
void comboBoxChanged (ComboBox* comboBoxThatHasChanged) override;
|
||||
|
||||
void sendLocalNotification();
|
||||
void fillRequiredParams (PushNotifications::Notification& n);
|
||||
void fillOptionalParamsOne (PushNotifications::Notification& n);
|
||||
void fillOptionalParamsTwo (PushNotifications::Notification& n);
|
||||
void fillOptionalParamsThree (PushNotifications::Notification& n);
|
||||
void setupAccentColour();
|
||||
void setupLedColour();
|
||||
|
||||
void getDeliveredNotifications();
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster* source) override;
|
||||
|
||||
void componentBeingDeleted (Component& component) override;
|
||||
|
||||
void handleNotification (bool isLocalNotification, const PushNotifications::Notification& n) override;
|
||||
|
||||
void handleNotificationAction (bool isLocalNotification,
|
||||
const PushNotifications::Notification& n,
|
||||
const juce::String& actionIdentifier,
|
||||
const juce::String& optionalResponse) override;
|
||||
|
||||
void localNotificationDismissedByUser (const PushNotifications::Notification& n) override;
|
||||
|
||||
void deliveredNotificationsListReceived (const Array<PushNotifications::Notification>&) override;
|
||||
|
||||
void pendingLocalNotificationsListReceived (const Array<PushNotifications::Notification>&) override;
|
||||
|
||||
void deviceTokenRefreshed (const String& token) override;
|
||||
|
||||
#if JUCE_ANDROID
|
||||
void remoteNotificationsDeleted() override;
|
||||
|
||||
void upstreamMessageSent (const String& messageId) override;
|
||||
|
||||
void upstreamMessageSendingError (const String& messageId, const String& error) override;
|
||||
|
||||
static Array<PushNotifications::Channel> getAndroidChannels();
|
||||
#elif JUCE_IOS
|
||||
static PushNotifications::Settings getIosSettings();
|
||||
#endif
|
||||
|
||||
struct RequiredParamsView : public Component
|
||||
{
|
||||
RequiredParamsView()
|
||||
{
|
||||
addAndMakeVisible (identifierLabel);
|
||||
addAndMakeVisible (identifierEditor);
|
||||
addAndMakeVisible (titleLabel);
|
||||
addAndMakeVisible (titleEditor);
|
||||
addAndMakeVisible (bodyLabel);
|
||||
addAndMakeVisible (bodyEditor);
|
||||
#if JUCE_IOS
|
||||
addAndMakeVisible (categoryLabel);
|
||||
addAndMakeVisible (categoryComboBox);
|
||||
|
||||
categories.add ("okCategory");
|
||||
categories.add ("okCancelCategory");
|
||||
categories.add ("textCategory");
|
||||
|
||||
for (const auto& c : categories)
|
||||
categoryComboBox.addItem (c, categoryComboBox.getNumItems() + 1);
|
||||
categoryComboBox.setSelectedItemIndex (0);
|
||||
|
||||
#elif JUCE_ANDROID
|
||||
#if __ANDROID_API__ >= 26
|
||||
addAndMakeVisible (channelIdLabel);
|
||||
addAndMakeVisible (channelIdComboBox);
|
||||
|
||||
for (int i = 1; i <= 3; ++i)
|
||||
channelIdComboBox.addItem (String (i), i);
|
||||
channelIdComboBox.setSelectedItemIndex (0);
|
||||
|
||||
#endif
|
||||
addAndMakeVisible (iconLabel);
|
||||
addAndMakeVisible (iconComboBox);
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
iconComboBox.addItem ("icon" + String (i + 1), i + 1);
|
||||
iconComboBox.setSelectedItemIndex (0);
|
||||
#endif
|
||||
|
||||
// For now, to be able to dismiss mobile keyboard.
|
||||
setWantsKeyboardFocus (true);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
const int labelColumnWidth = getWidth() / 3;
|
||||
#if JUCE_ANDROID && __ANDROID_API__ >= 26
|
||||
const int rowHeight = getHeight() / 8;
|
||||
#else
|
||||
const int rowHeight = getHeight() / 7;
|
||||
#endif
|
||||
|
||||
auto layoutRow = [labelColumnWidth] (Rectangle<int> rowBounds, Component& label, Component& editor)
|
||||
{
|
||||
label .setBounds (rowBounds.removeFromLeft (labelColumnWidth));
|
||||
editor.setBounds (rowBounds);
|
||||
};
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
layoutRow (bounds.removeFromTop (rowHeight), identifierLabel, identifierEditor);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), titleLabel, titleEditor);
|
||||
layoutRow (bounds.removeFromTop (4 * rowHeight), bodyLabel, bodyEditor);
|
||||
#if JUCE_IOS
|
||||
layoutRow (bounds.removeFromTop (rowHeight), categoryLabel, categoryComboBox);
|
||||
#elif JUCE_ANDROID
|
||||
#if __ANDROID_API__ >= 26
|
||||
layoutRow (bounds.removeFromTop (rowHeight), channelIdLabel, channelIdComboBox);
|
||||
#endif
|
||||
layoutRow (bounds.removeFromTop (rowHeight), iconLabel, iconComboBox);
|
||||
#endif
|
||||
}
|
||||
Label identifierLabel { "identifierLabel", "Identifier" };
|
||||
TextEditor identifierEditor;
|
||||
Label titleLabel { "titleLabel", "Title" };
|
||||
TextEditor titleEditor;
|
||||
Label bodyLabel { "bodyLabel", "Body" };
|
||||
TextEditor bodyEditor;
|
||||
#if JUCE_IOS
|
||||
StringArray categories;
|
||||
Label categoryLabel { "categoryLabel", "Category" };
|
||||
ComboBox categoryComboBox;
|
||||
#elif JUCE_ANDROID
|
||||
Label channelIdLabel { "channelIdLabel", "Channel ID" };
|
||||
ComboBox channelIdComboBox;
|
||||
Label iconLabel { "iconLabel", "Icon" };
|
||||
ComboBox iconComboBox;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct OptionalParamsOneView : public Component
|
||||
{
|
||||
OptionalParamsOneView()
|
||||
{
|
||||
addAndMakeVisible (subtitleLabel);
|
||||
addAndMakeVisible (subtitleEditor);
|
||||
addAndMakeVisible (badgeNumberLabel);
|
||||
addAndMakeVisible (badgeNumberComboBox);
|
||||
addAndMakeVisible (soundToPlayLabel);
|
||||
addAndMakeVisible (soundToPlayComboBox);
|
||||
addAndMakeVisible (propertiesLabel);
|
||||
addAndMakeVisible (propertiesEditor);
|
||||
#if JUCE_IOS
|
||||
addAndMakeVisible (fireInLabel);
|
||||
addAndMakeVisible (fireInComboBox);
|
||||
addAndMakeVisible (repeatLabel);
|
||||
addAndMakeVisible (repeatButton);
|
||||
|
||||
fireInComboBox.addItem ("Now", 1);
|
||||
|
||||
for (int i = 1; i < 11; ++i)
|
||||
fireInComboBox.addItem (String (10 * i) + "seconds", i + 1);
|
||||
fireInComboBox.setSelectedItemIndex (0);
|
||||
|
||||
#elif JUCE_ANDROID
|
||||
addAndMakeVisible (largeIconLabel);
|
||||
addAndMakeVisible (largeIconComboBox);
|
||||
addAndMakeVisible (badgeIconLabel);
|
||||
addAndMakeVisible (badgeIconComboBox);
|
||||
addAndMakeVisible (tickerTextLabel);
|
||||
addAndMakeVisible (tickerTextEditor);
|
||||
addAndMakeVisible (autoCancelLabel);
|
||||
addAndMakeVisible (autoCancelButton);
|
||||
addAndMakeVisible (alertOnlyOnceLabel);
|
||||
addAndMakeVisible (alertOnlyOnceButton);
|
||||
addAndMakeVisible (actionsLabel);
|
||||
addAndMakeVisible (actionsComboBox);
|
||||
|
||||
largeIconComboBox.addItem ("none", 1);
|
||||
|
||||
for (int i = 1; i < 5; ++i)
|
||||
largeIconComboBox.addItem ("icon" + String (i), i + 1);
|
||||
largeIconComboBox.setSelectedItemIndex (0);
|
||||
|
||||
badgeIconComboBox.addItem ("none", 1);
|
||||
badgeIconComboBox.addItem ("small", 2);
|
||||
badgeIconComboBox.addItem ("large", 3);
|
||||
badgeIconComboBox.setSelectedItemIndex (2);
|
||||
|
||||
actionsComboBox.addItem ("none", 1);
|
||||
actionsComboBox.addItem ("ok-cancel", 2);
|
||||
actionsComboBox.addItem ("ok-cancel-icons", 3);
|
||||
actionsComboBox.addItem ("text-input", 4);
|
||||
actionsComboBox.addItem ("text-input-limited_responses", 5);
|
||||
actionsComboBox.setSelectedItemIndex (0);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
badgeNumberComboBox.addItem (String (i), i + 1);
|
||||
badgeNumberComboBox.setSelectedItemIndex (0);
|
||||
|
||||
#if JUCE_IOS
|
||||
String prefix = "sounds/";
|
||||
String extension = ".caf";
|
||||
#else
|
||||
String prefix;
|
||||
String extension;
|
||||
#endif
|
||||
|
||||
soundToPlayComboBox.addItem ("none", 1);
|
||||
soundToPlayComboBox.addItem ("default_os_sound", 2);
|
||||
soundToPlayComboBox.addItem (prefix + "demonstrative" + extension, 3);
|
||||
soundToPlayComboBox.addItem (prefix + "isntit" + extension, 4);
|
||||
soundToPlayComboBox.addItem (prefix + "jinglebellssms" + extension, 5);
|
||||
soundToPlayComboBox.addItem (prefix + "served" + extension, 6);
|
||||
soundToPlayComboBox.addItem (prefix + "solemn" + extension, 7);
|
||||
soundToPlayComboBox.setSelectedItemIndex (1);
|
||||
|
||||
// For now, to be able to dismiss mobile keyboard.
|
||||
setWantsKeyboardFocus (true);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
const int labelColumnWidth = getWidth() / 3;
|
||||
#if JUCE_ANDROID
|
||||
const int rowHeight = getHeight() / 12;
|
||||
#else
|
||||
const int rowHeight = getHeight() / 8;
|
||||
#endif
|
||||
|
||||
auto layoutRow = [labelColumnWidth] (Rectangle<int> rowBounds, Component& label, Component& editor)
|
||||
{
|
||||
label .setBounds (rowBounds.removeFromLeft (labelColumnWidth));
|
||||
editor.setBounds (rowBounds);
|
||||
};
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
layoutRow (bounds.removeFromTop (rowHeight), subtitleLabel, subtitleEditor);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), badgeNumberLabel, badgeNumberComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), soundToPlayLabel, soundToPlayComboBox);
|
||||
layoutRow (bounds.removeFromTop (3 * rowHeight), propertiesLabel, propertiesEditor);
|
||||
#if JUCE_IOS
|
||||
layoutRow (bounds.removeFromTop (rowHeight), fireInLabel, fireInComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), repeatLabel, repeatButton);
|
||||
#elif JUCE_ANDROID
|
||||
layoutRow (bounds.removeFromTop (rowHeight), largeIconLabel, largeIconComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), badgeIconLabel, badgeIconComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), tickerTextLabel, tickerTextEditor);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), autoCancelLabel, autoCancelButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), alertOnlyOnceLabel, alertOnlyOnceButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), actionsLabel, actionsComboBox);
|
||||
#endif
|
||||
}
|
||||
Label subtitleLabel { "subtitleLabel", "Subtitle" };
|
||||
TextEditor subtitleEditor;
|
||||
Label badgeNumberLabel { "badgeNumberLabel", "BadgeNumber" };
|
||||
ComboBox badgeNumberComboBox;
|
||||
Label soundToPlayLabel { "soundToPlayLabel", "SoundToPlay" };
|
||||
ComboBox soundToPlayComboBox;
|
||||
Label propertiesLabel { "propertiesLabel", "Properties" };
|
||||
TextEditor propertiesEditor;
|
||||
#if JUCE_IOS
|
||||
Label fireInLabel { "fireInLabel", "Fire in" };
|
||||
ComboBox fireInComboBox;
|
||||
Label repeatLabel { "repeatLabel", "Repeat" };
|
||||
ToggleButton repeatButton;
|
||||
#elif JUCE_ANDROID
|
||||
Label largeIconLabel { "largeIconLabel", "Large Icon" };
|
||||
ComboBox largeIconComboBox;
|
||||
Label badgeIconLabel { "badgeIconLabel", "Badge Icon" };
|
||||
ComboBox badgeIconComboBox;
|
||||
Label tickerTextLabel { "tickerTextLabel", "Ticker Text" };
|
||||
TextEditor tickerTextEditor;
|
||||
Label autoCancelLabel { "autoCancelLabel", "AutoCancel" };
|
||||
ToggleButton autoCancelButton;
|
||||
Label alertOnlyOnceLabel { "alertOnlyOnceLabel", "AlertOnlyOnce" };
|
||||
ToggleButton alertOnlyOnceButton;
|
||||
Label actionsLabel { "actionsLabel", "Actions" };
|
||||
ComboBox actionsComboBox;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct OptionalParamsTwoView : public Component
|
||||
{
|
||||
OptionalParamsTwoView()
|
||||
{
|
||||
addAndMakeVisible (progressMaxLabel);
|
||||
addAndMakeVisible (progressMaxComboBox);
|
||||
addAndMakeVisible (progressCurrentLabel);
|
||||
addAndMakeVisible (progressCurrentComboBox);
|
||||
addAndMakeVisible (progressIndeterminateLabel);
|
||||
addAndMakeVisible (progressIndeterminateButton);
|
||||
addAndMakeVisible (categoryLabel);
|
||||
addAndMakeVisible (categoryComboBox);
|
||||
addAndMakeVisible (priorityLabel);
|
||||
addAndMakeVisible (priorityComboBox);
|
||||
addAndMakeVisible (personLabel);
|
||||
addAndMakeVisible (personEditor);
|
||||
addAndMakeVisible (lockScreenVisibilityLabel);
|
||||
addAndMakeVisible (lockScreenVisibilityComboBox);
|
||||
addAndMakeVisible (groupIdLabel);
|
||||
addAndMakeVisible (groupIdEditor);
|
||||
addAndMakeVisible (sortKeyLabel);
|
||||
addAndMakeVisible (sortKeyEditor);
|
||||
addAndMakeVisible (groupSummaryLabel);
|
||||
addAndMakeVisible (groupSummaryButton);
|
||||
addAndMakeVisible (groupAlertBehaviourLabel);
|
||||
addAndMakeVisible (groupAlertBehaviourComboBox);
|
||||
|
||||
for (int i = 0; i < 11; ++i)
|
||||
{
|
||||
progressMaxComboBox .addItem (String (i * 10) + "%", i + 1);
|
||||
progressCurrentComboBox.addItem (String (i * 10) + "%", i + 1);
|
||||
}
|
||||
|
||||
progressMaxComboBox .setSelectedItemIndex (0);
|
||||
progressCurrentComboBox.setSelectedItemIndex (0);
|
||||
|
||||
categoryComboBox.addItem ("unspecified", 1);
|
||||
categoryComboBox.addItem ("alarm", 2);
|
||||
categoryComboBox.addItem ("call", 3);
|
||||
categoryComboBox.addItem ("email", 4);
|
||||
categoryComboBox.addItem ("error", 5);
|
||||
categoryComboBox.addItem ("event", 6);
|
||||
categoryComboBox.addItem ("message", 7);
|
||||
categoryComboBox.addItem ("progress", 8);
|
||||
categoryComboBox.addItem ("promo", 9);
|
||||
categoryComboBox.addItem ("recommendation", 10);
|
||||
categoryComboBox.addItem ("reminder", 11);
|
||||
categoryComboBox.addItem ("service", 12);
|
||||
categoryComboBox.addItem ("social", 13);
|
||||
categoryComboBox.addItem ("status", 14);
|
||||
categoryComboBox.addItem ("system", 15);
|
||||
categoryComboBox.addItem ("transport", 16);
|
||||
categoryComboBox.setSelectedItemIndex (0);
|
||||
|
||||
for (int i = -2; i < 3; ++i)
|
||||
priorityComboBox.addItem (String (i), i + 3);
|
||||
priorityComboBox.setSelectedItemIndex (2);
|
||||
|
||||
lockScreenVisibilityComboBox.addItem ("don't show", 1);
|
||||
lockScreenVisibilityComboBox.addItem ("show partially", 2);
|
||||
lockScreenVisibilityComboBox.addItem ("show completely", 3);
|
||||
lockScreenVisibilityComboBox.setSelectedItemIndex (1);
|
||||
|
||||
groupAlertBehaviourComboBox.addItem ("alert all", 1);
|
||||
groupAlertBehaviourComboBox.addItem ("alert summary", 2);
|
||||
groupAlertBehaviourComboBox.addItem ("alert children", 3);
|
||||
groupAlertBehaviourComboBox.setSelectedItemIndex (0);
|
||||
|
||||
// For now, to be able to dismiss mobile keyboard.
|
||||
setWantsKeyboardFocus (true);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
const int labelColumnWidth = getWidth() / 3;
|
||||
const int rowHeight = getHeight() / 11;
|
||||
|
||||
auto layoutRow = [labelColumnWidth] (Rectangle<int> rowBounds, Component& label, Component& editor)
|
||||
{
|
||||
label .setBounds (rowBounds.removeFromLeft (labelColumnWidth));
|
||||
editor.setBounds (rowBounds);
|
||||
};
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
layoutRow (bounds.removeFromTop (rowHeight), progressMaxLabel, progressMaxComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), progressCurrentLabel, progressCurrentComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), progressIndeterminateLabel, progressIndeterminateButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), categoryLabel, categoryComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), priorityLabel, priorityComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), personLabel, personEditor);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), lockScreenVisibilityLabel, lockScreenVisibilityComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), groupIdLabel, groupIdEditor);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), sortKeyLabel, sortKeyEditor);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), groupSummaryLabel, groupSummaryButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), groupAlertBehaviourLabel, groupAlertBehaviourComboBox);
|
||||
}
|
||||
|
||||
Label progressMaxLabel { "progressMaxLabel", "ProgressMax" };
|
||||
ComboBox progressMaxComboBox;
|
||||
Label progressCurrentLabel { "progressCurrentLabel", "ProgressCurrent" };
|
||||
ComboBox progressCurrentComboBox;
|
||||
Label progressIndeterminateLabel { "progressIndeterminateLabel", "ProgressIndeterminate" };
|
||||
ToggleButton progressIndeterminateButton;
|
||||
Label categoryLabel { "categoryLabel", "Category" };
|
||||
ComboBox categoryComboBox;
|
||||
Label priorityLabel { "priorityLabel", "Priority" };
|
||||
ComboBox priorityComboBox;
|
||||
Label personLabel { "personLabel", "Person" };
|
||||
TextEditor personEditor;
|
||||
Label lockScreenVisibilityLabel { "lockScreenVisibilityLabel", "LockScreenVisibility" };
|
||||
ComboBox lockScreenVisibilityComboBox;
|
||||
Label groupIdLabel { "groupIdLabel", "GroupID" };
|
||||
TextEditor groupIdEditor;
|
||||
Label sortKeyLabel { "sortKeyLabel", "SortKey" };
|
||||
TextEditor sortKeyEditor;
|
||||
Label groupSummaryLabel { "groupSummaryLabel", "GroupSummary" };
|
||||
ToggleButton groupSummaryButton;
|
||||
Label groupAlertBehaviourLabel { "groupAlertBehaviourLabel", "GroupAlertBehaviour" };
|
||||
ComboBox groupAlertBehaviourComboBox;
|
||||
};
|
||||
|
||||
struct OptionalParamsThreeView : public Component
|
||||
{
|
||||
OptionalParamsThreeView()
|
||||
{
|
||||
addAndMakeVisible (accentColourLabel);
|
||||
addAndMakeVisible (accentColourButton);
|
||||
addAndMakeVisible (ledColourLabel);
|
||||
addAndMakeVisible (ledColourButton);
|
||||
addAndMakeVisible (ledMsToBeOnLabel);
|
||||
addAndMakeVisible (ledMsToBeOnComboBox);
|
||||
addAndMakeVisible (ledMsToBeOffLabel);
|
||||
addAndMakeVisible (ledMsToBeOffComboBox);
|
||||
addAndMakeVisible (vibratorMsToBeOnLabel);
|
||||
addAndMakeVisible (vibratorMsToBeOnComboBox);
|
||||
addAndMakeVisible (vibratorMsToBeOffLabel);
|
||||
addAndMakeVisible (vibratorMsToBeOffComboBox);
|
||||
addAndMakeVisible (localOnlyLabel);
|
||||
addAndMakeVisible (localOnlyButton);
|
||||
addAndMakeVisible (ongoingLabel);
|
||||
addAndMakeVisible (ongoingButton);
|
||||
addAndMakeVisible (timestampVisibilityLabel);
|
||||
addAndMakeVisible (timestampVisibilityComboBox);
|
||||
addAndMakeVisible (timeoutAfterLabel);
|
||||
addAndMakeVisible (timeoutAfterComboBox);
|
||||
|
||||
timeoutAfterComboBox.addItem ("No timeout", 1);
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
ledMsToBeOnComboBox .addItem (String (i * 200) + "ms", i + 1);
|
||||
ledMsToBeOffComboBox .addItem (String (i * 200) + "ms", i + 1);
|
||||
vibratorMsToBeOnComboBox .addItem (String (i * 500) + "ms", i + 1);
|
||||
vibratorMsToBeOffComboBox.addItem (String (i * 500) + "ms", i + 1);
|
||||
timeoutAfterComboBox.addItem (String (5000 + 1000 * i) + "ms", i + 2);
|
||||
}
|
||||
|
||||
ledMsToBeOnComboBox .setSelectedItemIndex (5);
|
||||
ledMsToBeOffComboBox .setSelectedItemIndex (5);
|
||||
vibratorMsToBeOnComboBox .setSelectedItemIndex (0);
|
||||
vibratorMsToBeOffComboBox.setSelectedItemIndex (0);
|
||||
timeoutAfterComboBox.setSelectedItemIndex (0);
|
||||
|
||||
timestampVisibilityComboBox.addItem ("off", 1);
|
||||
timestampVisibilityComboBox.addItem ("on", 2);
|
||||
timestampVisibilityComboBox.addItem ("chronometer", 3);
|
||||
timestampVisibilityComboBox.addItem ("count down", 4);
|
||||
timestampVisibilityComboBox.setSelectedItemIndex (1);
|
||||
|
||||
// For now, to be able to dismiss mobile keyboard.
|
||||
setWantsKeyboardFocus (true);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
const int labelColumnWidth = getWidth() / 3;
|
||||
const int rowHeight = getHeight() / 10;
|
||||
|
||||
auto layoutRow = [labelColumnWidth] (Rectangle<int> rowBounds, Component& label, Component& editor)
|
||||
{
|
||||
label .setBounds (rowBounds.removeFromLeft (labelColumnWidth));
|
||||
editor.setBounds (rowBounds);
|
||||
};
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
layoutRow (bounds.removeFromTop (rowHeight), accentColourLabel, accentColourButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), ledColourLabel, ledColourButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), ledMsToBeOnLabel, ledMsToBeOnComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), ledMsToBeOffLabel, ledMsToBeOffComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), vibratorMsToBeOnLabel, vibratorMsToBeOnComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), vibratorMsToBeOffLabel, vibratorMsToBeOffComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), localOnlyLabel, localOnlyButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), ongoingLabel, ongoingButton);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), timestampVisibilityLabel, timestampVisibilityComboBox);
|
||||
layoutRow (bounds.removeFromTop (rowHeight), timeoutAfterLabel, timeoutAfterComboBox);
|
||||
}
|
||||
|
||||
Label accentColourLabel { "accentColourLabel", "AccentColour" };
|
||||
TextButton accentColourButton;
|
||||
Label ledColourLabel { "ledColourLabel", "LedColour" };
|
||||
TextButton ledColourButton;
|
||||
Label ledMsToBeOnLabel { "ledMsToBeOnLabel", "LedMsToBeOn" };
|
||||
ComboBox ledMsToBeOnComboBox;
|
||||
Label ledMsToBeOffLabel { "ledMsToBeOffLabel", "LedMsToBeOff" };
|
||||
ComboBox ledMsToBeOffComboBox;
|
||||
Label vibratorMsToBeOnLabel { "vibratorMsToBeOnLabel", "VibrationMsToBeOn" };
|
||||
ComboBox vibratorMsToBeOnComboBox;
|
||||
Label vibratorMsToBeOffLabel { "vibratorMsToBeOffLabel", "VibrationMsToBeOff" };
|
||||
ComboBox vibratorMsToBeOffComboBox;
|
||||
Label localOnlyLabel { "localOnlyLabel", "LocalOnly" };
|
||||
ToggleButton localOnlyButton;
|
||||
Label ongoingLabel { "ongoingLabel", "Ongoing" };
|
||||
ToggleButton ongoingButton;
|
||||
Label timestampVisibilityLabel { "timestampVisibilityLabel", "TimestampMode" };
|
||||
ComboBox timestampVisibilityComboBox;
|
||||
Label timeoutAfterLabel { "timeoutAfterLabel", "Timeout After Ms" };
|
||||
ComboBox timeoutAfterComboBox;
|
||||
|
||||
ColourSelector* accentColourSelector = nullptr;
|
||||
ColourSelector* ledColourSelector = nullptr;
|
||||
};
|
||||
|
||||
struct AuxActionsView : public Component
|
||||
{
|
||||
AuxActionsView()
|
||||
{
|
||||
addAndMakeVisible (getDeliveredNotificationsButton);
|
||||
addAndMakeVisible (removeDeliveredNotifWithIdButton);
|
||||
addAndMakeVisible (deliveredNotifIdentifier);
|
||||
addAndMakeVisible (removeAllDeliveredNotifsButton);
|
||||
#if JUCE_IOS
|
||||
addAndMakeVisible (getPendingNotificationsButton);
|
||||
addAndMakeVisible (removePendingNotifWithIdButton);
|
||||
addAndMakeVisible (pendingNotifIdentifier);
|
||||
addAndMakeVisible (removeAllPendingNotifsButton);
|
||||
#endif
|
||||
|
||||
// For now, to be able to dismiss mobile keyboard.
|
||||
setWantsKeyboardFocus (true);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
const int columnWidth = getWidth();
|
||||
|
||||
const int rowHeight = getHeight() / 6;
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
getDeliveredNotificationsButton .setBounds (bounds.removeFromTop (rowHeight));
|
||||
|
||||
auto rowBounds = bounds.removeFromTop (rowHeight);
|
||||
removeDeliveredNotifWithIdButton.setBounds (rowBounds.removeFromLeft (columnWidth / 2));
|
||||
deliveredNotifIdentifier .setBounds (rowBounds);
|
||||
|
||||
removeAllDeliveredNotifsButton .setBounds (bounds.removeFromTop (rowHeight));
|
||||
|
||||
#if JUCE_IOS
|
||||
getPendingNotificationsButton .setBounds (bounds.removeFromTop (rowHeight));
|
||||
|
||||
rowBounds = bounds.removeFromTop (rowHeight);
|
||||
removePendingNotifWithIdButton.setBounds (rowBounds.removeFromLeft (columnWidth / 2));
|
||||
pendingNotifIdentifier .setBounds (rowBounds);
|
||||
|
||||
removeAllPendingNotifsButton .setBounds (bounds.removeFromTop (rowHeight));
|
||||
#endif
|
||||
}
|
||||
|
||||
TextButton getDeliveredNotificationsButton { "Get Delivered Notifications" };
|
||||
TextButton removeDeliveredNotifWithIdButton { "Remove Delivered Notif With ID:" };
|
||||
TextEditor deliveredNotifIdentifier;
|
||||
TextButton removeAllDeliveredNotifsButton { "Remove All Delivered Notifs" };
|
||||
#if JUCE_IOS
|
||||
TextButton getPendingNotificationsButton { "Get Pending Notifications" };
|
||||
TextButton removePendingNotifWithIdButton { "Remove Pending Notif With ID:" };
|
||||
TextEditor pendingNotifIdentifier;
|
||||
TextButton removeAllPendingNotifsButton { "Remove All Pending Notifs" };
|
||||
#endif
|
||||
};
|
||||
|
||||
struct RemoteView : public Component
|
||||
{
|
||||
RemoteView()
|
||||
{
|
||||
addAndMakeVisible (getDeviceTokenButton);
|
||||
#if JUCE_ANDROID
|
||||
addAndMakeVisible (sendRemoteMessageButton);
|
||||
addAndMakeVisible (subscribeToSportsButton);
|
||||
addAndMakeVisible (unsubscribeFromSportsButton);
|
||||
#endif
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
const int rowSize = getHeight () / 10;
|
||||
|
||||
auto bounds = getLocalBounds().reduced (getWidth() / 10, getHeight() / 10);
|
||||
|
||||
bounds.removeFromTop (2 * rowSize);
|
||||
|
||||
getDeviceTokenButton .setBounds (bounds.removeFromTop (rowSize));
|
||||
sendRemoteMessageButton .setBounds (bounds.removeFromTop (rowSize));
|
||||
subscribeToSportsButton .setBounds (bounds.removeFromTop (rowSize));
|
||||
unsubscribeFromSportsButton.setBounds (bounds.removeFromTop (rowSize));
|
||||
}
|
||||
|
||||
TextButton getDeviceTokenButton { "GetDeviceToken" };
|
||||
TextButton sendRemoteMessageButton { "SendRemoteMessage" };
|
||||
TextButton subscribeToSportsButton { "SubscribeToSports" };
|
||||
TextButton unsubscribeFromSportsButton { "UnsubscribeFromSports" };
|
||||
};
|
||||
|
||||
Label headerLabel { "headerLabel", "Push Notifications Demo" };
|
||||
RequiredParamsView requiredParamsView;
|
||||
OptionalParamsOneView optionalParamsOneView;
|
||||
OptionalParamsTwoView optionalParamsTwoView;
|
||||
OptionalParamsThreeView optionalParamsThreeView;
|
||||
AuxActionsView auxActionsView;
|
||||
TabbedComponent localNotificationsTabs { TabbedButtonBar::TabsAtTop };
|
||||
RemoteView remoteView;
|
||||
TabbedComponent mainTabs { TabbedButtonBar::TabsAtTop };
|
||||
TextButton sendButton { "Send!" };
|
||||
Label notAvailableYetLabel { "notAvailableYetLabel", "Push Notifications feature is not available on this platform yet!" };
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
|
||||
};
|
||||
42
examples/PushNotificationsDemo/google-services.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "3137221487",
|
||||
"firebase_url": "https://pushnotificationsdemo-1c714.firebaseio.com",
|
||||
"project_id": "pushnotificationsdemo-1c714",
|
||||
"storage_bucket": "pushnotificationsdemo-1c714.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:3137221487:android:8fdcd861a33b035c",
|
||||
"android_client_info": {
|
||||
"package_name": "com.juce.pushnotificationsdemo"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "3137221487-uftk61ukltbi07dmejslgt0d6qnml0oo.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDPpqphjiEEYI3sJGptrebN5Z52GkOG4Wo"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"analytics_service": {
|
||||
"status": 1
|
||||
},
|
||||
"appinvite_service": {
|
||||
"status": 1,
|
||||
"other_platform_oauth_client": []
|
||||
},
|
||||
"ads_service": {
|
||||
"status": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
|
|
@ -107,9 +107,12 @@ public:
|
|||
|
||||
CachedValue<bool> androidInternetNeeded, androidMicNeeded, androidBluetoothNeeded,
|
||||
androidExternalReadPermission, androidExternalWritePermission,
|
||||
androidInAppBillingPermission;
|
||||
androidInAppBillingPermission, androidVibratePermission;
|
||||
CachedValue<String> androidOtherPermissions;
|
||||
|
||||
CachedValue<bool> androidEnableRemoteNotifications;
|
||||
CachedValue<String> androidRemoteNotificationsConfigFile;
|
||||
|
||||
CachedValue<String> androidKeyStore, androidKeyStorePass, androidKeyAlias, androidKeyAliasPass;
|
||||
|
||||
CachedValue<String> gradleVersion, androidPluginVersion, gradleToolchain, buildToolsVersion;
|
||||
|
|
@ -135,7 +138,10 @@ public:
|
|||
androidExternalReadPermission (settings, Ids::androidExternalReadNeeded, nullptr, true),
|
||||
androidExternalWritePermission (settings, Ids::androidExternalWriteNeeded, nullptr, true),
|
||||
androidInAppBillingPermission (settings, Ids::androidInAppBilling, nullptr, false),
|
||||
androidVibratePermission (settings, Ids::androidVibratePermissionNeeded, nullptr, false),
|
||||
androidOtherPermissions (settings, Ids::androidOtherPermissions, nullptr),
|
||||
androidEnableRemoteNotifications (settings, Ids::androidEnableRemoteNotifications, nullptr, false),
|
||||
androidRemoteNotificationsConfigFile (settings, Ids::androidRemoteNotificationsConfigFile, nullptr, ""),
|
||||
androidKeyStore (settings, Ids::androidKeyStore, nullptr, "${user.home}/.android/debug.keystore"),
|
||||
androidKeyStorePass (settings, Ids::androidKeyStorePass, nullptr, "android"),
|
||||
androidKeyAlias (settings, Ids::androidKeyAlias, nullptr, "androiddebugkey"),
|
||||
|
|
@ -327,6 +333,9 @@ protected:
|
|||
Value getAdditionalXmlResourcesValue() { return getValue (Ids::androidAdditionalXmlValueResources); }
|
||||
String getAdditionalXmlResources() const { return config [Ids::androidAdditionalXmlValueResources]; }
|
||||
|
||||
Value getAdditionalRawResourcesValue() { return getValue (Ids::androidAdditionalRawValueResources); }
|
||||
String getAdditionalRawResources() const { return config [Ids::androidAdditionalRawValueResources]; }
|
||||
|
||||
Value getCustomStringsXmlValue() { return getValue (Ids::androidCustomStringXmlElements); }
|
||||
String getCustomStringsXml() const { return config [Ids::androidCustomStringXmlElements]; }
|
||||
|
||||
|
|
@ -343,8 +352,14 @@ protected:
|
|||
"Paths to additional \"value resource\" files in XML format that should be included in the app (one per line). "
|
||||
"If you have additional XML resources that should be treated as value resources, add them here.");
|
||||
|
||||
props.add (new TextPropertyComponent (getCustomStringsXmlValue(), "Custom string.xml elements", 8192, true),
|
||||
"You can specify custom XML elements that will be added to string.xml as children of <resources> element.");
|
||||
props.add (new TextPropertyComponent (getAdditionalRawResourcesValue(), "Extra Android Raw Resources", 2048, true),
|
||||
"Paths to additional \"raw resource\" files that should be included in the app (one per line). "
|
||||
"Resource file names must contain only lowercase a-z, 0-9 or underscore.");
|
||||
|
||||
props.add (new TextPropertyComponent (getCustomStringsXmlValue(), "Custom string resources", 8192, true),
|
||||
"Custom XML resources that will be added to string.xml as children of <resources> element. "
|
||||
"Example: \n<string name=\"value\">text</string>\n"
|
||||
"<string name2=\"value2\">text2</string>\n");
|
||||
}
|
||||
|
||||
String getProductFlavourNameIdentifier() const
|
||||
|
|
@ -533,12 +548,24 @@ private:
|
|||
mo << " }" << newLine;
|
||||
mo << " dependencies {" << newLine;
|
||||
mo << " classpath 'com.android.tools.build:gradle:" << androidPluginVersion.get() << "'" << newLine;
|
||||
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
mo << " classpath 'com.google.gms:google-services:3.1.0'" << newLine;
|
||||
|
||||
mo << " }" << newLine;
|
||||
mo << "}" << newLine;
|
||||
mo << "" << newLine;
|
||||
mo << "allprojects {" << newLine;
|
||||
mo << " repositories {" << newLine;
|
||||
mo << " jcenter()" << newLine;
|
||||
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
{
|
||||
mo << " maven {" << newLine;
|
||||
mo << " url \"https://maven.google.com\"" << newLine;
|
||||
mo << " }" << newLine;
|
||||
}
|
||||
|
||||
mo << " }" << newLine;
|
||||
mo << "}" << newLine;
|
||||
|
||||
|
|
@ -568,6 +595,7 @@ private:
|
|||
|
||||
mo << getAndroidRepositories() << newLine;
|
||||
mo << getAndroidDependencies() << newLine;
|
||||
mo << getApplyPlugins() << newLine;
|
||||
|
||||
mo << "}" << newLine << newLine;
|
||||
|
||||
|
|
@ -748,12 +776,28 @@ private:
|
|||
juce::StringArray dependencies;
|
||||
dependencies.addLines (androidDependencies.get());
|
||||
|
||||
mo << "dependencies {" << newLine;
|
||||
mo << "dependencies {" << newLine;
|
||||
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
{
|
||||
mo << " 'com.google.firebase:firebase-core:11.4.0'" << newLine;
|
||||
mo << " compile 'com.google.firebase:firebase-messaging:11.4.0'" << newLine;
|
||||
}
|
||||
|
||||
for (const auto& d : dependencies)
|
||||
mo << " " << d << newLine;
|
||||
|
||||
mo << "}" << newLine;
|
||||
mo << "}" << newLine;
|
||||
|
||||
return mo.toString();
|
||||
}
|
||||
|
||||
String getApplyPlugins() const
|
||||
{
|
||||
MemoryOutputStream mo;
|
||||
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
mo << "apply plugin: 'com.google.gms.google-services'" << newLine;
|
||||
|
||||
return mo.toString();
|
||||
}
|
||||
|
|
@ -838,9 +882,19 @@ private:
|
|||
props.add (new BooleanPropertyComponent (androidInAppBillingPermission.getPropertyAsValue(), "In-App Billing", "Specify In-App Billing permission in the manifest"),
|
||||
"If enabled, this will set the com.android.vending.BILLING flag in the manifest.");
|
||||
|
||||
props.add (new BooleanPropertyComponent (androidVibratePermission.getPropertyAsValue(), "Vibrate", "Specify permissions to vibrate"),
|
||||
"If enabled, this will set the android.permission.VIBRATE flag in the manifest.");
|
||||
|
||||
props.add (new TextPropertyComponent (androidOtherPermissions.getPropertyAsValue(), "Custom permissions", 2048, false),
|
||||
"A space-separated list of other permission flags that should be added to the manifest.");
|
||||
|
||||
props.add (new BooleanPropertyComponent (androidEnableRemoteNotifications.getPropertyAsValue(), "Remote Notifications", "Enabled"),
|
||||
"Enable to be able to send remote notifications to devices running your app (min API level 14). Provide Remote Notifications Config File, "
|
||||
"configure your app in Firebase Console and ensure you have the latest Google Repository in Android Studio's SDK Manager.");
|
||||
|
||||
props.add (new TextPropertyComponent (androidRemoteNotificationsConfigFile.getPropertyAsValue(), "Remote Notifications Config File", 2048, false),
|
||||
"Path to google-services.json file. This will be the file provided by Firebase when creating a new app in Firebase console.");
|
||||
|
||||
props.add (new TextPropertyComponent (androidManifestCustomXmlElements.getPropertyAsValue(), "Custom manifest XML content", 8192, true),
|
||||
"You can specify custom AndroidManifest.xml content overriding the default one generated by Projucer. "
|
||||
"Projucer will automatically create any missing and required XML elements and attributes "
|
||||
|
|
@ -902,10 +956,11 @@ private:
|
|||
auto inAppBillingPath = String ("com.android.vending.billing").replaceCharacter ('.', File::getSeparatorChar());
|
||||
auto javaSourceFolder = coreModule->getFolder().getChildFile ("native").getChildFile ("java");
|
||||
auto javaInAppBillingTarget = targetFolder.getChildFile ("app/src/main/java").getChildFile (inAppBillingPath);
|
||||
auto javaActivityTarget = targetFolder.getChildFile ("app/src/main/java")
|
||||
.getChildFile (package.replaceCharacter ('.', File::getSeparatorChar()));
|
||||
auto javaTarget = targetFolder.getChildFile ("app/src/main/java")
|
||||
.getChildFile (package.replaceCharacter ('.', File::getSeparatorChar()));
|
||||
|
||||
copyActivityJavaFiles (javaSourceFolder, javaActivityTarget, package);
|
||||
copyActivityJavaFiles (javaSourceFolder, javaTarget, package);
|
||||
copyServicesJavaFiles (javaSourceFolder, javaTarget, package);
|
||||
copyAdditionalJavaFiles (javaSourceFolder, javaInAppBillingTarget);
|
||||
}
|
||||
}
|
||||
|
|
@ -994,21 +1049,69 @@ private:
|
|||
inAppBillingJavaSrcFile.copyFileTo (inAppBillingJavaDestFile);
|
||||
}
|
||||
|
||||
void copyServicesJavaFiles (const File& javaSourceFolder, const File& targetFolder, const String& package) const
|
||||
{
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
{
|
||||
String instanceIdFileName = "JuceFirebaseInstanceIdService.java";
|
||||
String messagingFileName = "JuceFirebaseMessagingService.java";
|
||||
|
||||
File instanceIdFile (javaSourceFolder.getChildFile (instanceIdFileName));
|
||||
File messagingFile (javaSourceFolder.getChildFile (messagingFileName));
|
||||
|
||||
jassert (instanceIdFile.existsAsFile());
|
||||
jassert (messagingFile .existsAsFile());
|
||||
|
||||
Array<File> files;
|
||||
files.add (instanceIdFile);
|
||||
files.add (messagingFile);
|
||||
|
||||
for (const auto& file : files)
|
||||
{
|
||||
auto javaSourceLines = StringArray::fromLines (file.loadFileAsString());
|
||||
|
||||
{
|
||||
MemoryOutputStream newFile;
|
||||
|
||||
for (const auto& line : javaSourceLines)
|
||||
newFile << line.replace ("package com.juce;", "package " + package + ";") << newLine;
|
||||
|
||||
javaSourceLines = StringArray::fromLines (newFile.toString());
|
||||
}
|
||||
|
||||
auto targetFile = targetFolder.getChildFile (file.getFileName());
|
||||
|
||||
overwriteFileIfDifferentOrThrow (targetFile, javaSourceLines.joinIntoString (newLine));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void copyExtraResourceFiles() const
|
||||
{
|
||||
for (ConstConfigIterator config (*this); config.next();)
|
||||
{
|
||||
const auto& cfg = dynamic_cast<const AndroidBuildConfiguration&> (*config);
|
||||
const juce::String path = cfg.isDebug() ? "app/src/debug/res/values" : "app/src/release/res/values";
|
||||
const String xmlValuesPath = cfg.isDebug() ? "app/src/debug/res/values" : "app/src/release/res/values";
|
||||
const String rawPath = cfg.isDebug() ? "app/src/debug/res/raw" : "app/src/release/res/raw";
|
||||
|
||||
copyExtraResourceFiles (cfg.getAdditionalXmlResources(), path);
|
||||
copyExtraResourceFiles (cfg.getAdditionalXmlResources(), xmlValuesPath);
|
||||
copyExtraResourceFiles (cfg.getAdditionalRawResources(), rawPath);
|
||||
}
|
||||
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
{
|
||||
File file (getProject().getFile().getChildFile (androidRemoteNotificationsConfigFile.get()));
|
||||
// Settings file must be present for remote notifications to work and it must be called google-services.json.
|
||||
jassert (file.existsAsFile() && file.getFileName() == "google-services.json");
|
||||
|
||||
copyExtraResourceFiles (androidRemoteNotificationsConfigFile.get(), "app");
|
||||
}
|
||||
}
|
||||
|
||||
void copyExtraResourceFiles (const juce::String& xmlResources, const juce::String& dstRelativePath) const
|
||||
void copyExtraResourceFiles (const String& resources, const String& dstRelativePath) const
|
||||
{
|
||||
juce::StringArray resourcePaths;
|
||||
resourcePaths.addTokens (xmlResources, true);
|
||||
StringArray resourcePaths;
|
||||
resourcePaths.addTokens (resources, true);
|
||||
|
||||
const File parentFolder (getTargetFolder().getChildFile (dstRelativePath));
|
||||
|
||||
|
|
@ -1016,7 +1119,7 @@ private:
|
|||
|
||||
for (const auto& path : resourcePaths)
|
||||
{
|
||||
juce::File file (getProject().getFile().getChildFile(path));
|
||||
File file (getProject().getFile().getChildFile (path));
|
||||
|
||||
jassert (file.existsAsFile());
|
||||
|
||||
|
|
@ -1076,21 +1179,19 @@ private:
|
|||
{
|
||||
for (ConstConfigIterator config (*this); config.next();)
|
||||
{
|
||||
XmlElement strings ("resources");
|
||||
XmlElement* resourceName = strings.createNewChildElement ("string");
|
||||
|
||||
resourceName->setAttribute ("name", "app_name");
|
||||
resourceName->addTextElement (projectName);
|
||||
|
||||
const auto& cfg = dynamic_cast<const AndroidBuildConfiguration&> (*config);
|
||||
|
||||
for (XmlElement* e = XmlDocument::parse (cfg.getCustomStringsXml()); e != nullptr; e = e->getNextElement())
|
||||
strings.addChildElement (e);
|
||||
String customStringsXmlContent = "<resources>\n";
|
||||
customStringsXmlContent << "<string name=\"app_name\">" << projectName << "</string>\n";
|
||||
customStringsXmlContent << cfg.getCustomStringsXml();
|
||||
customStringsXmlContent << "\n</resources>";
|
||||
|
||||
ScopedPointer<XmlElement> strings = XmlDocument::parse (customStringsXmlContent);
|
||||
|
||||
const juce::String dir = cfg.isDebug() ? "debug" : "release";
|
||||
const juce::String subPath = "app/src/" + dir + "/res/values/string.xml";
|
||||
|
||||
writeXmlOrThrow (strings, folder.getChildFile (subPath), "utf-8", 100, true);
|
||||
writeXmlOrThrow (*strings, folder.getChildFile (subPath), "utf-8", 100, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1251,10 +1352,19 @@ private:
|
|||
defines.set ("JUCE_ANDROID_API_VERSION", androidMinimumSDK.get());
|
||||
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSNAME", getJNIActivityClassName().replaceCharacter ('/', '_'));
|
||||
defines.set ("JUCE_ANDROID_ACTIVITY_CLASSPATH", "\"" + getJNIActivityClassName() + "\"");
|
||||
defines.set ("JUCE_PUSH_NOTIFICATIONS", "1");
|
||||
|
||||
if (androidInAppBillingPermission.get())
|
||||
defines.set ("JUCE_IN_APP_PURCHASES", "1");
|
||||
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
{
|
||||
auto instanceIdClassName = getActivityClassPackage() + ".JuceFirebaseInstanceIdService";
|
||||
auto messagingClassName = getActivityClassPackage() + ".JuceFirebaseMessagingService";
|
||||
defines.set ("JUCE_FIREBASE_INSTANCE_ID_SERVICE_CLASSNAME", instanceIdClassName.replaceCharacter ('.', '_'));
|
||||
defines.set ("JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME", messagingClassName.replaceCharacter ('.', '_'));
|
||||
}
|
||||
|
||||
if (supportsGLv3())
|
||||
defines.set ("JUCE_ANDROID_GL_ES_VERSION_3_0", "1");
|
||||
|
||||
|
|
@ -1475,6 +1585,7 @@ private:
|
|||
}
|
||||
|
||||
setAttributeIfNotPresent (*act, "android:screenOrientation", androidScreenOrientation.get());
|
||||
setAttributeIfNotPresent (*act, "android:launchMode", "singleTask");
|
||||
|
||||
auto* intent = getOrCreateChildWithName (*act, "intent-filter");
|
||||
|
||||
|
|
@ -1483,6 +1594,23 @@ private:
|
|||
|
||||
auto* category = getOrCreateChildWithName (*intent, "category");
|
||||
setAttributeIfNotPresent (*category, "android:name", "android.intent.category.LAUNCHER");
|
||||
|
||||
if (androidEnableRemoteNotifications.get())
|
||||
{
|
||||
auto* service = app->createNewChildElement ("service");
|
||||
service->setAttribute ("android:name", ".JuceFirebaseMessagingService");
|
||||
auto* intentFilter = service->createNewChildElement ("intent-filter");
|
||||
intentFilter->createNewChildElement ("action")->setAttribute ("android:name", "com.google.firebase.MESSAGING_EVENT");
|
||||
|
||||
service = app->createNewChildElement ("service");
|
||||
service->setAttribute ("android:name", ".JuceFirebaseInstanceIdService");
|
||||
intentFilter = service->createNewChildElement ("intent-filter");
|
||||
intentFilter->createNewChildElement ("action")->setAttribute ("android:name", "com.google.firebase.INSTANCE_ID_EVENT");
|
||||
|
||||
auto* metaData = app->createNewChildElement ("meta-data");
|
||||
metaData->setAttribute ("android:name", "firebase_analytics_collection_deactivated");
|
||||
metaData->setAttribute ("android:value", "true");
|
||||
}
|
||||
}
|
||||
|
||||
return manifest;
|
||||
|
|
@ -1531,6 +1659,9 @@ private:
|
|||
if (androidInAppBillingPermission.get())
|
||||
s.add ("com.android.vending.BILLING");
|
||||
|
||||
if (androidVibratePermission.get())
|
||||
s.add ("android.permission.VIBRATE");
|
||||
|
||||
return getCleanedStringArray (s);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1134,6 +1134,9 @@ public:
|
|||
if (owner.isInAppPurchasesEnabled())
|
||||
defines.set ("JUCE_IN_APP_PURCHASES", "1");
|
||||
|
||||
if (owner.iOS && owner.isPushNotificationsEnabled())
|
||||
defines.set ("JUCE_PUSH_NOTIFICATIONS", "1");
|
||||
|
||||
defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type));
|
||||
|
||||
StringArray defsList;
|
||||
|
|
@ -2243,6 +2246,9 @@ private:
|
|||
if (isInAppPurchasesEnabled())
|
||||
xcodeFrameworks.addIfNotAlreadyThere ("StoreKit");
|
||||
|
||||
if (iOS && isPushNotificationsEnabled())
|
||||
xcodeFrameworks.addIfNotAlreadyThere ("UserNotifications");
|
||||
|
||||
xcodeFrameworks.addTokens (getExtraFrameworksString(), ",;", "\"'");
|
||||
xcodeFrameworks.trim();
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ namespace Ids
|
|||
DECLARE_ID (androidRepositories);
|
||||
DECLARE_ID (androidDependencies);
|
||||
DECLARE_ID (androidAdditionalXmlValueResources);
|
||||
DECLARE_ID (androidAdditionalRawValueResources);
|
||||
DECLARE_ID (androidActivityClass);
|
||||
DECLARE_ID (androidActivitySubClassName);
|
||||
DECLARE_ID (androidVersionCode);
|
||||
|
|
@ -184,6 +185,9 @@ namespace Ids
|
|||
DECLARE_ID (androidExternalReadNeeded);
|
||||
DECLARE_ID (androidExternalWriteNeeded);
|
||||
DECLARE_ID (androidInAppBilling);
|
||||
DECLARE_ID (androidVibratePermissionNeeded);
|
||||
DECLARE_ID (androidEnableRemoteNotifications);
|
||||
DECLARE_ID (androidRemoteNotificationsConfigFile);
|
||||
DECLARE_ID (androidMinimumSDK);
|
||||
DECLARE_ID (androidOtherPermissions);
|
||||
DECLARE_ID (androidKeyStore);
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@
|
|||
#include "native/juce_BasicNativeHeaders.h"
|
||||
#endif
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
#undef small
|
||||
#endif
|
||||
|
||||
#include "system/juce_StandardHeader.h"
|
||||
|
||||
namespace juce
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ public class JuceAppActivity extends Activity
|
|||
getApplicationInfo().dataDir);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private void hideActionBar()
|
||||
{
|
||||
// get "getActionBar" method
|
||||
|
|
@ -300,6 +301,7 @@ public class JuceAppActivity extends Activity
|
|||
private native void resumeApp();
|
||||
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
|
||||
private native void appActivityResult (int requestCode, int resultCode, Intent data);
|
||||
private native void appNewIntent (Intent intent);
|
||||
|
||||
//==============================================================================
|
||||
private ViewHolder viewHolder;
|
||||
|
|
@ -1367,6 +1369,15 @@ public class JuceAppActivity extends Activity
|
|||
appActivityResult (requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent (Intent intent)
|
||||
{
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
|
||||
appNewIntent (intent);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public final Typeface getTypeFaceFromAsset (String assetName)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package com.juce;
|
||||
|
||||
import com.google.firebase.iid.*;
|
||||
|
||||
public final class JuceFirebaseInstanceIdService extends FirebaseInstanceIdService
|
||||
{
|
||||
private native void firebaseInstanceIdTokenRefreshed (String token);
|
||||
|
||||
@Override
|
||||
public void onTokenRefresh()
|
||||
{
|
||||
String token = FirebaseInstanceId.getInstance().getToken();
|
||||
|
||||
firebaseInstanceIdTokenRefreshed (token);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.juce;
|
||||
|
||||
import com.google.firebase.messaging.*;
|
||||
|
||||
public final class JuceFirebaseMessagingService extends FirebaseMessagingService
|
||||
{
|
||||
private native void firebaseRemoteMessageReceived (RemoteMessage message);
|
||||
private native void firebaseRemoteMessagesDeleted();
|
||||
private native void firebaseRemoteMessageSent (String messageId);
|
||||
private native void firebaseRemoteMessageSendError (String messageId, String error);
|
||||
|
||||
@Override
|
||||
public void onMessageReceived (RemoteMessage message)
|
||||
{
|
||||
firebaseRemoteMessageReceived (message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeletedMessages()
|
||||
{
|
||||
firebaseRemoteMessagesDeleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageSent (String messageId)
|
||||
{
|
||||
firebaseRemoteMessageSent (messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendError (String messageId, Exception e)
|
||||
{
|
||||
firebaseRemoteMessageSendError (messageId, e.toString());
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ public:
|
|||
|
||||
LocalRef& operator= (const LocalRef& other)
|
||||
{
|
||||
jobject newObj = retain (other.obj);
|
||||
JavaType newObj = retain (other.obj);
|
||||
clear();
|
||||
obj = newObj;
|
||||
return *this;
|
||||
|
|
@ -168,6 +168,9 @@ namespace
|
|||
{
|
||||
inline String juceString (JNIEnv* env, jstring s)
|
||||
{
|
||||
if (s == 0)
|
||||
return {};
|
||||
|
||||
const char* const utf8 = env->GetStringUTFChars (s, nullptr);
|
||||
CharPointer_UTF8 utf8CP (utf8);
|
||||
const String result (utf8CP);
|
||||
|
|
@ -313,11 +316,12 @@ extern AndroidSystem android;
|
|||
METHOD (isPermissionGranted, "isPermissionGranted", "(I)Z" ) \
|
||||
METHOD (isPermissionDeclaredInManifest, "isPermissionDeclaredInManifest", "(I)Z" ) \
|
||||
METHOD (getSystemService, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;") \
|
||||
METHOD (getPackageName, "getPackageName", "()Ljava/lang/String;") \
|
||||
METHOD (getResources, "getResources", "()Landroid/content/res/Resources;") \
|
||||
STATICMETHOD (createInvocationHandler, "createInvocationHandler", "(J)Ljava/lang/reflect/InvocationHandler;") \
|
||||
METHOD (bindService, "bindService", "(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z") \
|
||||
METHOD (unbindService, "unbindService", "(Landroid/content/ServiceConnection;)V") \
|
||||
METHOD (startIntentSenderForResult, "startIntentSenderForResult", "(Landroid/content/IntentSender;ILandroid/content/Intent;III)V") \
|
||||
METHOD (getPackageName, "getPackageName", "()Ljava/lang/String;") \
|
||||
METHOD (moveTaskToBack, "moveTaskToBack", "(Z)Z") \
|
||||
METHOD (startActivity, "startActivity", "(Landroid/content/Intent;)V") \
|
||||
|
||||
|
|
@ -399,15 +403,20 @@ DECLARE_JNI_CLASS (JavaObject, "java/lang/Object");
|
|||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (constructor, "<init>", "()V") \
|
||||
METHOD (constructWithString, "<init>", "(Ljava/lang/String;)V") \
|
||||
METHOD (setPackage, "setPackage", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
METHOD (getIntExtra, "getIntExtra", "(Ljava/lang/String;I)I") \
|
||||
METHOD (getStringExtra, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;") \
|
||||
METHOD (addCategory, "addCategory", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
METHOD (setType, "setType", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
METHOD (getData, "getData", "()Landroid/net/Uri;") \
|
||||
METHOD (setAction, "setAction", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
METHOD (addCategory, "addCategory", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
METHOD (constructor, "<init>", "()V") \
|
||||
METHOD (constructorWithContextAndClass, "<init>", "(Landroid/content/Context;Ljava/lang/Class;)V") \
|
||||
METHOD (constructWithString, "<init>", "(Ljava/lang/String;)V") \
|
||||
METHOD (getAction, "getAction", "()Ljava/lang/String;") \
|
||||
METHOD (getCategories, "getCategories", "()Ljava/util/Set;") \
|
||||
METHOD (getData, "getData", "()Landroid/net/Uri;") \
|
||||
METHOD (getExtras, "getExtras", "()Landroid/os/Bundle;") \
|
||||
METHOD (getIntExtra, "getIntExtra", "(Ljava/lang/String;I)I") \
|
||||
METHOD (getStringExtra, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;") \
|
||||
METHOD (putExtras, "putExtras", "(Landroid/os/Bundle;)Landroid/content/Intent;") \
|
||||
METHOD (setAction, "setAction", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
METHOD (setPackage, "setPackage", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
METHOD (setType, "setType", "(Ljava/lang/String;)Landroid/content/Intent;") \
|
||||
|
||||
DECLARE_JNI_CLASS (Intent, "android/content/Intent");
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@
|
|||
#import <Carbon/Carbon.h> // still needed for SetSystemUIMode()
|
||||
#endif
|
||||
|
||||
#elif JUCE_IOS
|
||||
#if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_WINDOWS
|
||||
#include <windowsx.h>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,16 @@ namespace juce
|
|||
{
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_PUSH_NOTIFICATIONS && JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
// Returns true if the intent was handled.
|
||||
extern bool juce_handleNotificationIntent (void*);
|
||||
extern void juce_firebaseDeviceNotificationsTokenRefreshed (void*);
|
||||
extern void juce_firebaseRemoteNotificationReceived (void*);
|
||||
extern void juce_firebaseRemoteMessagesDeleted();
|
||||
extern void juce_firebaseRemoteMessageSent(void*);
|
||||
extern void juce_firebaseRemoteMessageSendError (void*, void*);
|
||||
#endif
|
||||
|
||||
#if JUCE_IN_APP_PURCHASES && JUCE_MODULE_AVAILABLE_juce_product_unlocking
|
||||
extern void juce_inAppPurchaseCompleted (void*);
|
||||
#endif
|
||||
|
|
@ -98,6 +108,75 @@ JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, appActivityResult, void, (JN
|
|||
#endif
|
||||
}
|
||||
|
||||
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, appNewIntent, void, (JNIEnv* env, jobject, jobject intentData))
|
||||
{
|
||||
setEnv (env);
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS && JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
if (juce_handleNotificationIntent ((void *)intentData))
|
||||
return;
|
||||
|
||||
// Add other functions processing intents here as needed.
|
||||
#else
|
||||
ignoreUnused (intentData);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME)
|
||||
JUCE_JNI_CALLBACK (JUCE_FIREBASE_INSTANCE_ID_SERVICE_CLASSNAME, firebaseInstanceIdTokenRefreshed, void, (JNIEnv* env, jobject /*activity*/, jstring token))
|
||||
{
|
||||
setEnv (env);
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
juce_firebaseDeviceNotificationsTokenRefreshed (token);
|
||||
#else
|
||||
ignoreUnused (token);
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_JNI_CALLBACK (JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME, firebaseRemoteMessageReceived, void, (JNIEnv* env, jobject /*activity*/, jobject remoteMessage))
|
||||
{
|
||||
setEnv (env);
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
juce_firebaseRemoteNotificationReceived (remoteMessage);
|
||||
#else
|
||||
ignoreUnused (remoteMessage);
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_JNI_CALLBACK (JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME, firebaseRemoteMessagesDeleted, void, (JNIEnv* env, jobject /*activity*/))
|
||||
{
|
||||
setEnv (env);
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
juce_firebaseRemoteMessagesDeleted();
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_JNI_CALLBACK (JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME, firebaseRemoteMessageSent, void, (JNIEnv* env, jobject /*activity*/, jstring messageId))
|
||||
{
|
||||
setEnv (env);
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
juce_firebaseRemoteMessageSent (messageId);
|
||||
#else
|
||||
ignoreUnused (messageId);
|
||||
#endif
|
||||
}
|
||||
|
||||
JUCE_JNI_CALLBACK (JUCE_FIREBASE_MESSAGING_SERVICE_CLASSNAME, firebaseRemoteMessageSendError, void, (JNIEnv* env, jobject /*activity*/, jstring messageId, jstring error))
|
||||
{
|
||||
setEnv (env);
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
juce_firebaseRemoteMessageSendError (messageId, error);
|
||||
#else
|
||||
ignoreUnused (messageId, error);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||
METHOD (drawBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \
|
||||
|
|
|
|||
|
|
@ -38,7 +38,11 @@ namespace juce
|
|||
Array<AppInactivityCallback*> appBecomingInactiveCallbacks;
|
||||
}
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
@interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate, UNUserNotificationCenterDelegate>
|
||||
#else
|
||||
@interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate>
|
||||
#endif
|
||||
{
|
||||
UIBackgroundTaskIdentifier appSuspendTask;
|
||||
}
|
||||
|
|
@ -51,17 +55,45 @@ namespace juce
|
|||
- (void) applicationWillEnterForeground: (UIApplication*) application;
|
||||
- (void) applicationDidBecomeActive: (UIApplication*) application;
|
||||
- (void) applicationWillResignActive: (UIApplication*) application;
|
||||
- (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*)identifier
|
||||
completionHandler: (void (^)(void))completionHandler;
|
||||
- (void) application: (UIApplication*) application handleEventsForBackgroundURLSession: (NSString*) identifier
|
||||
completionHandler: (void (^)(void)) completionHandler;
|
||||
- (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings;
|
||||
- (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken;
|
||||
- (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error;
|
||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo;
|
||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
|
||||
fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler;
|
||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
|
||||
forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
|
||||
completionHandler: (void(^)()) completionHandler;
|
||||
- (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification;
|
||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
|
||||
forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler;
|
||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
|
||||
forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
|
||||
completionHandler: (void(^)()) completionHandler;
|
||||
#if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
|
||||
withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler;
|
||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
|
||||
withCompletionHandler: (void(^)())completionHandler;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation JuceAppStartupDelegate
|
||||
|
||||
NSObject* _pushNotificationsDelegate;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
appSuspendTask = UIBackgroundTaskInvalid;
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
|
||||
#endif
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +150,8 @@ namespace juce
|
|||
|
||||
- (void) applicationDidBecomeActive: (UIApplication*) application
|
||||
{
|
||||
ignoreUnused (application);
|
||||
application.applicationIconBadgeNumber = 0;
|
||||
|
||||
isIOSAppActive = true;
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +172,230 @@ namespace juce
|
|||
completionHandler();
|
||||
}
|
||||
|
||||
- (void) setPushNotificationsDelegateToUse: (NSObject*) delegate
|
||||
{
|
||||
_pushNotificationsDelegate = delegate;
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didRegisterUserNotificationSettings:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: ¬ificationSettings atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didRegisterForRemoteNotificationsWithDeviceToken:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &deviceToken atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didFailToRegisterForRemoteNotificationsWithError:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &error atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didReceiveRemoteNotification:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &userInfo atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
|
||||
fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didReceiveRemoteNotification:fetchCompletionHandler:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &userInfo atIndex:3];
|
||||
[invocation setArgument: &completionHandler atIndex:4];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
|
||||
forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
|
||||
completionHandler: (void(^)()) completionHandler
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &identifier atIndex:3];
|
||||
[invocation setArgument: &userInfo atIndex:4];
|
||||
[invocation setArgument: &responseInfo atIndex:5];
|
||||
[invocation setArgument: &completionHandler atIndex:6];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didReceiveLocalNotification:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: ¬ification atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
|
||||
forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:handleActionWithIdentifier:forLocalNotification:completionHandler:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &identifier atIndex:3];
|
||||
[invocation setArgument: ¬ification atIndex:4];
|
||||
[invocation setArgument: &completionHandler atIndex:5];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
|
||||
forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
|
||||
completionHandler: (void(^)()) completionHandler
|
||||
{
|
||||
ignoreUnused (application);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &identifier atIndex:3];
|
||||
[invocation setArgument: ¬ification atIndex:4];
|
||||
[invocation setArgument: &responseInfo atIndex:5];
|
||||
[invocation setArgument: &completionHandler atIndex:6];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
|
||||
withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler
|
||||
{
|
||||
ignoreUnused (center);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"userNotificationCenter:willPresentNotification:withCompletionHandler:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: ¢er atIndex:2];
|
||||
[invocation setArgument: ¬ification atIndex:3];
|
||||
[invocation setArgument: &completionHandler atIndex:4];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
|
||||
withCompletionHandler: (void(^)()) completionHandler
|
||||
{
|
||||
ignoreUnused (center);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:");
|
||||
|
||||
if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: _pushNotificationsDelegate];
|
||||
[invocation setArgument: ¢er atIndex:2];
|
||||
[invocation setArgument: &response atIndex:3];
|
||||
[invocation setArgument: &completionHandler atIndex:4];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
namespace juce
|
||||
|
|
|
|||
|
|
@ -35,10 +35,15 @@
|
|||
|
||||
#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
|
||||
#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1
|
||||
#define JUCE_CORE_INCLUDE_JNI_HELPERS 1
|
||||
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
|
||||
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
|
||||
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
|
||||
|
||||
#ifndef JUCE_PUSH_NOTIFICATIONS
|
||||
#define JUCE_PUSH_NOTIFICATIONS 0
|
||||
#endif
|
||||
|
||||
#include "juce_gui_extra.h"
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -50,7 +55,21 @@
|
|||
#import <IOKit/hid/IOHIDKeys.h>
|
||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_IOS
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#endif
|
||||
|
||||
#include "native/juce_ios_PushNotifications.cpp"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_ANDROID
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
#include "native/juce_android_PushNotifications.cpp"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_WINDOWS
|
||||
|
|
@ -93,6 +112,7 @@
|
|||
#include "misc/juce_ColourSelector.cpp"
|
||||
#include "misc/juce_KeyMappingEditorComponent.cpp"
|
||||
#include "misc/juce_PreferencesPanel.cpp"
|
||||
#include "misc/juce_PushNotifications.cpp"
|
||||
#include "misc/juce_RecentlyOpenedFilesList.cpp"
|
||||
#include "misc/juce_SplashScreen.cpp"
|
||||
#include "misc/juce_SystemTrayIconComponent.cpp"
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@
|
|||
#include "misc/juce_ColourSelector.h"
|
||||
#include "misc/juce_KeyMappingEditorComponent.h"
|
||||
#include "misc/juce_PreferencesPanel.h"
|
||||
#include "misc/juce_PushNotifications.h"
|
||||
#include "misc/juce_RecentlyOpenedFilesList.h"
|
||||
#include "misc/juce_SplashScreen.h"
|
||||
#include "misc/juce_SystemTrayIconComponent.h"
|
||||
|
|
|
|||
190
modules/juce_gui_extra/misc/juce_PushNotifications.cpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_ANDROID && ! JUCE_IOS
|
||||
bool PushNotifications::Notification::isValid() const noexcept { return true; }
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
juce_ImplementSingleton (PushNotifications)
|
||||
|
||||
PushNotifications::PushNotifications()
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
: pimpl (new Pimpl (*this))
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
PushNotifications::~PushNotifications() { clearSingletonInstance(); }
|
||||
|
||||
void PushNotifications::addListener (Listener* l) { listeners.add (l); }
|
||||
void PushNotifications::removeListener (Listener* l) { listeners.remove (l); }
|
||||
|
||||
void PushNotifications::requestPermissionsWithSettings (const PushNotifications::Settings& settings)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS && JUCE_IOS
|
||||
pimpl->requestPermissionsWithSettings (settings);
|
||||
#else
|
||||
ignoreUnused (settings);
|
||||
listeners.call (&PushNotifications::Listener::notificationSettingsReceived, {});
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::requestSettingsUsed()
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS && JUCE_IOS
|
||||
pimpl->requestSettingsUsed();
|
||||
#else
|
||||
listeners.call (&PushNotifications::Listener::notificationSettingsReceived, {});
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PushNotifications::areNotificationsEnabled() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
return pimpl->areNotificationsEnabled();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::getDeliveredNotifications() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->getDeliveredNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::removeAllDeliveredNotifications()
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->removeAllDeliveredNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
String PushNotifications::getDeviceToken() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
return pimpl->getDeviceToken();
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::setupChannels (const Array<ChannelGroup>& groups, const Array<Channel>& channels)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->setupChannels (groups, channels);
|
||||
#else
|
||||
ignoreUnused (groups, channels);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::getPendingLocalNotifications() const
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->getPendingLocalNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::removeAllPendingLocalNotifications()
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->removeAllPendingLocalNotifications();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::subscribeToTopic (const String& topic)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->subscribeToTopic (topic);
|
||||
#else
|
||||
ignoreUnused (topic);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::unsubscribeFromTopic (const String& topic)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->unsubscribeFromTopic (topic);
|
||||
#else
|
||||
ignoreUnused (topic);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void PushNotifications::sendLocalNotification (const Notification& n)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->sendLocalNotification (n);
|
||||
#else
|
||||
ignoreUnused (n);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::removeDeliveredNotification (const String& identifier)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->removeDeliveredNotification (identifier);
|
||||
#else
|
||||
ignoreUnused (identifier);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::removePendingLocalNotification (const String& identifier)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->removePendingLocalNotification (identifier);
|
||||
#else
|
||||
ignoreUnused (identifier);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PushNotifications::sendUpstreamMessage (const String& serverSenderId,
|
||||
const String& collapseKey,
|
||||
const String& messageId,
|
||||
const String& messageType,
|
||||
int timeToLive,
|
||||
const StringPairArray& additionalData)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
pimpl->sendUpstreamMessage (serverSenderId,
|
||||
collapseKey,
|
||||
messageId,
|
||||
messageType,
|
||||
timeToLive,
|
||||
additionalData);
|
||||
#else
|
||||
ignoreUnused (serverSenderId, collapseKey, messageId, messageType);
|
||||
ignoreUnused (timeToLive, additionalData);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
687
modules/juce_gui_extra/misc/juce_PushNotifications.h
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/** Singleton class responsible for push notifications functionality. Both remote and
|
||||
local notifications are supported. To get information about notifications,
|
||||
register a listener on your application startup. It is best to register the
|
||||
listener as soon as possible, because your application can be launched from
|
||||
a push notification too.
|
||||
|
||||
To send a local notification create an instance of @class Notification, fill the
|
||||
necessary fields and call PushNotifications::sendLocalNotification(). When receiving
|
||||
local or remote notifications, inspect the Notification's fields for notification details.
|
||||
Bear in mind that some fields will not be available when receiving a remote notification.
|
||||
*/
|
||||
class JUCE_API PushNotifications
|
||||
{
|
||||
public:
|
||||
juce_DeclareSingleton (PushNotifications, false)
|
||||
|
||||
//==========================================================================
|
||||
/** Represents a notification that can be sent or received. */
|
||||
struct Notification
|
||||
{
|
||||
Notification() = default;
|
||||
|
||||
/** Checks whether a given notification is correctly configured for a given OS. */
|
||||
bool isValid() const noexcept;
|
||||
|
||||
/** Represents an action on a notification that can be presented as a button or a text input.
|
||||
On Android, each notification has its action specified explicitly, on iOS you configure an
|
||||
allowed set of actions on startup and pack them into categories (see @class Settings).
|
||||
*/
|
||||
struct Action
|
||||
{
|
||||
/** Controls the appearance of this action. */
|
||||
enum Style
|
||||
{
|
||||
button, /**< Show this action as a button. */
|
||||
text /**< Show this action as a text input field (on Android API 20 or higher is required). */
|
||||
};
|
||||
|
||||
/** @name Common fields */
|
||||
/**@{*/
|
||||
Style style = button;
|
||||
String title; /**< Required. the name of the action displayed to the user. */
|
||||
String textInputPlaceholder; /**< Optional: placeholder text for text input notification.
|
||||
Note that it will be ignored if button style is used. */
|
||||
var parameters; /**< Optional: additional parameters that can be passed. */
|
||||
/**@}*/
|
||||
|
||||
/** @name iOS only fields */
|
||||
/**@{*/
|
||||
String identifier; /**< Required: unique identifier. This should be one of the
|
||||
identifiers set with requestPermissionsWithSettings(). */
|
||||
bool triggerInBackground = false; /**< Whether the app can process the action in background. */
|
||||
bool destructive = false; /**< Whether to display the action as destructive. */
|
||||
String textInputButtonText; /**< Optional: Text displayed on text input notification
|
||||
button (from iOS 10 only).
|
||||
Note that it will be ignored if style is set to Style::button. */
|
||||
/**@}*/
|
||||
|
||||
/** @name Android only fields */
|
||||
/**@{*/
|
||||
String icon; /**< Optional: name of an icon file (without an extension) to be used for
|
||||
this action. This must be the name of one of the image
|
||||
files included into resources when exporting an Android project
|
||||
(see "Extra Android Raw Resources" setting in Projucer).
|
||||
Note that not all Android versions support an icon for an action, though
|
||||
it is recommended to provide it nevertheless. */
|
||||
|
||||
StringArray allowedResponses; /**< Optional: a list of possible answers if the answer set is limited.
|
||||
When left empty, then the user will be able to input any text. */
|
||||
/**@}*/
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
/** @name Common fields */
|
||||
/**@{*/
|
||||
|
||||
String identifier; /**< Required: unique id that can be used to later dismiss the notification
|
||||
(on iOS available from version 10). */
|
||||
|
||||
String title; /**< Required: the title of the notification, usually displayed in the first row. */
|
||||
String body; /**< Required: the content of the notification, usually displayed in the second row. */
|
||||
String subtitle; /**< Optional: additional text, that may be displayed e.g. in the third row or in the header
|
||||
area. Note that on Android, depending on OS version, this may fight for
|
||||
space with other components of the notification, so use this field
|
||||
judiciously. On iOS available from version 10. On Android available from API 16. */
|
||||
|
||||
String groupId; /**< Optional: allows the OS to visually group, collapse, and expand a set of notifications,
|
||||
note that OS may automatically group notifications if no groupId is specified.
|
||||
Available on Android API 20 or above and iOS 10 or above. */
|
||||
|
||||
int badgeNumber = 0; /**< Optional: on platforms that support it, can set a number this notification represents. */
|
||||
URL soundToPlay; /**< Optional: empty when the notification should be silent. When the name is set to
|
||||
"default_os_sound", then a default sound will be used.
|
||||
|
||||
For a custom sound on iOS, set the URL to a relative path within your bundle, including
|
||||
file extension. For instance, if your bundle contains "sounds" folder with "my_sound.caf"
|
||||
file, then the URL should be "sounds/my_sound.caf".
|
||||
|
||||
For a custom sound on Android, set URL to the name of a raw resource file
|
||||
(without an extention) that was included when exporting an Android project in
|
||||
Projucer (see "Extra Android Raw Resources" setting). */
|
||||
|
||||
var properties; /**< Optional: collection of additional properties that may be passed as a dictionary. */
|
||||
|
||||
/**@}*/
|
||||
|
||||
//==========================================================================
|
||||
/** @name iOS only fields */
|
||||
/**@{*/
|
||||
|
||||
String category; /**< Required: determines set of actions that will appear (as per setup done
|
||||
in initializeWithSettings()). */
|
||||
double triggerIntervalSec = 0.; /**< Optional: specifies number of seconds before the notification should trigger. */
|
||||
bool repeat = false; /**< Optional: allows the notification to continuously retrigger after
|
||||
triggerIntervalSec seconds. Available from iOS 10. */
|
||||
|
||||
/**@}*/
|
||||
|
||||
//==========================================================================
|
||||
/** @name Android only fields */
|
||||
/**@{*/
|
||||
|
||||
String icon; /**< Required: name of an icon file (without an extension) to be used for
|
||||
this notification. This must be the name of one of the image
|
||||
files included into resources when exporting an Android project
|
||||
(see "Extra Android Raw Resources" setting in Projucer). */
|
||||
|
||||
String channelId; /**< Required for Android API level 26 or above: specifies notification channel id. Refer to
|
||||
setupChannels(). Ignored on earlier Android versions. */
|
||||
|
||||
Image largeIcon; /**< Optional: an additional large icon displayed in the notification content view. */
|
||||
|
||||
String tickerText; /**< Optional: ticker text used for accessibility services. */
|
||||
|
||||
Array<Action> actions; /**< Optional: actions associated with the notification. Note that the OS may allow only a limited
|
||||
number of actions to be presented, so always present most important actions first.
|
||||
Available from Android API 16 or above. */
|
||||
|
||||
/**< Used to represent a progress of some operation. */
|
||||
struct Progress
|
||||
{
|
||||
int max = 0; /**< Max possible value of a progress. A typical usecase is to set max to 100 and increment
|
||||
current's value as percentage complete. */
|
||||
int current = 0; /**< Current progress value, should be from 0 to max. */
|
||||
bool indeterminate = false; /**< If true, then the progress represents a continuing activity indicator with ongoing
|
||||
animation and no numeric value. */
|
||||
};
|
||||
|
||||
Progress progress; /**< Optional: set to default (0, 0, false), to disable progress display. */
|
||||
|
||||
/** Metadata that can be used by the OS to better handle the notification, depending on its priority. */
|
||||
enum Type
|
||||
{
|
||||
unspecified, /**< Category not set. */
|
||||
alarm, /**< Alarm or timer. */
|
||||
call, /**< Incoming voice/video call or similar. */
|
||||
email, /**< Async message like email. */
|
||||
error, /**< Error in background operation or authentication status. */
|
||||
event, /**< Calendar event. */
|
||||
message, /**< Incoming message (sms, instant message etc.). */
|
||||
taskProgress, /**< Progress for a long-running background operation. */
|
||||
promo, /**< Promotion or advertisement. */
|
||||
recommendation, /**< Specific, single thing related recommendation. */
|
||||
reminder, /**< User-scheduled reminder. */
|
||||
service, /**< Running background service. */
|
||||
social, /**< Social network or sharing update. */
|
||||
status, /**< Ongoing information about device or contextual status. */
|
||||
system, /**< System or device status update. */
|
||||
transport /**< Media transport control for playback. */
|
||||
};
|
||||
|
||||
/** Metadata used as a hint to the OS about the priority of the notification. */
|
||||
enum Priority
|
||||
{
|
||||
veryLow = -2,
|
||||
low = -1,
|
||||
medium = 0,
|
||||
high = 1,
|
||||
veryHigh = 2
|
||||
};
|
||||
|
||||
String person; /**< Optional: additional metadata used as a hint to OS that a notification is
|
||||
related to a specific person. Can be useful for instance messaging apps.
|
||||
Available from Android API 21 or above. */
|
||||
|
||||
Type type = unspecified; /**< Optional. Available from Android API 21 or above. */
|
||||
Priority priority = medium; /**< Optional. Available from Android API 16 or above. */
|
||||
|
||||
/** Describes how to show the notification when the screen is locked. Available from Android API 21 or above. */
|
||||
enum LockScreenAppearance
|
||||
{
|
||||
dontShow = -1, /**< The notification is not allowed on the lock screen */
|
||||
showPartially = 0, /**< Only some information is allowed on the lock screen */
|
||||
showCompletely = 1 /**< The entire notification is allowed on the lock screen */
|
||||
};
|
||||
|
||||
LockScreenAppearance lockScreenAppearance = showPartially; /**< Optional. */
|
||||
|
||||
ScopedPointer<Notification> publicVersion; /**< Optional: if you set lockScreenAppearance to showPartially,
|
||||
then you can provide "public version" of your notification
|
||||
that will be displayed on the lock screen. This way you can
|
||||
control what information is visible when the screen is locked. */
|
||||
|
||||
String groupSortKey; /**< Optional: Used to order notifications within the same group. Available from Android API 20 or above. */
|
||||
bool groupSummary = false; /**< Optional: if true, then this notification will be a group summary of the group set with groupId.
|
||||
Available from Android API 20 or above. */
|
||||
|
||||
Colour accentColour; /**< Optional: sets accent colour. The default colour will be used if accentColour is not set.
|
||||
Available from Android API 21 or above. */
|
||||
Colour ledColour; /**< Optional: Sets the led colour. The hardware will do its best to approximate the colour.
|
||||
The default colour will be used if ledColour is not set. */
|
||||
|
||||
/**< Allows to control the time the device's led is on and off. */
|
||||
struct LedBlinkPattern
|
||||
{
|
||||
int msToBeOn = 0; /**< The led will be on for the given number of milliseconds, after which it will turn off. */
|
||||
int msToBeOff = 0; /**< The led will be off for the given number of milliseconds, after which it will turn on. */
|
||||
};
|
||||
|
||||
LedBlinkPattern ledBlinkPattern; /**< Optional. */
|
||||
|
||||
Array<int> vibrationPattern; /**< Optional: sets the vibration pattern in milliseconds. The first value indicates how long
|
||||
to wait until vibration starts. The second value indicates how long to vibrate. The third
|
||||
value will say how long to not vibrate and so on. For instance, if the pattern is:
|
||||
1000, 2000, 3000, 4000 - then one second after receiving a notification the device will
|
||||
vibrate for two seconds, followed by 3 seconds of no vibration and finally, 4 seconds of
|
||||
vibration. */
|
||||
|
||||
bool shouldAutoCancel = true; /**< Optional: If true, the notification will be automatically cancelled when a user clicks it in the panel. */
|
||||
|
||||
bool localOnly = true; /**< Optional: whether or not the notification should bridge to other devices.
|
||||
Available from Android API 20 or above. */
|
||||
|
||||
bool ongoing = false; /**< Optional: If true, then it cannot be dismissed by the user and it must be dimissed manually.
|
||||
Typically used for ongoing background tasks that the user is actively engaged with. To
|
||||
dismiss such notification, you need to call removeDeliveredNotification() or
|
||||
removeAllDeliveredNotifications(). */
|
||||
|
||||
bool alertOnlyOnce = false; /**< Optional: Set this flag if you would only like the sound, vibrate and ticker to be played if the notification
|
||||
is not already showing. */
|
||||
|
||||
/**< Controls timestamp visibility and format. */
|
||||
enum TimestampVisibility
|
||||
{
|
||||
off, /**< Do not show timestamp. */
|
||||
normal, /**< Show normal timestamp. */
|
||||
chronometer, /**< Show chronometer as a stopwatch. Available from Android API 16 or above. */
|
||||
countDownChronometer /**< Set the chronometer to count down instead of counting up. Available from Android API 24 or above.*/
|
||||
};
|
||||
|
||||
TimestampVisibility timestampVisibility = normal; /**< Optional. */
|
||||
|
||||
/**< Controls badge icon type to use if a notification is shown as a badge. Available from Android API 26 or above. */
|
||||
enum BadgeIconType
|
||||
{
|
||||
none,
|
||||
small,
|
||||
large
|
||||
};
|
||||
|
||||
BadgeIconType badgeIconType = large;
|
||||
|
||||
/** Controls sound and vibration behaviour for group notifications. Available from Android API 26 or above. */
|
||||
enum GroupAlertBehaviour
|
||||
{
|
||||
alertAll, /**< both child notifications and group notifications should produce sound and vibration. */
|
||||
AlertSummary, /**< all child notifications in the group should have no sound nor vibration, even
|
||||
if corresponding notification channel has sounds and vibrations enabled. */
|
||||
AlertChildren /**< summary notifications in the group should have no sound nor vibration, even if
|
||||
corresponding notification channel has sounds and vibrations enabled. */
|
||||
};
|
||||
|
||||
GroupAlertBehaviour groupAlertBehaviour = alertAll;
|
||||
|
||||
int timeoutAfterMs = 0; /**< specifies a duration in milliseconds, after which the notification should be
|
||||
cancelled, if it is not already canceled. Available from Android API 26 or above. */
|
||||
/**@}*/
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
/** Describes settings we want to use for current device. Note that at the
|
||||
moment this is only used on iOS.
|
||||
|
||||
To setup push notifications for current device, provide permissions required,
|
||||
as well as register categories of notifications you want to support. Each
|
||||
category needs to have a unique identifier and it can optionally have multiple
|
||||
actions. Each action also needs to have a unique identifier. The example setup
|
||||
may look as follows:
|
||||
|
||||
@code
|
||||
|
||||
using Action = PushNotifications::Settings::Action;
|
||||
using Category = PushNotifications::Settings::Category;
|
||||
|
||||
Action okAction;
|
||||
okAction.identifier = "okAction";
|
||||
okAction.title = "OK!";
|
||||
okAction.style = Action::button;
|
||||
okAction.triggerInBackground = true;
|
||||
|
||||
Action cancelAction;
|
||||
cancelAction.identifier = "cancelAction";
|
||||
cancelAction.title = "Cancel";
|
||||
cancelAction.style = Action::button;
|
||||
cancelAction.triggerInBackground = true;
|
||||
cancelAction.destructive = true;
|
||||
|
||||
Action textAction;
|
||||
textAction.identifier = "textAction";
|
||||
textAction.title = "Enter text";
|
||||
textAction.style = Action::text;
|
||||
textAction.triggerInBackground = true;
|
||||
textAction.destructive = false;
|
||||
textAction.textInputButtonText = "Ok";
|
||||
textAction.textInputPlaceholder = "Enter text...";
|
||||
|
||||
Category okCategory;
|
||||
okCategory.identifier = "okCategory";
|
||||
okCategory.actions = { okAction };
|
||||
|
||||
Category okCancelCategory;
|
||||
okCancelCategory.identifier = "okCancelCategory";
|
||||
okCancelCategory.actions = { okAction, cancelAction };
|
||||
|
||||
Category textCategory;
|
||||
textCategory.identifier = "textCategory";
|
||||
textCategory.actions = { textAction };
|
||||
textCategory.sendDismissAction = true;
|
||||
|
||||
PushNotifications::Settings settings;
|
||||
settings.allowAlert = true;
|
||||
settings.allowBadge = true;
|
||||
settings.allowSound = true;
|
||||
settings.categories = { okCategory, okCancelCategory, textCategory };
|
||||
|
||||
@endcode
|
||||
*/
|
||||
struct Settings
|
||||
{
|
||||
using Action = Notification::Action;
|
||||
|
||||
/** Describes a category of a notification. Each category has a unique idenfifier
|
||||
and a list of associated actions.
|
||||
Note that the OS may allow only a limited number of actions to be presented, so
|
||||
always present most important actions first.
|
||||
*/
|
||||
struct Category
|
||||
{
|
||||
juce::String identifier; /**< unique indentifier */
|
||||
juce::Array<Action> actions; /**< optional list of actions within this category */
|
||||
bool sendDismissAction = false; /**< whether dismiss action will be sent to the app (from iOS 10 only) */
|
||||
};
|
||||
|
||||
bool allowSound = false; /**< whether the app should play a sound upon notification */
|
||||
bool allowAlert = false; /**< whether the app should present an alert upon notification */
|
||||
bool allowBadge = false; /**< whether the app may badge its icon upon notification */
|
||||
Array<Category> categories; /**< list of categories the app wants to support */
|
||||
};
|
||||
|
||||
/** Initializes push notifications on current device with the settings provided.
|
||||
Call this on your application startup and on iOS the first time the application starts,
|
||||
a user will be presented with a permission request dialog to give push notifications permission.
|
||||
Once a user responds, Listener::notificationSettingsReceived() will be called so that
|
||||
you can check what permissions where actually granted. The listener callback will be called
|
||||
on each subsequent startup too (provided you called requestPermissionsWithSettings() on previous
|
||||
application run). This way you can check what are current push notifications permissions.
|
||||
|
||||
Note that settings are currently only used on iOS. When calling on other platforms, Settings
|
||||
with no categories and all allow* flags set to true will be received in
|
||||
Listener::notificationSettingsReceived().
|
||||
|
||||
You can also call requestSettingsUsed() to explicitly ask for current settings.
|
||||
*/
|
||||
void requestPermissionsWithSettings (const Settings& s);
|
||||
|
||||
/** Sends an asynchronous request to retrieve current settings that are currently in use.
|
||||
These can be exactly the same as used in requestPermissionsWithSettings(), but depending
|
||||
on user's subsequent changes in OS settings, the actual current settings may be
|
||||
different (e.g. user might have later decided to disable sounds).
|
||||
|
||||
Note that settings are currently only used on iOS. When calling on other platforms, Settings
|
||||
with no categories and all allow* flags set to true will be received in
|
||||
Listener::notificationSettingsReceived().
|
||||
*/
|
||||
void requestSettingsUsed();
|
||||
|
||||
//==========================================================================
|
||||
/** Android API level 26 or higher only: Represents notification channel through which
|
||||
notifications will be sent. Starting from Android API level 26, you should call setupChannels()
|
||||
at the start of your application, before posting any notifications. Then, when sending notifications,
|
||||
assign a channel to each created notification.
|
||||
*/
|
||||
struct Channel
|
||||
{
|
||||
String identifier; /**< Required: Unique channel identifier. */
|
||||
String name; /**< Required: User facing name of the channel. */
|
||||
|
||||
/** Controls how interruptive the notification posted on this channel are. */
|
||||
enum Importance
|
||||
{
|
||||
none,
|
||||
min,
|
||||
low,
|
||||
normal,
|
||||
high,
|
||||
max
|
||||
};
|
||||
|
||||
Importance importance = normal; /**< Required. */
|
||||
Notification::LockScreenAppearance lockScreenAppearance = Notification::showPartially; /**< Optional. */
|
||||
|
||||
String description; /**< Optional: user visible description of the channel. */
|
||||
String groupId; /**< Required: group this channel belongs to (see @class ChannelGroup). */
|
||||
Colour ledColour; /**< Optional: sets the led colour for notifications in this channel. */
|
||||
bool bypassDoNotDisturb = false; /**< Optional: true if notifications in this channel can bypass do not disturb setting. */
|
||||
bool canShowBadge = false; /**< Optional: true if notifications in this channel can show badges in a Launcher application. */
|
||||
bool enableLights = false; /**< Optional: true if notifications in this channel should show lights (subject to hardware support). */
|
||||
bool enableVibration = false; /**< Optional: true if notifications in this channel should trigger vibrations. */
|
||||
|
||||
URL soundToPlay; /**< Optional: sound to play in this channel. See Notification::soundToPlay for more info. */
|
||||
Array<int> vibrationPattern; /**< Optional: vibration pattern for this channel. See Notification::vibrationPattern for more info. */
|
||||
};
|
||||
|
||||
/** Android API level 26 or higher only: represents a channel group. This allows for
|
||||
visual grouping of corresponding channels in notification settings presented to the user.
|
||||
At least one channel group has to be specified before notifications can be sent.
|
||||
*/
|
||||
struct ChannelGroup
|
||||
{
|
||||
String identifier; /**< Required: Unique channel group identifier. */
|
||||
String name; /**< Required: User visible name of the channel group. */
|
||||
};
|
||||
|
||||
/** Android API level 26 or higher only: configures notification channel groups and channels to be
|
||||
used in the app. These have to be setup before notifications can be sent on Android API
|
||||
level 26 or higher.
|
||||
*/
|
||||
void setupChannels (const Array<ChannelGroup>&, const Array<Channel>&);
|
||||
|
||||
//==========================================================================
|
||||
/** iOS only: sends an asynchronous request to retrieve a list of notifications that were
|
||||
scheduled and not yet delivered.
|
||||
|
||||
When the list is retrieved, Listener::pendingLocalNotificationsListReceived() will be called.
|
||||
*/
|
||||
void getPendingLocalNotifications() const;
|
||||
|
||||
/** Unschedules a pending local notification with a given identifier. Available from iOS 10. */
|
||||
void removePendingLocalNotification (const String& identifier);
|
||||
|
||||
/** Unschedules all pending local notifications. iOS only. */
|
||||
void removeAllPendingLocalNotifications();
|
||||
|
||||
//==========================================================================
|
||||
/** Checks whether notifications are enabled for given application.
|
||||
On iOS this will always return true, use requestSettingsUsed() instead.
|
||||
*/
|
||||
bool areNotificationsEnabled() const;
|
||||
|
||||
/** On iOS as well as on Android, sends a local notification.
|
||||
On Android and iOS 10 or above, this will refresh an existing notification
|
||||
if the same identifier is used as in a notification that was already sent
|
||||
and not yet responded by a user.
|
||||
*/
|
||||
void sendLocalNotification (const Notification& n);
|
||||
|
||||
/** Sends a request for a list of notifications delivered. Such notifications are visible in the
|
||||
notification area on the device and they are still waiting for user action/response.
|
||||
When the request is finished Listener::deliveredNotificationsListReceived() will be called.
|
||||
|
||||
On iOS, iOS version 10 or higher is required. On Android, API level 18 or higher is required.
|
||||
For unsupported platforms, Listener::deliveredNotificationsListReceived() will return an empty array.
|
||||
*/
|
||||
void getDeliveredNotifications() const;
|
||||
|
||||
/** Removes a previously delivered notification. This can be useful for instance when the
|
||||
information in the notification becomes obsolete.
|
||||
*/
|
||||
void removeDeliveredNotification (const String& identifier);
|
||||
|
||||
/** Removes all notifications that were delivered. */
|
||||
void removeAllDeliveredNotifications();
|
||||
|
||||
//==========================================================================
|
||||
/** Retrieves current device token. Note, it is not a good idea to cache this token
|
||||
because it may change in the meantime. Always call this method to get the current
|
||||
token value.
|
||||
*/
|
||||
String getDeviceToken() const;
|
||||
|
||||
/** Android only: allows to subscribe to messages from a specific topic.
|
||||
So you could for instance subscribe this device to all "sports" topic messages
|
||||
to receive any remote notifications that have "sports" topic set.
|
||||
Refer to Firebase documentation for how to send topic messages.
|
||||
*/
|
||||
void subscribeToTopic (const String& topic);
|
||||
|
||||
/** Android only: allows to remove a topic subscription that was previously added with
|
||||
subscribeToTopic().
|
||||
*/
|
||||
void unsubscribeFromTopic (const String& topic);
|
||||
|
||||
/** Android only: sends an upstream message to your app server. The server must implement
|
||||
XMPP Connection Server protocol (refer to Firebase documentation).
|
||||
|
||||
@param serverSenderId Represents the sender. Consult your Firebase project
|
||||
settings to retrieve the sender id.
|
||||
|
||||
@param collapseKey Remote messages with the same collapse key that were not
|
||||
yet delivered will be collapsed into one, with the
|
||||
newest message replacing all the previous ones.
|
||||
Note that there may be a limit of maximum collapse keys
|
||||
used at the same time and beyond the limit (refer to
|
||||
Firebase documentation) it is not guaranteed which keys
|
||||
will be in use by the server.
|
||||
|
||||
@param messageId A unique message ID. Used in error callbacks and debugging.
|
||||
|
||||
@param messageType Message type.
|
||||
|
||||
@param timeToLive TTL in seconds. If 0, the message sending will be attempted
|
||||
immediately and it will be dropped if the device is not
|
||||
connected. Otherwise, the message will be queued for the
|
||||
period specified.
|
||||
|
||||
@param additionalData Collection of key-value pairs to be used as an additional
|
||||
data for the message.
|
||||
*/
|
||||
void sendUpstreamMessage (const String& serverSenderId,
|
||||
const String& collapseKey,
|
||||
const String& messageId,
|
||||
const String& messageType,
|
||||
int timeToLive,
|
||||
const StringPairArray& additionalData);
|
||||
|
||||
//==========================================================================
|
||||
/** Register a listener (ideally on application startup) to receive information about
|
||||
notifications received and any callbacks to async functions called.
|
||||
*/
|
||||
struct Listener
|
||||
{
|
||||
virtual ~Listener() {}
|
||||
|
||||
/** This callback will be called after you call requestSettingsUsed() or
|
||||
requestPermissionsWithSettings().
|
||||
|
||||
Note that settings are currently only used on iOS. When called on other platforms, Settings
|
||||
with no categories and all allow* flags set to true will be received in
|
||||
Listener::notificationSettingsReceived().
|
||||
*/
|
||||
virtual void notificationSettingsReceived (const Settings&) {}
|
||||
|
||||
/** Called when the list of pending notifications, requested by calling
|
||||
getPendingLocalNotifications() is returned. iOS 10 or above only.
|
||||
*/
|
||||
virtual void pendingLocalNotificationsListReceived (const Array<Notification>&) {}
|
||||
|
||||
/** This can be called in multiple different situations, depending on the OS and the situation.
|
||||
|
||||
On pre iOS 10 device it will be called when a user presses on a notification or when a
|
||||
notification was received when the app was in the foreground already. On iOS 10 it will be
|
||||
called when a user presses on a notification
|
||||
|
||||
Note: on Android, if remote notification was received while the app was in the background and
|
||||
then user pressed on it, the notification object received in this callback will contain only
|
||||
"properties" member set. Hence, if you want to know what was the notification title, content
|
||||
etc, you need to set them as additional properties, so that you will be able to restore them
|
||||
from "properties" dictionary.
|
||||
|
||||
Note you can receive this callback on startup, if the application was launched from a notification.
|
||||
*/
|
||||
virtual void handleNotification (bool /*isLocalNotification*/, const Notification& /*n*/) {}
|
||||
|
||||
/** This can be called when a user performs some action on the notification such as
|
||||
pressing on an action button or responding with a text input.
|
||||
Note that pressing on a notification area, i.e. not on an action button is not considered
|
||||
to be an action, and hence receivedNotification() will be called in that case.
|
||||
|
||||
Note you can receive this callback on startup, if the application was launched from a notification's action.
|
||||
|
||||
@param optionalResponse Text response a user inputs for notifications with a text input.
|
||||
Empty for notifications without a text input option.
|
||||
|
||||
*/
|
||||
virtual void handleNotificationAction (bool /*isLocalNotification*/,
|
||||
const Notification& /*n*/,
|
||||
const String& /*actionIdentifier*/,
|
||||
const String& /*optionalResponse*/) {}
|
||||
|
||||
/** For iOS10 and Android, this can be also called when a user dismissed the notification before
|
||||
responding to it.
|
||||
*/
|
||||
virtual void localNotificationDismissedByUser (const Notification& /*n*/) {}
|
||||
|
||||
/** Called after getDeliveredNotifications() request is fulfilled. Returns notifications
|
||||
that are visible in the notification area on the device and that are still waiting
|
||||
for a user action/response.
|
||||
|
||||
On iOS, iOS version 10 or higher is required. On Android, API level 18 or higher is required.
|
||||
For unsupported platforms, an empty array will be returned.
|
||||
*/
|
||||
virtual void deliveredNotificationsListReceived (const Array<Notification>&) {}
|
||||
|
||||
/** Called whenever a token gets refreshed. You should monitor any token updates, because
|
||||
only the last token that is assigned to device is valid and can be used.
|
||||
*/
|
||||
virtual void deviceTokenRefreshed (const String& /*token*/) {}
|
||||
|
||||
/** Called when Firebase Cloud Messaging server deletes pending messages. This can happen when
|
||||
1) too many messages were sent to the server (hint: use collapsible messages).
|
||||
2) the devices hasn't been online in a long time (refer to Firebase documentation for
|
||||
the maximum time a message can be stored on FCM before expiring).
|
||||
*/
|
||||
virtual void remoteNotificationsDeleted() {}
|
||||
|
||||
/** Called when an upstream message sent with PushNotifications::sendUpstreamMessage() has been
|
||||
sent successfully.
|
||||
Bear in mind that in may take several minutes or more to receive this callback.
|
||||
*/
|
||||
virtual void upstreamMessageSent (const String& /*messageId*/) {}
|
||||
|
||||
/** Called when there was an error sending an upstream message with
|
||||
PushNotifications::sendUpstreamMessage().
|
||||
Bear in mind that in may take several minutes or more to receive this callback.
|
||||
*/
|
||||
virtual void upstreamMessageSendingError (const String& /*messageId*/, const String& /*error*/) {}
|
||||
};
|
||||
|
||||
void addListener (Listener* l);
|
||||
void removeListener (Listener* l);
|
||||
|
||||
private:
|
||||
PushNotifications();
|
||||
~PushNotifications();
|
||||
|
||||
ListenerList<PushNotifications::Listener> listeners;
|
||||
|
||||
#if JUCE_ANDROID
|
||||
friend bool juce_handleNotificationIntent (void* intent);
|
||||
friend void juce_firebaseDeviceNotificationsTokenRefreshed (void*);
|
||||
friend void juce_firebaseRemoteNotificationReceived (void*);
|
||||
friend void juce_firebaseRemoteMessagesDeleted();
|
||||
friend void juce_firebaseRemoteMessageSent (void*);
|
||||
friend void juce_firebaseRemoteMessageSendError (void*, void*);
|
||||
#endif
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
struct Pimpl;
|
||||
friend struct Pimpl;
|
||||
|
||||
ScopedPointer<Pimpl> pimpl;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||