mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
PushNotifications: add OSX implementation.
This commit is contained in:
parent
87831624cb
commit
b8b304e4cd
11 changed files with 1313 additions and 694 deletions
|
|
@ -31,19 +31,25 @@
|
|||
</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="BinaryResources/sounds/demonstrative.caf" xcodeResource="0"/>
|
||||
<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="BinaryResources/sounds/demonstrative.mp3" xcodeResource="1"/>
|
||||
<FILE id="PWlDpi" name="isntit.caf" compile="0" resource="1" file="BinaryResources/sounds/isntit.caf"
|
||||
xcodeResource="0"/>
|
||||
<FILE id="nbNoVQ" name="isntit.mp3" compile="0" resource="1" file="BinaryResources/sounds/isntit.mp3"
|
||||
xcodeResource="1"/>
|
||||
<FILE id="AheEYO" name="jinglebellssms.caf" compile="0" resource="1"
|
||||
file="BinaryResources/sounds/jinglebellssms.caf"/>
|
||||
file="BinaryResources/sounds/jinglebellssms.caf" xcodeResource="0"/>
|
||||
<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"/>
|
||||
file="BinaryResources/sounds/jinglebellssms.mp3" xcodeResource="1"/>
|
||||
<FILE id="TmLrYM" name="served.caf" compile="0" resource="1" file="BinaryResources/sounds/served.caf"
|
||||
xcodeResource="0"/>
|
||||
<FILE id="Ad45fH" name="served.mp3" compile="0" resource="1" file="BinaryResources/sounds/served.mp3"
|
||||
xcodeResource="1"/>
|
||||
<FILE id="qH4XUR" name="solemn.caf" compile="0" resource="1" file="BinaryResources/sounds/solemn.caf"
|
||||
xcodeResource="0"/>
|
||||
<FILE id="cwrEXS" name="solemn.mp3" compile="0" resource="1" file="BinaryResources/sounds/solemn.mp3"
|
||||
xcodeResource="1"/>
|
||||
</GROUP>
|
||||
</GROUP>
|
||||
<GROUP id="{1AF8C966-743E-3F06-189C-AADD83767CB4}" name="Source">
|
||||
|
|
@ -104,7 +110,7 @@
|
|||
<MODULEPATH id="juce_audio_processors" path="../../modules"/>
|
||||
</MODULEPATHS>
|
||||
</ANDROIDSTUDIO>
|
||||
<XCODE_MAC targetFolder="Builds/MacOSX">
|
||||
<XCODE_MAC targetFolder="Builds/MacOSX" iosPushNotifications="1" customXcodeResourceFolders="./BinaryResources/images">
|
||||
<CONFIGURATIONS>
|
||||
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="PushNotificationsDemo"
|
||||
enablePluginBinaryCopyStep="1"/>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,10 @@
|
|||
//==============================================================================
|
||||
MainContentComponent::MainContentComponent()
|
||||
{
|
||||
#if JUCE_ANDROID || JUCE_IOS
|
||||
setupControls();
|
||||
distributeControls();
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
addAndMakeVisible (headerLabel);
|
||||
addAndMakeVisible (mainTabs);
|
||||
addAndMakeVisible (sendButton);
|
||||
|
|
@ -40,12 +43,18 @@ MainContentComponent::MainContentComponent()
|
|||
headerLabel.setJustificationType (Justification::centred);
|
||||
notAvailableYetLabel.setJustificationType (Justification::centred);
|
||||
|
||||
#if JUCE_MAC
|
||||
StringArray tabNames { "Params1", "Params2", "Params3", "Params4" };
|
||||
#else
|
||||
StringArray tabNames { "Req. params", "Opt. params1", "Opt. params2", "Opt. params3" };
|
||||
#endif
|
||||
|
||||
const auto colour = getLookAndFeel().findColour (ResizableWindow::backgroundColourId);
|
||||
localNotificationsTabs.addTab ("Req. params", colour, &requiredParamsView, false);
|
||||
localNotificationsTabs.addTab ("Opt. params1", colour, &optionalParamsOneView, false);
|
||||
localNotificationsTabs.addTab (tabNames[0], colour, ¶msOneView, false);
|
||||
localNotificationsTabs.addTab (tabNames[1], colour, ¶msTwoView, false);
|
||||
#if JUCE_ANDROID
|
||||
localNotificationsTabs.addTab ("Opt. params2", colour, &optionalParamsTwoView, false);
|
||||
localNotificationsTabs.addTab ("Opt. params3", colour, &optionalParamsThreeView, false);
|
||||
localNotificationsTabs.addTab (tabNames[2], colour, ¶msThreeView, false);
|
||||
localNotificationsTabs.addTab (tabNames[3], colour, ¶msFourView, false);
|
||||
#endif
|
||||
localNotificationsTabs.addTab ("Aux. actions", colour, &auxActionsView, false);
|
||||
|
||||
|
|
@ -63,7 +72,7 @@ MainContentComponent::MainContentComponent()
|
|||
auxActionsView.getDeliveredNotificationsButton .addListener (this);
|
||||
auxActionsView.removeDeliveredNotifWithIdButton.addListener (this);
|
||||
auxActionsView.removeAllDeliveredNotifsButton .addListener (this);
|
||||
#if JUCE_IOS
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
auxActionsView.getPendingNotificationsButton .addListener (this);
|
||||
auxActionsView.removePendingNotifWithIdButton.addListener (this);
|
||||
auxActionsView.removeAllPendingNotifsButton .addListener (this);
|
||||
|
|
@ -74,16 +83,16 @@ MainContentComponent::MainContentComponent()
|
|||
remoteView.subscribeToSportsButton .addListener (this);
|
||||
remoteView.unsubscribeFromSportsButton.addListener (this);
|
||||
|
||||
optionalParamsThreeView.accentColourButton.addListener (this);
|
||||
optionalParamsThreeView.ledColourButton .addListener (this);
|
||||
paramControls.accentColourButton.addListener (this);
|
||||
paramControls.ledColourButton .addListener (this);
|
||||
|
||||
jassert (PushNotifications::getInstance()->areNotificationsEnabled());
|
||||
|
||||
PushNotifications::getInstance()->addListener (this);
|
||||
|
||||
#if JUCE_IOS
|
||||
optionalParamsOneView.fireInComboBox.addListener (this);
|
||||
PushNotifications::getInstance()->requestPermissionsWithSettings (getIosSettings());
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
paramControls.fireInComboBox.addListener (this);
|
||||
PushNotifications::getInstance()->requestPermissionsWithSettings (getNotificationSettings());
|
||||
#elif JUCE_ANDROID
|
||||
PushNotifications::ChannelGroup cg { "demoGroup", "demo group" };
|
||||
PushNotifications::getInstance()->setupChannels ({{ cg }}, getAndroidChannels());
|
||||
|
|
@ -95,6 +104,200 @@ MainContentComponent::~MainContentComponent()
|
|||
PushNotifications::getInstance()->removeListener (this);
|
||||
}
|
||||
|
||||
void MainContentComponent::setupControls()
|
||||
{
|
||||
auto& pc = paramControls;
|
||||
|
||||
StringArray categories { "okCategory", "okCancelCategory", "textCategory" };
|
||||
|
||||
for (const auto& c : categories)
|
||||
pc.categoryComboBox.addItem (c, pc.categoryComboBox.getNumItems() + 1);
|
||||
pc.categoryComboBox.setSelectedItemIndex (0);
|
||||
|
||||
for (int i = 1; i <= 3; ++i)
|
||||
pc.channelIdComboBox.addItem (String (i), i);
|
||||
pc.channelIdComboBox.setSelectedItemIndex (0);
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
pc.iconComboBox.addItem ("icon" + String (i + 1), i + 1);
|
||||
pc.iconComboBox.setSelectedItemIndex (0);
|
||||
|
||||
#if JUCE_MAC
|
||||
pc.iconComboBox.addItem ("none", 100);
|
||||
#endif
|
||||
|
||||
pc.fireInComboBox.addItem ("Now", 1);
|
||||
|
||||
for (int i = 1; i < 11; ++i)
|
||||
pc.fireInComboBox.addItem (String (10 * i) + "seconds", i + 1);
|
||||
pc.fireInComboBox.setSelectedItemIndex (0);
|
||||
|
||||
pc.largeIconComboBox.addItem ("none", 1);
|
||||
|
||||
for (int i = 1; i < 5; ++i)
|
||||
pc.largeIconComboBox.addItem ("icon" + String (i), i + 1);
|
||||
pc.largeIconComboBox.setSelectedItemIndex (0);
|
||||
|
||||
pc.badgeIconComboBox.addItem ("none", 1);
|
||||
pc.badgeIconComboBox.addItem ("small", 2);
|
||||
pc.badgeIconComboBox.addItem ("large", 3);
|
||||
pc.badgeIconComboBox.setSelectedItemIndex (2);
|
||||
|
||||
pc.actionsComboBox.addItem ("none", 1);
|
||||
pc.actionsComboBox.addItem ("ok-cancel", 2);
|
||||
pc.actionsComboBox.addItem ("text-input", 3);
|
||||
#if JUCE_ANDROID
|
||||
pc.actionsComboBox.addItem ("ok-cancel-icons", 4);
|
||||
pc.actionsComboBox.addItem ("text-input-limited_responses", 5);
|
||||
#endif
|
||||
pc.actionsComboBox.setSelectedItemIndex (0);
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
pc.badgeNumberComboBox.addItem (String (i), i + 1);
|
||||
pc.badgeNumberComboBox.setSelectedItemIndex (0);
|
||||
|
||||
#if JUCE_IOS
|
||||
String prefix = "sounds/";
|
||||
String extension = ".caf";
|
||||
#else
|
||||
String prefix;
|
||||
String extension;
|
||||
#endif
|
||||
|
||||
pc.soundToPlayComboBox.addItem ("none", 1);
|
||||
pc.soundToPlayComboBox.addItem ("default_os_sound", 2);
|
||||
pc.soundToPlayComboBox.addItem (prefix + "demonstrative" + extension, 3);
|
||||
pc.soundToPlayComboBox.addItem (prefix + "isntit" + extension, 4);
|
||||
pc.soundToPlayComboBox.addItem (prefix + "jinglebellssms" + extension, 5);
|
||||
pc.soundToPlayComboBox.addItem (prefix + "served" + extension, 6);
|
||||
pc.soundToPlayComboBox.addItem (prefix + "solemn" + extension, 7);
|
||||
pc.soundToPlayComboBox.setSelectedItemIndex (1);
|
||||
|
||||
for (int i = 0; i < 11; ++i)
|
||||
{
|
||||
pc.progressMaxComboBox .addItem (String (i * 10) + "%", i + 1);
|
||||
pc.progressCurrentComboBox.addItem (String (i * 10) + "%", i + 1);
|
||||
}
|
||||
|
||||
pc.progressMaxComboBox .setSelectedItemIndex (0);
|
||||
pc.progressCurrentComboBox.setSelectedItemIndex (0);
|
||||
|
||||
pc.notifCategoryComboBox.addItem ("unspecified", 1);
|
||||
pc.notifCategoryComboBox.addItem ("alarm", 2);
|
||||
pc.notifCategoryComboBox.addItem ("call", 3);
|
||||
pc.notifCategoryComboBox.addItem ("email", 4);
|
||||
pc.notifCategoryComboBox.addItem ("error", 5);
|
||||
pc.notifCategoryComboBox.addItem ("event", 6);
|
||||
pc.notifCategoryComboBox.addItem ("message", 7);
|
||||
pc.notifCategoryComboBox.addItem ("progress", 8);
|
||||
pc.notifCategoryComboBox.addItem ("promo", 9);
|
||||
pc.notifCategoryComboBox.addItem ("recommendation", 10);
|
||||
pc.notifCategoryComboBox.addItem ("reminder", 11);
|
||||
pc.notifCategoryComboBox.addItem ("service", 12);
|
||||
pc.notifCategoryComboBox.addItem ("social", 13);
|
||||
pc.notifCategoryComboBox.addItem ("status", 14);
|
||||
pc.notifCategoryComboBox.addItem ("system", 15);
|
||||
pc.notifCategoryComboBox.addItem ("transport", 16);
|
||||
pc.notifCategoryComboBox.setSelectedItemIndex (0);
|
||||
|
||||
for (int i = -2; i < 3; ++i)
|
||||
pc.priorityComboBox.addItem (String (i), i + 3);
|
||||
pc.priorityComboBox.setSelectedItemIndex (2);
|
||||
|
||||
pc.lockScreenVisibilityComboBox.addItem ("don't show", 1);
|
||||
pc.lockScreenVisibilityComboBox.addItem ("show partially", 2);
|
||||
pc.lockScreenVisibilityComboBox.addItem ("show completely", 3);
|
||||
pc.lockScreenVisibilityComboBox.setSelectedItemIndex (1);
|
||||
|
||||
pc.groupAlertBehaviourComboBox.addItem ("alert all", 1);
|
||||
pc.groupAlertBehaviourComboBox.addItem ("alert summary", 2);
|
||||
pc.groupAlertBehaviourComboBox.addItem ("alert children", 3);
|
||||
pc.groupAlertBehaviourComboBox.setSelectedItemIndex (0);
|
||||
|
||||
pc.timeoutAfterComboBox.addItem ("No timeout", 1);
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
pc.ledMsToBeOnComboBox .addItem (String (i * 200) + "ms", i + 1);
|
||||
pc.ledMsToBeOffComboBox .addItem (String (i * 200) + "ms", i + 1);
|
||||
pc.vibratorMsToBeOnComboBox .addItem (String (i * 500) + "ms", i + 1);
|
||||
pc.vibratorMsToBeOffComboBox.addItem (String (i * 500) + "ms", i + 1);
|
||||
pc.timeoutAfterComboBox.addItem (String (5000 + 1000 * i) + "ms", i + 2);
|
||||
}
|
||||
|
||||
pc.ledMsToBeOnComboBox .setSelectedItemIndex (5);
|
||||
pc.ledMsToBeOffComboBox .setSelectedItemIndex (5);
|
||||
pc.vibratorMsToBeOnComboBox .setSelectedItemIndex (0);
|
||||
pc.vibratorMsToBeOffComboBox.setSelectedItemIndex (0);
|
||||
pc.timeoutAfterComboBox.setSelectedItemIndex (0);
|
||||
|
||||
pc.timestampVisibilityComboBox.addItem ("off", 1);
|
||||
pc.timestampVisibilityComboBox.addItem ("on", 2);
|
||||
pc.timestampVisibilityComboBox.addItem ("chronometer", 3);
|
||||
pc.timestampVisibilityComboBox.addItem ("count down", 4);
|
||||
pc.timestampVisibilityComboBox.setSelectedItemIndex (1);
|
||||
}
|
||||
|
||||
void MainContentComponent::distributeControls()
|
||||
{
|
||||
auto& pc = paramControls;
|
||||
|
||||
paramsOneView.addRowComponent (new RowComponent (pc.identifierLabel, pc.identifierEditor));
|
||||
paramsOneView.addRowComponent (new RowComponent (pc.titleLabel, pc.titleEditor));
|
||||
paramsOneView.addRowComponent (new RowComponent (pc.bodyLabel, pc.bodyEditor, 4));
|
||||
#if JUCE_IOS
|
||||
paramsOneView.addRowComponent (new RowComponent (pc.categoryLabel, pc.categoryComboBox));
|
||||
#elif JUCE_ANDROID
|
||||
paramsOneView.addRowComponent (new RowComponent (pc.channelIdLabel, pc.channelIdComboBox));
|
||||
#endif
|
||||
#if JUCE_ANDROID || JUCE_MAC
|
||||
paramsOneView.addRowComponent (new RowComponent (pc.iconLabel, pc.iconComboBox));
|
||||
#endif
|
||||
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.subtitleLabel, pc.subtitleEditor));
|
||||
#if ! JUCE_MAC
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.badgeNumberLabel, pc.badgeNumberComboBox));
|
||||
#endif
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.soundToPlayLabel, pc.soundToPlayComboBox));
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.propertiesLabel, pc.propertiesEditor, 3));
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.fireInLabel, pc.fireInComboBox));
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.repeatLabel, pc.repeatButton));
|
||||
#elif JUCE_ANDROID
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.largeIconLabel, pc.largeIconComboBox));
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.badgeIconLabel, pc.badgeIconComboBox));
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.tickerTextLabel, pc.tickerTextEditor));
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.autoCancelLabel, pc.autoCancelButton));
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.alertOnlyOnceLabel, pc.alertOnlyOnceButton));
|
||||
#endif
|
||||
#if JUCE_ANDROID || JUCE_MAC
|
||||
paramsTwoView.addRowComponent (new RowComponent (pc.actionsLabel, pc.actionsComboBox));
|
||||
#endif
|
||||
#if JUCE_ANDROID
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.progressMaxLabel, pc.progressMaxComboBox));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.progressCurrentLabel, pc.progressCurrentComboBox));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.progressIndeterminateLabel, pc.progressIndeterminateButton));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.categoryLabel, pc.categoryComboBox));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.priorityLabel, pc.priorityComboBox));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.personLabel, pc.personEditor));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.lockScreenVisibilityLabel, pc.lockScreenVisibilityComboBox));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.groupIdLabel, pc.groupIdEditor));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.sortKeyLabel, pc.sortKeyEditor));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.groupSummaryLabel, pc.groupSummaryButton));
|
||||
paramsThreeView.addRowComponent (new RowComponent (pc.groupAlertBehaviourLabel, pc.groupAlertBehaviourComboBox));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.accentColourLabel, pc.accentColourButton));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.ledColourLabel, pc.ledColourButton));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.ledMsToBeOffLabel, pc.ledMsToBeOffComboBox));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.ledMsToBeOnLabel, pc.ledMsToBeOnComboBox));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.vibratorMsToBeOffLabel, pc.vibratorMsToBeOffComboBox));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.vibratorMsToBeOnLabel, pc.vibratorMsToBeOnComboBox));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.localOnlyLabel, pc.localOnlyButton));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.ongoingLabel, pc.ongoingButton));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.timestampVisibilityLabel, pc.timestampVisibilityComboBox));
|
||||
paramsFourView.addRowComponent (new RowComponent (pc.timeoutAfterLabel, pc.timeoutAfterComboBox));
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainContentComponent::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
|
||||
|
|
@ -117,9 +320,9 @@ void MainContentComponent::buttonClicked (Button* b)
|
|||
{
|
||||
if (b == &sendButton)
|
||||
sendLocalNotification();
|
||||
else if (b == &optionalParamsThreeView.accentColourButton)
|
||||
else if (b == ¶mControls.accentColourButton)
|
||||
setupAccentColour();
|
||||
else if (b == &optionalParamsThreeView.ledColourButton)
|
||||
else if (b == ¶mControls.ledColourButton)
|
||||
setupLedColour();
|
||||
else if (b == &auxActionsView.getDeliveredNotificationsButton)
|
||||
getDeliveredNotifications();
|
||||
|
|
@ -127,7 +330,7 @@ void MainContentComponent::buttonClicked (Button* b)
|
|||
PushNotifications::getInstance()->removeDeliveredNotification (auxActionsView.deliveredNotifIdentifier.getText());
|
||||
else if (b == &auxActionsView.removeAllDeliveredNotifsButton)
|
||||
PushNotifications::getInstance()->removeAllDeliveredNotifications();
|
||||
#if JUCE_IOS
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
else if (b == &auxActionsView.getPendingNotificationsButton)
|
||||
PushNotifications::getInstance()->getPendingLocalNotifications();
|
||||
else if (b == &auxActionsView.removePendingNotifWithIdButton)
|
||||
|
|
@ -141,6 +344,9 @@ void MainContentComponent::buttonClicked (Button* b)
|
|||
|
||||
DBG ("token = " + token);
|
||||
|
||||
if (token.isEmpty())
|
||||
showRemoteInstructions();
|
||||
else
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon, "Device token", token);
|
||||
}
|
||||
#if JUCE_ANDROID
|
||||
|
|
@ -172,19 +378,15 @@ void MainContentComponent::buttonClicked (Button* b)
|
|||
|
||||
void MainContentComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
|
||||
{
|
||||
#if JUCE_IOS
|
||||
if (comboBoxThatHasChanged == &optionalParamsOneView.fireInComboBox)
|
||||
if (comboBoxThatHasChanged == ¶mControls.fireInComboBox)
|
||||
{
|
||||
const bool repeatsAllowed = optionalParamsOneView.fireInComboBox.getSelectedItemIndex() >= 6;
|
||||
const bool repeatsAllowed = paramControls.fireInComboBox.getSelectedItemIndex() >= 6;
|
||||
|
||||
optionalParamsOneView.repeatButton.setEnabled (repeatsAllowed);
|
||||
paramControls.repeatButton.setEnabled (repeatsAllowed);
|
||||
|
||||
if (! repeatsAllowed)
|
||||
optionalParamsOneView.repeatButton.setToggleState (false, NotificationType::sendNotification);
|
||||
paramControls.repeatButton.setToggleState (false, NotificationType::sendNotification);
|
||||
}
|
||||
#else
|
||||
ignoreUnused (comboBoxThatHasChanged);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainContentComponent::sendLocalNotification()
|
||||
|
|
@ -222,23 +424,32 @@ void MainContentComponent::sendLocalNotification()
|
|||
|
||||
void MainContentComponent::fillRequiredParams (PushNotifications::Notification& n)
|
||||
{
|
||||
n.identifier = requiredParamsView.identifierEditor.getText();
|
||||
n.title = requiredParamsView.titleEditor.getText();
|
||||
n.body = requiredParamsView.bodyEditor.getText();
|
||||
n.identifier = paramControls.identifierEditor.getText();
|
||||
n.title = paramControls.titleEditor.getText();
|
||||
n.body = paramControls.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";
|
||||
n.category = paramControls.categoryComboBox.getText();
|
||||
#elif JUCE_ANDROID || JUCE_MAC
|
||||
#if JUCE_MAC
|
||||
String prefix = "images/";
|
||||
String extension = ".png";
|
||||
#else
|
||||
String prefix;
|
||||
String extension;
|
||||
#endif
|
||||
if (paramControls.iconComboBox.getSelectedItemIndex() == 0)
|
||||
n.icon = prefix + "ic_stat_name" + extension;
|
||||
else if (paramControls.iconComboBox.getSelectedItemIndex() == 1)
|
||||
n.icon = prefix + "ic_stat_name2" + extension;
|
||||
else if (paramControls.iconComboBox.getSelectedItemIndex() == 2)
|
||||
n.icon = prefix + "ic_stat_name3" + extension;
|
||||
else if (paramControls.iconComboBox.getSelectedItemIndex() == 3)
|
||||
n.icon = prefix + "ic_stat_name4" + extension;
|
||||
else if (paramControls.iconComboBox.getSelectedItemIndex() == 4)
|
||||
n.icon = prefix + "ic_stat_name5" + extension;
|
||||
#endif
|
||||
|
||||
#if JUCE_ANDROID
|
||||
// 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";
|
||||
|
|
@ -247,69 +458,59 @@ void MainContentComponent::fillRequiredParams (PushNotifications::Notification&
|
|||
n.publicVersion->icon = n.icon;
|
||||
|
||||
#if __ANDROID_API__ >= 26
|
||||
n.channelId = String (requiredParamsView.channelIdComboBox.getSelectedItemIndex() + 1);
|
||||
n.channelId = String (paramControls.channelIdComboBox.getSelectedItemIndex() + 1);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainContentComponent::fillOptionalParamsOne (PushNotifications::Notification& n)
|
||||
{
|
||||
n.subtitle = optionalParamsOneView.subtitleEditor.getText();
|
||||
n.badgeNumber = optionalParamsOneView.badgeNumberComboBox.getSelectedItemIndex();
|
||||
n.subtitle = paramControls.subtitleEditor.getText();
|
||||
n.badgeNumber = paramControls.badgeNumberComboBox.getSelectedItemIndex();
|
||||
|
||||
if (optionalParamsOneView.soundToPlayComboBox.getSelectedItemIndex() > 0)
|
||||
n.soundToPlay = URL (optionalParamsOneView.soundToPlayComboBox.getItemText (optionalParamsOneView.soundToPlayComboBox.getSelectedItemIndex()));
|
||||
if (paramControls.soundToPlayComboBox.getSelectedItemIndex() > 0)
|
||||
n.soundToPlay = URL (paramControls.soundToPlayComboBox.getItemText (paramControls.soundToPlayComboBox.getSelectedItemIndex()));
|
||||
|
||||
n.properties = JSON::parse (optionalParamsOneView.propertiesEditor.getText());
|
||||
n.properties = JSON::parse (paramControls.propertiesEditor.getText());
|
||||
|
||||
#if JUCE_IOS
|
||||
n.triggerIntervalSec = double (optionalParamsOneView.fireInComboBox.getSelectedItemIndex() * 10);
|
||||
n.repeat = optionalParamsOneView.repeatButton.getToggleState();
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
n.triggerIntervalSec = double (paramControls.fireInComboBox.getSelectedItemIndex() * 10);
|
||||
n.repeat = paramControls.repeatButton.getToggleState();
|
||||
#elif JUCE_ANDROID
|
||||
if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 1)
|
||||
if (paramControls.largeIconComboBox.getSelectedItemIndex() == 1)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name6_png, BinaryData::ic_stat_name6_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 2)
|
||||
else if (paramControls.largeIconComboBox.getSelectedItemIndex() == 2)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name7_png, BinaryData::ic_stat_name7_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 3)
|
||||
else if (paramControls.largeIconComboBox.getSelectedItemIndex() == 3)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name8_png, BinaryData::ic_stat_name8_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 4)
|
||||
else if (paramControls.largeIconComboBox.getSelectedItemIndex() == 4)
|
||||
n.largeIcon = ImageFileFormat::loadFrom (BinaryData::ic_stat_name9_png, BinaryData::ic_stat_name9_pngSize);
|
||||
else if (optionalParamsOneView.largeIconComboBox.getSelectedItemIndex() == 5)
|
||||
else if (paramControls.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.badgeIconType = (PushNotifications::Notification::BadgeIconType) paramControls.badgeIconComboBox.getSelectedItemIndex();
|
||||
n.tickerText = paramControls.tickerTextEditor.getText();
|
||||
|
||||
n.shouldAutoCancel = optionalParamsOneView.autoCancelButton.getToggleState();
|
||||
n.alertOnlyOnce = optionalParamsOneView.alertOnlyOnceButton.getToggleState();
|
||||
n.shouldAutoCancel = paramControls.autoCancelButton.getToggleState();
|
||||
n.alertOnlyOnce = paramControls.alertOnlyOnceButton.getToggleState();
|
||||
#endif
|
||||
|
||||
if (optionalParamsOneView.actionsComboBox.getSelectedItemIndex() == 1)
|
||||
#if JUCE_ANDROID || JUCE_MAC
|
||||
if (paramControls.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";
|
||||
a .title = a .identifier = "Ok";
|
||||
a2.title = a2.identifier = "Cancel";
|
||||
n.actions.add (a);
|
||||
n.actions.add (a2);
|
||||
}
|
||||
else if (optionalParamsOneView.actionsComboBox.getSelectedItemIndex() == 2)
|
||||
else if (paramControls.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 .title = a .identifier = "Input Text Here";
|
||||
a2.title = a2.identifier = "No";
|
||||
a .style = PushNotifications::Notification::Action::text;
|
||||
a2.style = PushNotifications::Notification::Action::button;
|
||||
a .icon = "ic_stat_name4";
|
||||
|
|
@ -318,11 +519,23 @@ void MainContentComponent::fillOptionalParamsOne (PushNotifications::Notificatio
|
|||
n.actions.add (a);
|
||||
n.actions.add (a2);
|
||||
}
|
||||
else if (optionalParamsOneView.actionsComboBox.getSelectedItemIndex() == 4)
|
||||
else if (paramControls.actionsComboBox.getSelectedItemIndex() == 3)
|
||||
{
|
||||
PushNotifications::Notification::Action a, a2;
|
||||
a .title = "Input Text Here";
|
||||
a2.title = "No";
|
||||
a .title = a .identifier = "Ok";
|
||||
a2.title = a2.identifier = "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 (paramControls.actionsComboBox.getSelectedItemIndex() == 4)
|
||||
{
|
||||
PushNotifications::Notification::Action a, a2;
|
||||
a .title = a .identifier = "Input Text Here";
|
||||
a2.title = a2.identifier = "No";
|
||||
a .style = PushNotifications::Notification::Action::text;
|
||||
a2.style = PushNotifications::Notification::Action::button;
|
||||
a .icon = "ic_stat_name4";
|
||||
|
|
@ -342,102 +555,102 @@ void MainContentComponent::fillOptionalParamsTwo (PushNotifications::Notificatio
|
|||
using Notification = PushNotifications::Notification;
|
||||
|
||||
Notification::Progress progress;
|
||||
progress.max = optionalParamsTwoView.progressMaxComboBox.getSelectedItemIndex() * 10;
|
||||
progress.current = optionalParamsTwoView.progressCurrentComboBox.getSelectedItemIndex() * 10;
|
||||
progress.indeterminate = optionalParamsTwoView.progressIndeterminateButton.getToggleState();
|
||||
progress.max = paramControls.progressMaxComboBox.getSelectedItemIndex() * 10;
|
||||
progress.current = paramControls.progressCurrentComboBox.getSelectedItemIndex() * 10;
|
||||
progress.indeterminate = paramControls.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());
|
||||
n.person = paramControls.personEditor.getText();
|
||||
n.type = Notification::Type (paramControls.categoryComboBox.getSelectedItemIndex());
|
||||
n.priority = Notification::Priority (paramControls.priorityComboBox.getSelectedItemIndex() - 2);
|
||||
n.lockScreenAppearance = Notification::LockScreenAppearance (paramControls.lockScreenVisibilityComboBox.getSelectedItemIndex() - 1);
|
||||
n.groupId = paramControls.groupIdEditor.getText();
|
||||
n.groupSortKey = paramControls.sortKeyEditor.getText();
|
||||
n.groupSummary = paramControls.groupSummaryButton.getToggleState();
|
||||
n.groupAlertBehaviour = Notification::GroupAlertBehaviour (paramControls.groupAlertBehaviourComboBox.getSelectedItemIndex());
|
||||
}
|
||||
|
||||
void MainContentComponent::fillOptionalParamsThree (PushNotifications::Notification& n)
|
||||
{
|
||||
n.accentColour = optionalParamsThreeView.accentColourButton.findColour (TextButton::buttonColourId, false);
|
||||
n.ledColour = optionalParamsThreeView.ledColourButton .findColour (TextButton::buttonColourId, false);
|
||||
n.accentColour = paramControls.accentColourButton.findColour (TextButton::buttonColourId, false);
|
||||
n.ledColour = paramControls.ledColourButton .findColour (TextButton::buttonColourId, false);
|
||||
|
||||
using Notification = PushNotifications::Notification;
|
||||
Notification::LedBlinkPattern ledBlinkPattern;
|
||||
ledBlinkPattern.msToBeOn = optionalParamsThreeView.ledMsToBeOnComboBox .getSelectedItemIndex() * 200;
|
||||
ledBlinkPattern.msToBeOff = optionalParamsThreeView.ledMsToBeOffComboBox.getSelectedItemIndex() * 200;
|
||||
ledBlinkPattern.msToBeOn = paramControls.ledMsToBeOnComboBox .getSelectedItemIndex() * 200;
|
||||
ledBlinkPattern.msToBeOff = paramControls.ledMsToBeOffComboBox.getSelectedItemIndex() * 200;
|
||||
n.ledBlinkPattern = ledBlinkPattern;
|
||||
|
||||
Array<int> vibrationPattern;
|
||||
|
||||
if (optionalParamsThreeView.vibratorMsToBeOnComboBox .getSelectedItemIndex() > 0 &&
|
||||
optionalParamsThreeView.vibratorMsToBeOffComboBox.getSelectedItemIndex() > 0)
|
||||
if (paramControls.vibratorMsToBeOnComboBox .getSelectedItemIndex() > 0 &&
|
||||
paramControls.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);
|
||||
vibrationPattern.add (paramControls.vibratorMsToBeOffComboBox.getSelectedItemIndex() * 500);
|
||||
vibrationPattern.add (paramControls.vibratorMsToBeOnComboBox .getSelectedItemIndex() * 500);
|
||||
vibrationPattern.add (2 * paramControls.vibratorMsToBeOffComboBox.getSelectedItemIndex() * 500);
|
||||
vibrationPattern.add (2 * paramControls.vibratorMsToBeOnComboBox .getSelectedItemIndex() * 500);
|
||||
}
|
||||
|
||||
n.vibrationPattern = vibrationPattern;
|
||||
|
||||
n.localOnly = optionalParamsThreeView.localOnlyButton.getToggleState();
|
||||
n.ongoing = optionalParamsThreeView.ongoingButton.getToggleState();
|
||||
n.timestampVisibility = Notification::TimestampVisibility (optionalParamsThreeView.timestampVisibilityComboBox.getSelectedItemIndex());
|
||||
n.localOnly = paramControls.localOnlyButton.getToggleState();
|
||||
n.ongoing = paramControls.ongoingButton.getToggleState();
|
||||
n.timestampVisibility = Notification::TimestampVisibility (paramControls.timestampVisibilityComboBox.getSelectedItemIndex());
|
||||
|
||||
if (optionalParamsThreeView.timeoutAfterComboBox.getSelectedItemIndex() > 0)
|
||||
if (paramControls.timeoutAfterComboBox.getSelectedItemIndex() > 0)
|
||||
{
|
||||
auto index = optionalParamsThreeView.timeoutAfterComboBox.getSelectedItemIndex();
|
||||
auto index = paramControls.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);
|
||||
paramControls.accentColourSelector = new ColourSelector();
|
||||
paramControls.accentColourSelector->setName ("accent colour");
|
||||
paramControls.accentColourSelector->setCurrentColour (paramControls.accentColourButton.findColour (TextButton::buttonColourId));
|
||||
paramControls.accentColourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
|
||||
paramControls.accentColourSelector->setSize (200, 200);
|
||||
paramControls.accentColourSelector->addComponentListener (this);
|
||||
paramControls.accentColourSelector->addChangeListener (this);
|
||||
|
||||
CallOutBox::launchAsynchronously (optionalParamsThreeView.accentColourSelector, optionalParamsThreeView.accentColourButton.getScreenBounds(), nullptr);
|
||||
CallOutBox::launchAsynchronously (paramControls.accentColourSelector, paramControls.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);
|
||||
paramControls.ledColourSelector = new ColourSelector();
|
||||
paramControls.ledColourSelector->setName ("led colour");
|
||||
paramControls.ledColourSelector->setCurrentColour (paramControls.ledColourButton.findColour (TextButton::buttonColourId));
|
||||
paramControls.ledColourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
|
||||
paramControls.ledColourSelector->setSize (200, 200);
|
||||
paramControls.ledColourSelector->addComponentListener (this);
|
||||
paramControls.ledColourSelector->addChangeListener (this);
|
||||
|
||||
CallOutBox::launchAsynchronously (optionalParamsThreeView.ledColourSelector, optionalParamsThreeView.accentColourButton.getScreenBounds(), nullptr);
|
||||
CallOutBox::launchAsynchronously (paramControls.ledColourSelector, paramControls.accentColourButton.getScreenBounds(), nullptr);
|
||||
}
|
||||
|
||||
void MainContentComponent::changeListenerCallback (ChangeBroadcaster* source)
|
||||
{
|
||||
if (source == optionalParamsThreeView.accentColourSelector)
|
||||
if (source == paramControls.accentColourSelector)
|
||||
{
|
||||
Colour c = optionalParamsThreeView.accentColourSelector->getCurrentColour();
|
||||
optionalParamsThreeView.accentColourButton.setColour (TextButton::buttonColourId, c);
|
||||
Colour c = paramControls.accentColourSelector->getCurrentColour();
|
||||
paramControls.accentColourButton.setColour (TextButton::buttonColourId, c);
|
||||
}
|
||||
else if (source == optionalParamsThreeView.ledColourSelector)
|
||||
else if (source == paramControls.ledColourSelector)
|
||||
{
|
||||
Colour c = optionalParamsThreeView.ledColourSelector->getCurrentColour();
|
||||
optionalParamsThreeView.ledColourButton.setColour (TextButton::buttonColourId, c);
|
||||
Colour c = paramControls.ledColourSelector->getCurrentColour();
|
||||
paramControls.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;
|
||||
if (&component == paramControls.accentColourSelector)
|
||||
paramControls.accentColourSelector = nullptr;
|
||||
else if (&component == paramControls.ledColourSelector)
|
||||
paramControls.ledColourSelector = nullptr;
|
||||
}
|
||||
|
||||
void MainContentComponent::handleNotification (bool isLocalNotification, const PushNotifications::Notification& n)
|
||||
|
|
@ -576,9 +789,15 @@ Array<PushNotifications::Channel> MainContentComponent::getAndroidChannels()
|
|||
return { ch1, ch2, ch3 };
|
||||
}
|
||||
|
||||
#elif JUCE_IOS
|
||||
PushNotifications::Settings MainContentComponent::getIosSettings()
|
||||
#elif JUCE_IOS || JUCE_MAC
|
||||
PushNotifications::Settings MainContentComponent::getNotificationSettings()
|
||||
{
|
||||
PushNotifications::Settings settings;
|
||||
settings.allowAlert = true;
|
||||
settings.allowBadge = true;
|
||||
settings.allowSound = true;
|
||||
|
||||
#if JUCE_IOS
|
||||
using Action = PushNotifications::Settings::Action;
|
||||
using Category = PushNotifications::Settings::Category;
|
||||
|
||||
|
|
@ -617,11 +836,8 @@ PushNotifications::Settings MainContentComponent::getIosSettings()
|
|||
textCategory.actions = { textAction };
|
||||
textCategory.sendDismissAction = true;
|
||||
|
||||
PushNotifications::Settings settings;
|
||||
settings.allowAlert = true;
|
||||
settings.allowBadge = true;
|
||||
settings.allowSound = true;
|
||||
settings.categories = { okCategory, okCancelCategory, textCategory };
|
||||
#endif
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,216 +88,49 @@ private:
|
|||
void upstreamMessageSendingError (const String& messageId, const String& error) override;
|
||||
|
||||
static Array<PushNotifications::Channel> getAndroidChannels();
|
||||
#elif JUCE_IOS
|
||||
static PushNotifications::Settings getIosSettings();
|
||||
#elif JUCE_IOS || JUCE_MAC
|
||||
static PushNotifications::Settings getNotificationSettings();
|
||||
#endif
|
||||
|
||||
struct RequiredParamsView : public Component
|
||||
struct RowComponent : public Component
|
||||
{
|
||||
RequiredParamsView()
|
||||
RowComponent (Label& l, Component& c, int u = 1)
|
||||
: label (l),
|
||||
editor (c),
|
||||
rowUnits (u)
|
||||
{
|
||||
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);
|
||||
addAndMakeVisible (label);
|
||||
addAndMakeVisible (editor);
|
||||
}
|
||||
|
||||
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 bounds = getLocalBounds();
|
||||
label .setBounds (bounds.removeFromLeft (getWidth() / 3));
|
||||
editor.setBounds (bounds);
|
||||
}
|
||||
|
||||
auto layoutRow = [labelColumnWidth] (Rectangle<int> rowBounds, Component& label, Component& editor)
|
||||
{
|
||||
label .setBounds (rowBounds.removeFromLeft (labelColumnWidth));
|
||||
editor.setBounds (rowBounds);
|
||||
Label& label;
|
||||
Component& editor;
|
||||
int rowUnits;
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
struct ParamControls
|
||||
{
|
||||
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" };
|
||||
|
|
@ -306,12 +139,10 @@ private:
|
|||
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" };
|
||||
|
|
@ -324,106 +155,6 @@ private:
|
|||
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;
|
||||
|
|
@ -431,8 +162,8 @@ private:
|
|||
ComboBox progressCurrentComboBox;
|
||||
Label progressIndeterminateLabel { "progressIndeterminateLabel", "ProgressIndeterminate" };
|
||||
ToggleButton progressIndeterminateButton;
|
||||
Label categoryLabel { "categoryLabel", "Category" };
|
||||
ComboBox categoryComboBox;
|
||||
Label notifCategoryLabel { "notifCategoryLabel", "Category" };
|
||||
ComboBox notifCategoryComboBox;
|
||||
Label priorityLabel { "priorityLabel", "Priority" };
|
||||
ComboBox priorityComboBox;
|
||||
Label personLabel { "personLabel", "Person" };
|
||||
|
|
@ -447,84 +178,6 @@ private:
|
|||
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;
|
||||
|
|
@ -551,6 +204,45 @@ private:
|
|||
ColourSelector* ledColourSelector = nullptr;
|
||||
};
|
||||
|
||||
void setupControls();
|
||||
void distributeControls();
|
||||
|
||||
struct ParamsView : public Component
|
||||
{
|
||||
ParamsView()
|
||||
{
|
||||
// For now, to be able to dismiss mobile keyboard.
|
||||
setWantsKeyboardFocus (true);
|
||||
}
|
||||
|
||||
void addRowComponent (RowComponent *rc)
|
||||
{
|
||||
rowComponents.add (rc);
|
||||
addAndMakeVisible (rc);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
int totalRowUnits = 0;
|
||||
|
||||
for (const auto &rc : rowComponents)
|
||||
totalRowUnits += rc->rowUnits;
|
||||
|
||||
const int rowHeight = getHeight() / totalRowUnits;
|
||||
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
for (auto &rc : rowComponents)
|
||||
rc->setBounds (bounds.removeFromTop (rc->rowUnits * rowHeight));
|
||||
|
||||
auto* last = rowComponents[rowComponents.size() - 1];
|
||||
last->setBounds (last->getBounds().withHeight (getHeight() - last->getY()));
|
||||
}
|
||||
|
||||
private:
|
||||
OwnedArray<RowComponent> rowComponents;
|
||||
};
|
||||
|
||||
struct AuxActionsView : public Component
|
||||
{
|
||||
AuxActionsView()
|
||||
|
|
@ -559,7 +251,7 @@ private:
|
|||
addAndMakeVisible (removeDeliveredNotifWithIdButton);
|
||||
addAndMakeVisible (deliveredNotifIdentifier);
|
||||
addAndMakeVisible (removeAllDeliveredNotifsButton);
|
||||
#if JUCE_IOS
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
addAndMakeVisible (getPendingNotificationsButton);
|
||||
addAndMakeVisible (removePendingNotifWithIdButton);
|
||||
addAndMakeVisible (pendingNotifIdentifier);
|
||||
|
|
@ -586,7 +278,7 @@ private:
|
|||
|
||||
removeAllDeliveredNotifsButton .setBounds (bounds.removeFromTop (rowHeight));
|
||||
|
||||
#if JUCE_IOS
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
getPendingNotificationsButton .setBounds (bounds.removeFromTop (rowHeight));
|
||||
|
||||
rowBounds = bounds.removeFromTop (rowHeight);
|
||||
|
|
@ -601,12 +293,10 @@ private:
|
|||
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
|
||||
|
|
@ -641,15 +331,50 @@ private:
|
|||
TextButton unsubscribeFromSportsButton { "UnsubscribeFromSports" };
|
||||
};
|
||||
|
||||
struct DemoTabbedComponent : public TabbedComponent
|
||||
{
|
||||
explicit DemoTabbedComponent (TabbedButtonBar::Orientation orientation)
|
||||
: TabbedComponent (orientation)
|
||||
{
|
||||
}
|
||||
|
||||
void currentTabChanged (int, const String& newCurrentTabName) override
|
||||
{
|
||||
if (! showedRemoteInstructions && newCurrentTabName == "Remote")
|
||||
{
|
||||
MainContentComponent::showRemoteInstructions();
|
||||
|
||||
showedRemoteInstructions = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
bool showedRemoteInstructions = false;
|
||||
};
|
||||
|
||||
static void showRemoteInstructions()
|
||||
{
|
||||
#if JUCE_IOS || JUCE_MAC
|
||||
NativeMessageBox::showMessageBoxAsync (AlertWindow::InfoIcon,
|
||||
"Remote Notifications instructions",
|
||||
"In order to be able to test remote notifications "
|
||||
"ensure that the app is signed and that you register "
|
||||
"the bundle ID for remote notifications in "
|
||||
"Apple Developer Center.");
|
||||
#endif
|
||||
}
|
||||
|
||||
Label headerLabel { "headerLabel", "Push Notifications Demo" };
|
||||
RequiredParamsView requiredParamsView;
|
||||
OptionalParamsOneView optionalParamsOneView;
|
||||
OptionalParamsTwoView optionalParamsTwoView;
|
||||
OptionalParamsThreeView optionalParamsThreeView;
|
||||
ParamControls paramControls;
|
||||
ParamsView paramsOneView;
|
||||
ParamsView paramsTwoView;
|
||||
ParamsView paramsThreeView;
|
||||
ParamsView paramsFourView;
|
||||
AuxActionsView auxActionsView;
|
||||
TabbedComponent localNotificationsTabs { TabbedButtonBar::TabsAtTop };
|
||||
RemoteView remoteView;
|
||||
TabbedComponent mainTabs { TabbedButtonBar::TabsAtTop };
|
||||
DemoTabbedComponent mainTabs { TabbedButtonBar::TabsAtTop };
|
||||
TextButton sendButton { "Send!" };
|
||||
Label notAvailableYetLabel { "notAvailableYetLabel", "Push Notifications feature is not available on this platform yet!" };
|
||||
|
||||
|
|
|
|||
|
|
@ -249,9 +249,6 @@ public:
|
|||
props.add (new BooleanPropertyComponent (getBackgroundBleValue(), "Bluetooth MIDI background capability", "Enabled"),
|
||||
"Enable this to grant your app the capability to connect to Bluetooth LE devices when in background mode.");
|
||||
|
||||
props.add (new BooleanPropertyComponent (getPushNotificationsValue(), "Push Notifications capability", "Enabled"),
|
||||
"Enable this to grant your app the capability to receive push notifications.");
|
||||
|
||||
props.add (new BooleanPropertyComponent (getAppGroupsEnabledValue(), "App groups capability", "Enabled"),
|
||||
"Enable this to grant your app the capability to share resources between apps using the same app group ID.");
|
||||
|
||||
|
|
@ -259,6 +256,9 @@ public:
|
|||
"Enable this to grant your app the capability to use native file load/save browser windows on iOS.");
|
||||
}
|
||||
|
||||
props.add (new BooleanPropertyComponent (getPushNotificationsValue(), "Push Notifications capability", "Enabled"),
|
||||
"Enable this to grant your app the capability to receive push notifications.");
|
||||
|
||||
props.add (new TextPropertyComponent (getPListToMergeValue(), "Custom PList", 8192, true),
|
||||
"You can paste the contents of an XML PList file in here, and the settings that it contains will override any "
|
||||
"settings that the Projucer creates. BEWARE! When doing this, be careful to remove from the XML any "
|
||||
|
|
@ -860,7 +860,7 @@ public:
|
|||
&& type == Target::StandalonePlugIn
|
||||
&& owner.getProject().shouldEnableIAA()) ? 1 : 0;
|
||||
|
||||
auto pushNotificationsEnabled = (owner.iOS && owner.isPushNotificationsEnabled()) ? 1 : 0;
|
||||
auto pushNotificationsEnabled = owner.isPushNotificationsEnabled() ? 1 : 0;
|
||||
auto sandboxEnabled = (type == Target::AudioUnitv3PlugIn ? 1 : 0);
|
||||
|
||||
attributes << "SystemCapabilities = {";
|
||||
|
|
@ -1146,7 +1146,7 @@ public:
|
|||
if (owner.isInAppPurchasesEnabled())
|
||||
defines.set ("JUCE_IN_APP_PURCHASES", "1");
|
||||
|
||||
if (owner.iOS && owner.isPushNotificationsEnabled())
|
||||
if (owner.isPushNotificationsEnabled())
|
||||
defines.set ("JUCE_PUSH_NOTIFICATIONS", "1");
|
||||
|
||||
defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type));
|
||||
|
|
@ -2552,8 +2552,10 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
if (isiOS() && isPushNotificationsEnabled())
|
||||
entitlements.set ("aps-environment", "<string>development</string>");
|
||||
if (isPushNotificationsEnabled())
|
||||
entitlements.set (isiOS() ? "aps-environment"
|
||||
: "com.apple.developer.aps-environment",
|
||||
"<string>development</string>");
|
||||
}
|
||||
|
||||
if (isAppGroupsEnabled())
|
||||
|
|
|
|||
|
|
@ -67,6 +67,132 @@ static inline NSArray* createNSArrayFromStringArray (const StringArray& strings)
|
|||
return [array autorelease];
|
||||
}
|
||||
|
||||
static NSArray* varArrayToNSArray (const var& varToParse);
|
||||
|
||||
static NSDictionary* varObjectToNSDictionary (const var& varToParse)
|
||||
{
|
||||
auto* dictionary = [NSMutableDictionary dictionary];
|
||||
|
||||
if (varToParse.isObject())
|
||||
{
|
||||
auto* dynamicObject = varToParse.getDynamicObject();
|
||||
|
||||
auto& properties = dynamicObject->getProperties();
|
||||
|
||||
for (int i = 0; i < properties.size(); ++i)
|
||||
{
|
||||
auto* keyString = juceStringToNS (properties.getName (i).toString());
|
||||
|
||||
const var& valueVar = properties.getValueAt (i);
|
||||
|
||||
if (valueVar.isObject())
|
||||
{
|
||||
auto* valueDictionary = varObjectToNSDictionary (valueVar);
|
||||
|
||||
[dictionary setObject: valueDictionary forKey: keyString];
|
||||
}
|
||||
else if (valueVar.isArray())
|
||||
{
|
||||
auto* valueArray = varArrayToNSArray (valueVar);
|
||||
|
||||
[dictionary setObject: valueArray forKey: keyString];
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* valueString = juceStringToNS (valueVar.toString());
|
||||
|
||||
[dictionary setObject: valueString forKey: keyString];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
static NSArray* varArrayToNSArray (const var& varToParse)
|
||||
{
|
||||
jassert (varToParse.isArray());
|
||||
|
||||
if (! varToParse.isArray())
|
||||
return nil;
|
||||
|
||||
const auto* varArray = varToParse.getArray();
|
||||
|
||||
auto* array = [NSMutableArray arrayWithCapacity: (NSUInteger) varArray->size()];
|
||||
|
||||
for (const auto& aVar : *varArray)
|
||||
{
|
||||
if (aVar.isObject())
|
||||
{
|
||||
auto* valueDictionary = varObjectToNSDictionary (aVar);
|
||||
|
||||
[array addObject: valueDictionary];
|
||||
}
|
||||
else if (aVar.isArray())
|
||||
{
|
||||
auto* valueArray = varArrayToNSArray (aVar);
|
||||
|
||||
[array addObject: valueArray];
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* valueString = juceStringToNS (aVar.toString());
|
||||
|
||||
[array addObject: valueString];
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
static var nsArrayToVar (NSArray* array);
|
||||
|
||||
static var nsDictionaryToVar (NSDictionary* dictionary)
|
||||
{
|
||||
DynamicObject::Ptr dynamicObject = new DynamicObject();
|
||||
|
||||
for (NSString* key in dictionary)
|
||||
{
|
||||
const auto keyString = nsStringToJuce (key);
|
||||
|
||||
id value = dictionary[key];
|
||||
|
||||
if ([value isKindOfClass: [NSString class]])
|
||||
dynamicObject->setProperty (keyString, nsStringToJuce ((NSString*) value));
|
||||
else if ([value isKindOfClass: [NSNumber class]])
|
||||
dynamicObject->setProperty (keyString, nsStringToJuce ([(NSNumber*) value stringValue]));
|
||||
else if ([value isKindOfClass: [NSDictionary class]])
|
||||
dynamicObject->setProperty (keyString, nsDictionaryToVar ((NSDictionary*) value));
|
||||
else if ([value isKindOfClass: [NSArray class]])
|
||||
dynamicObject->setProperty (keyString, nsArrayToVar ((NSArray*) value));
|
||||
else
|
||||
jassertfalse; // Unsupported yet, add here!
|
||||
}
|
||||
|
||||
return var (dynamicObject.get());
|
||||
}
|
||||
|
||||
static var nsArrayToVar (NSArray* array)
|
||||
{
|
||||
Array<var> resultArray;
|
||||
|
||||
for (id value in array)
|
||||
{
|
||||
if ([value isKindOfClass: [NSString class]])
|
||||
resultArray.add (var (nsStringToJuce ((NSString*) value)));
|
||||
else if ([value isKindOfClass: [NSNumber class]])
|
||||
resultArray.add (var (nsStringToJuce ([(NSNumber*) value stringValue])));
|
||||
else if ([value isKindOfClass: [NSDictionary class]])
|
||||
resultArray.add (nsDictionaryToVar ((NSDictionary*) value));
|
||||
else if ([value isKindOfClass: [NSArray class]])
|
||||
resultArray.add (nsArrayToVar ((NSArray*) value));
|
||||
else
|
||||
jassertfalse; // Unsupported yet, add here!
|
||||
}
|
||||
|
||||
return var (resultArray);
|
||||
}
|
||||
|
||||
#if JUCE_MAC
|
||||
template <typename RectangleType>
|
||||
static NSRect makeNSRect (const RectangleType& r) noexcept
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ private:
|
|||
{
|
||||
AppDelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_")
|
||||
{
|
||||
addMethod (@selector (applicationWillFinishLaunching:), applicationWillFinishLaunching, "v@:@@");
|
||||
addMethod (@selector (applicationWillFinishLaunching:), applicationWillFinishLaunching, "v@:@");
|
||||
addMethod (@selector (getUrl:withReplyEvent:), getUrl_withReplyEvent, "v@:@@");
|
||||
addMethod (@selector (applicationShouldTerminate:), applicationShouldTerminate, "I@:@");
|
||||
addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@");
|
||||
|
|
@ -116,11 +116,22 @@ private:
|
|||
addMethod (@selector (mainMenuTrackingEnded:), mainMenuTrackingEnded, "v@:@");
|
||||
addMethod (@selector (dummyMethod), dummyMethod, "v@:");
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
//==============================================================================
|
||||
addIvar<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>*> ("pushNotificationsDelegate");
|
||||
|
||||
addMethod (@selector (applicationDidFinishLaunching:), applicationDidFinishLaunching, "v@:@");
|
||||
addMethod (@selector (setPushNotificationsDelegate:), setPushNotificationsDelegate, "v@:@");
|
||||
addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), registeredForRemoteNotifications, "v@:@@");
|
||||
addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), failedToRegisterForRemoteNotifications, "v@:@@");
|
||||
addMethod (@selector (application:didReceiveRemoteNotification:), didReceiveRemoteNotification, "v@:@@");
|
||||
#endif
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
private:
|
||||
static void applicationWillFinishLaunching (id self, SEL, NSApplication*, NSNotification*)
|
||||
static void applicationWillFinishLaunching (id self, SEL, NSNotification*)
|
||||
{
|
||||
[[NSAppleEventManager sharedAppleEventManager] setEventHandler: self
|
||||
andSelector: @selector (getUrl:withReplyEvent:)
|
||||
|
|
@ -128,6 +139,19 @@ private:
|
|||
andEventID: kAEGetURL];
|
||||
}
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
static void applicationDidFinishLaunching (id self, SEL, NSNotification* notification)
|
||||
{
|
||||
if (notification.userInfo != nil)
|
||||
{
|
||||
NSUserNotification* userNotification = [notification.userInfo objectForKey: nsStringLiteral ("NSApplicationLaunchUserNotificationKey")];
|
||||
|
||||
if (userNotification != nil && userNotification.userInfo != nil)
|
||||
didReceiveRemoteNotification (self, nil, [NSApplication sharedApplication], userNotification.userInfo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static NSApplicationTerminateReply applicationShouldTerminate (id /*self*/, SEL, NSApplication*)
|
||||
{
|
||||
if (auto* app = JUCEApplicationBase::getInstance())
|
||||
|
|
@ -216,6 +240,73 @@ private:
|
|||
|
||||
return s;
|
||||
}
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
//==============================================================================
|
||||
static void setPushNotificationsDelegate (id self, SEL, NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>* delegate)
|
||||
{
|
||||
object_setInstanceVariable (self, "pushNotificationsDelegate", delegate);
|
||||
}
|
||||
|
||||
static NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>* getPushNotificationsDelegate (id self)
|
||||
{
|
||||
return getIvar<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>*> (self, "pushNotificationsDelegate");
|
||||
}
|
||||
|
||||
static void registeredForRemoteNotifications (id self, SEL, NSApplication* application, NSData* deviceToken)
|
||||
{
|
||||
auto* delegate = getPushNotificationsDelegate (self);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didRegisterForRemoteNotificationsWithDeviceToken:");
|
||||
|
||||
if (delegate != nil && [delegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: delegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &deviceToken atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
static void failedToRegisterForRemoteNotifications (id self, SEL, NSApplication* application, NSError* error)
|
||||
{
|
||||
auto* delegate = getPushNotificationsDelegate (self);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didFailToRegisterForRemoteNotificationsWithError:");
|
||||
|
||||
if (delegate != nil && [delegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: delegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &error atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
|
||||
static void didReceiveRemoteNotification (id self, SEL, NSApplication* application, NSDictionary* userInfo)
|
||||
{
|
||||
auto* delegate = getPushNotificationsDelegate (self);
|
||||
|
||||
SEL selector = NSSelectorFromString (@"application:didReceiveRemoteNotification:");
|
||||
|
||||
if (delegate != nil && [delegate respondsToSelector: selector])
|
||||
{
|
||||
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [delegate methodSignatureForSelector: selector]];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: delegate];
|
||||
[invocation setArgument: &application atIndex:2];
|
||||
[invocation setArgument: &userInfo atIndex:3];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@
|
|||
#import <IOKit/hid/IOHIDKeys.h>
|
||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
#import <Foundation/NSUserNotification.h>
|
||||
|
||||
#include "native/juce_mac_PushNotifications.cpp"
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_IOS
|
||||
#if JUCE_PUSH_NOTIFICATIONS
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace juce
|
|||
{
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_ANDROID && ! JUCE_IOS
|
||||
#if ! JUCE_ANDROID && ! JUCE_IOS && ! JUCE_MAC
|
||||
bool PushNotifications::Notification::isValid() const noexcept { return true; }
|
||||
#endif
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ void PushNotifications::removeListener (Listener* l) { listeners.remove (l); }
|
|||
|
||||
void PushNotifications::requestPermissionsWithSettings (const PushNotifications::Settings& settings)
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS && JUCE_IOS
|
||||
#if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
|
||||
pimpl->requestPermissionsWithSettings (settings);
|
||||
#else
|
||||
ignoreUnused (settings);
|
||||
|
|
@ -59,7 +59,7 @@ void PushNotifications::requestPermissionsWithSettings (const PushNotifications:
|
|||
|
||||
void PushNotifications::requestSettingsUsed()
|
||||
{
|
||||
#if JUCE_PUSH_NOTIFICATIONS && JUCE_IOS
|
||||
#if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
|
||||
pimpl->requestSettingsUsed();
|
||||
#else
|
||||
listeners.call (&PushNotifications::Listener::notificationSettingsReceived, {});
|
||||
|
|
|
|||
|
|
@ -124,6 +124,14 @@ public:
|
|||
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 OSX, set the URL to the name of a sound file (preferably without
|
||||
an extension) and place the sound file directly in bundle's "Resources" directory (you
|
||||
can use "Xcode Resource" tickbox in Projucer to achieve that), i.e. it cannot be in a
|
||||
subdirectory of "Resources" like "Resources/sound". Alternatively, if a sound file
|
||||
cannot be found in bundle's "Resources" directory, the OS may look for the sound in the
|
||||
following paths: "~/Library/Sounds", "/Library/Sounds", "/Network/Library/Sounds",
|
||||
"/System/Library/Sounds".
|
||||
|
||||
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".
|
||||
|
|
@ -312,7 +320,11 @@ public:
|
|||
|
||||
//==========================================================================
|
||||
/** Describes settings we want to use for current device. Note that at the
|
||||
moment this is only used on iOS.
|
||||
moment this is only used on iOS and partially on OSX.
|
||||
|
||||
On OSX only allow* flags are used and they control remote notifications only.
|
||||
To control sound, alert and badge settings for local notifications on OSX,
|
||||
use Notifications settings in System Preferences.
|
||||
|
||||
To setup push notifications for current device, provide permissions required,
|
||||
as well as register categories of notifications you want to support. Each
|
||||
|
|
@ -411,9 +423,13 @@ public:
|
|||
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().
|
||||
Note that settings are currently only used on iOS and partially on OSX.
|
||||
|
||||
On OSX, only allow* flags are used and they refer to remote notifications only. For
|
||||
local notifications, refer to System Preferences.
|
||||
|
||||
When calling this function on other platforms, Settings with no categories and all allow*
|
||||
flags set to true will be received in Listener::notificationSettingsReceived().
|
||||
*/
|
||||
void requestSettingsUsed();
|
||||
|
||||
|
|
@ -486,7 +502,7 @@ public:
|
|||
|
||||
//==========================================================================
|
||||
/** Checks whether notifications are enabled for given application.
|
||||
On iOS this will always return true, use requestSettingsUsed() instead.
|
||||
On iOS and OSX this will always return true, use requestSettingsUsed() instead.
|
||||
*/
|
||||
bool areNotificationsEnabled() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,84 +34,6 @@ template <> struct ContainerDeletePolicy<NSObject<UIApplicationDelegate, UNUserN
|
|||
namespace PushNotificationsDelegateDetails
|
||||
{
|
||||
//==============================================================================
|
||||
NSArray* varArrayToNSArray (const var& varToParse);
|
||||
|
||||
NSDictionary* varObjectToNSDictionary (const var& varToParse)
|
||||
{
|
||||
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
|
||||
|
||||
if (varToParse.isObject())
|
||||
{
|
||||
auto* dynamicObject = varToParse.getDynamicObject();
|
||||
|
||||
auto& properties = dynamicObject->getProperties();
|
||||
|
||||
for (int i = 0; i < properties.size(); ++i)
|
||||
{
|
||||
NSString* keyString = juceStringToNS (properties.getName (i).toString());
|
||||
|
||||
const var& valueVar = properties.getValueAt (i);
|
||||
|
||||
if (valueVar.isObject())
|
||||
{
|
||||
NSDictionary* valueDictionary = varObjectToNSDictionary (valueVar);
|
||||
|
||||
[dictionary setObject: valueDictionary forKey: keyString];
|
||||
}
|
||||
else if (valueVar.isArray())
|
||||
{
|
||||
NSArray* valueArray = varArrayToNSArray (valueVar);
|
||||
|
||||
[dictionary setObject: valueArray forKey: keyString];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* valueString = juceStringToNS (valueVar.toString());
|
||||
|
||||
[dictionary setObject: valueString forKey: keyString];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
NSArray* varArrayToNSArray (const var& varToParse)
|
||||
{
|
||||
jassert (varToParse.isArray());
|
||||
|
||||
if (! varToParse.isArray())
|
||||
return nil;
|
||||
|
||||
const auto* varArray = varToParse.getArray();
|
||||
|
||||
NSMutableArray* array = [NSMutableArray arrayWithCapacity: (NSUInteger) varArray->size()];
|
||||
|
||||
for (const auto& aVar : *varArray)
|
||||
{
|
||||
if (aVar.isObject())
|
||||
{
|
||||
NSDictionary* valueDictionary = varObjectToNSDictionary (aVar);
|
||||
|
||||
[array addObject: valueDictionary];
|
||||
}
|
||||
else if (aVar.isArray())
|
||||
{
|
||||
NSArray* valueArray = varArrayToNSArray (aVar);
|
||||
|
||||
[array addObject: valueArray];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* valueString = juceStringToNS (aVar.toString());
|
||||
|
||||
[array addObject: valueString];
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
using Action = PushNotifications::Settings::Action;
|
||||
using Category = PushNotifications::Settings::Category;
|
||||
|
||||
|
|
@ -210,7 +132,7 @@ namespace PushNotificationsDelegateDetails
|
|||
|
||||
auto triggerTime = Time::getCurrentTime() + RelativeTime (n.triggerIntervalSec);
|
||||
notification.fireDate = [NSDate dateWithTimeIntervalSince1970: triggerTime.toMilliseconds() / 1000.];
|
||||
notification.userInfo = PushNotificationsDelegateDetails::varObjectToNSDictionary (n.properties);
|
||||
notification.userInfo = varObjectToNSDictionary (n.properties);
|
||||
|
||||
auto soundToPlayString = n.soundToPlay.toString (true);
|
||||
|
||||
|
|
@ -242,7 +164,7 @@ namespace PushNotificationsDelegateDetails
|
|||
else if (soundToPlayString.isNotEmpty())
|
||||
content.sound = [UNNotificationSound soundNamed: juceStringToNS (soundToPlayString)];
|
||||
|
||||
NSMutableDictionary* propsDict = (NSMutableDictionary*) PushNotificationsDelegateDetails::varObjectToNSDictionary (n.properties);
|
||||
NSMutableDictionary* propsDict = (NSMutableDictionary*) varObjectToNSDictionary (n.properties);
|
||||
[propsDict setObject: juceStringToNS (soundToPlayString) forKey: nsStringLiteral ("com.juce.soundName")];
|
||||
content.userInfo = propsDict;
|
||||
|
||||
|
|
@ -268,54 +190,6 @@ namespace PushNotificationsDelegateDetails
|
|||
}
|
||||
#endif
|
||||
|
||||
var nsArrayToVar (NSArray* array);
|
||||
|
||||
var nsDictionaryToVar (NSDictionary* dictionary)
|
||||
{
|
||||
DynamicObject::Ptr dynamicObject = new DynamicObject();
|
||||
|
||||
for (NSString* key in dictionary)
|
||||
{
|
||||
const auto keyString = nsStringToJuce (key);
|
||||
|
||||
id value = dictionary[key];
|
||||
|
||||
if ([value isKindOfClass: [NSString class]])
|
||||
dynamicObject->setProperty (keyString, nsStringToJuce ((NSString*) value));
|
||||
else if ([value isKindOfClass: [NSNumber class]])
|
||||
dynamicObject->setProperty (keyString, nsStringToJuce ([(NSNumber*) value stringValue]));
|
||||
else if ([value isKindOfClass: [NSDictionary class]])
|
||||
dynamicObject->setProperty (keyString, nsDictionaryToVar ((NSDictionary*) value));
|
||||
else if ([value isKindOfClass: [NSArray class]])
|
||||
dynamicObject->setProperty (keyString, nsArrayToVar ((NSArray*) value));
|
||||
else
|
||||
jassertfalse; // Unsupported yet, add here!
|
||||
}
|
||||
|
||||
return var (dynamicObject);
|
||||
}
|
||||
|
||||
var nsArrayToVar (NSArray* array)
|
||||
{
|
||||
Array<var> resultArray;
|
||||
|
||||
for (id value in array)
|
||||
{
|
||||
if ([value isKindOfClass: [NSString class]])
|
||||
resultArray.add (var (nsStringToJuce ((NSString*) value)));
|
||||
else if ([value isKindOfClass: [NSNumber class]])
|
||||
resultArray.add (var (nsStringToJuce ([(NSNumber*) value stringValue])));
|
||||
else if ([value isKindOfClass: [NSDictionary class]])
|
||||
resultArray.add (nsDictionaryToVar ((NSDictionary*) value));
|
||||
else if ([value isKindOfClass: [NSArray class]])
|
||||
resultArray.add (nsArrayToVar ((NSArray*) value));
|
||||
else
|
||||
jassertfalse; // Unsupported yet, add here!
|
||||
}
|
||||
|
||||
return var (resultArray);
|
||||
}
|
||||
|
||||
String getUserResponseFromNSDictionary (NSDictionary* dictionary)
|
||||
{
|
||||
if (dictionary == nil || dictionary.count == 0)
|
||||
|
|
@ -397,7 +271,7 @@ namespace PushNotificationsDelegateDetails
|
|||
n.category = nsStringToJuce (r.content.categoryIdentifier);
|
||||
n.badgeNumber = r.content.badge.intValue;
|
||||
|
||||
auto userInfoVar = PushNotificationsDelegateDetails::nsDictionaryToVar (r.content.userInfo);
|
||||
auto userInfoVar = nsDictionaryToVar (r.content.userInfo);
|
||||
|
||||
if (auto* object = userInfoVar.getDynamicObject())
|
||||
{
|
||||
|
|
@ -755,8 +629,6 @@ struct PushNotifications::Pimpl : private PushNotificationsDelegate
|
|||
#endif
|
||||
|
||||
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void requestSettingsUsed()
|
||||
|
|
@ -980,6 +852,8 @@ struct PushNotifications::Pimpl : private PushNotificationsDelegate
|
|||
|
||||
deviceToken = nsStringToJuce (deviceTokenString);
|
||||
|
||||
initialised = true;
|
||||
|
||||
owner.listeners.call (&PushNotifications::Listener::deviceTokenRefreshed, deviceToken);
|
||||
}
|
||||
|
||||
|
|
|
|||
557
modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp
Normal file
557
modules/juce_gui_extra/native/juce_mac_PushNotifications.cpp
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
template <> struct ContainerDeletePolicy<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>> { static void destroy (NSObject* o) { [o release]; } };
|
||||
|
||||
namespace PushNotificationsDelegateDetailsOsx
|
||||
{
|
||||
using Action = PushNotifications::Notification::Action;
|
||||
|
||||
//==============================================================================
|
||||
NSUserNotification* juceNotificationToNSUserNotification (const PushNotifications::Notification& n,
|
||||
bool isEarlierThanMavericks,
|
||||
bool isEarlierThanYosemite)
|
||||
{
|
||||
auto* notification = [[NSUserNotification alloc] init];
|
||||
|
||||
notification.title = juceStringToNS (n.title);
|
||||
notification.subtitle = juceStringToNS (n.subtitle);
|
||||
notification.informativeText = juceStringToNS (n.body);
|
||||
notification.userInfo = varObjectToNSDictionary (n.properties);
|
||||
|
||||
auto triggerTime = Time::getCurrentTime() + RelativeTime (n.triggerIntervalSec);
|
||||
notification.deliveryDate = [NSDate dateWithTimeIntervalSince1970: triggerTime.toMilliseconds() / 1000.];
|
||||
|
||||
if (n.repeat && n.triggerIntervalSec >= 60)
|
||||
{
|
||||
auto* dateComponents = [[NSDateComponents alloc] init];
|
||||
auto intervalSec = NSInteger (n.triggerIntervalSec);
|
||||
dateComponents.second = intervalSec;
|
||||
dateComponents.nanosecond = NSInteger ((n.triggerIntervalSec - intervalSec) * 1000000000);
|
||||
|
||||
notification.deliveryRepeatInterval = dateComponents;
|
||||
|
||||
[dateComponents autorelease];
|
||||
}
|
||||
|
||||
auto soundToPlayString = n.soundToPlay.toString (true);
|
||||
|
||||
if (soundToPlayString == "default_os_sound")
|
||||
{
|
||||
notification.soundName = NSUserNotificationDefaultSoundName;
|
||||
}
|
||||
else if (soundToPlayString.isNotEmpty())
|
||||
{
|
||||
auto* soundName = juceStringToNS (soundToPlayString.fromLastOccurrenceOf ("/", false, false)
|
||||
.upToLastOccurrenceOf (".", false, false));
|
||||
|
||||
notification.soundName = soundName;
|
||||
}
|
||||
|
||||
notification.hasActionButton = n.actions.size() > 0;
|
||||
|
||||
if (n.actions.size() > 0)
|
||||
notification.actionButtonTitle = juceStringToNS (n.actions.getReference (0).title);
|
||||
|
||||
if (! isEarlierThanMavericks)
|
||||
{
|
||||
notification.identifier = juceStringToNS (n.identifier);
|
||||
|
||||
if (n.actions.size() > 0)
|
||||
{
|
||||
notification.hasReplyButton = n.actions.getReference (0).style == Action::text;
|
||||
notification.responsePlaceholder = juceStringToNS (n.actions.getReference (0).textInputPlaceholder);
|
||||
}
|
||||
|
||||
auto* imageDirectory = n.icon.contains ("/")
|
||||
? juceStringToNS (n.icon.upToLastOccurrenceOf ("/", false, true))
|
||||
: [NSString string];
|
||||
|
||||
auto* imageName = juceStringToNS (n.icon.fromLastOccurrenceOf ("/", false, false)
|
||||
.upToLastOccurrenceOf (".", false, false));
|
||||
auto* imageExtension = juceStringToNS (n.icon.fromLastOccurrenceOf (".", false, false));
|
||||
|
||||
NSString* imagePath = nil;
|
||||
|
||||
if ([imageDirectory length] == NSUInteger (0))
|
||||
{
|
||||
imagePath = [[NSBundle mainBundle] pathForResource: imageName
|
||||
ofType: imageExtension];
|
||||
}
|
||||
else
|
||||
{
|
||||
imagePath = [[NSBundle mainBundle] pathForResource: imageName
|
||||
ofType: imageExtension
|
||||
inDirectory: imageDirectory];
|
||||
}
|
||||
|
||||
notification.contentImage = [[NSImage alloc] initWithContentsOfFile: imagePath];
|
||||
|
||||
if (! isEarlierThanYosemite)
|
||||
{
|
||||
if (n.actions.size() > 1)
|
||||
{
|
||||
auto* additionalActions = [NSMutableArray arrayWithCapacity: (NSUInteger) n.actions.size() - 1];
|
||||
|
||||
for (int a = 1; a < n.actions.size(); ++a)
|
||||
[additionalActions addObject: [NSUserNotificationAction actionWithIdentifier: juceStringToNS (n.actions[a].identifier)
|
||||
title: juceStringToNS (n.actions[a].title)]];
|
||||
|
||||
notification.additionalActions = additionalActions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[notification autorelease];
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PushNotifications::Notification nsUserNotificationToJuceNotification (NSUserNotification* n,
|
||||
bool isEarlierThanMavericks,
|
||||
bool isEarlierThanYosemite)
|
||||
{
|
||||
PushNotifications::Notification notif;
|
||||
|
||||
notif.title = nsStringToJuce (n.title);
|
||||
notif.subtitle = nsStringToJuce (n.subtitle);
|
||||
notif.body = nsStringToJuce (n.informativeText);
|
||||
|
||||
notif.repeat = n.deliveryRepeatInterval != nil;
|
||||
|
||||
if (n.deliveryRepeatInterval != nil)
|
||||
{
|
||||
notif.triggerIntervalSec = n.deliveryRepeatInterval.second + (n.deliveryRepeatInterval.nanosecond / 1000000000.);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDate* dateNow = [NSDate date];
|
||||
notif.triggerIntervalSec = [dateNow timeIntervalSinceDate: n.deliveryDate];
|
||||
}
|
||||
|
||||
notif.soundToPlay = URL (nsStringToJuce (n.soundName));
|
||||
notif.properties = nsDictionaryToVar (n.userInfo);
|
||||
|
||||
if (! isEarlierThanMavericks)
|
||||
{
|
||||
notif.identifier = nsStringToJuce (n.identifier);
|
||||
|
||||
if (n.contentImage != nil)
|
||||
notif.icon = nsStringToJuce ([n.contentImage name]);
|
||||
}
|
||||
|
||||
Array<Action> actions;
|
||||
|
||||
if (n.actionButtonTitle != nil)
|
||||
{
|
||||
Action action;
|
||||
action.title = nsStringToJuce (n.actionButtonTitle);
|
||||
|
||||
if (! isEarlierThanMavericks)
|
||||
{
|
||||
if (n.hasReplyButton)
|
||||
action.style = Action::text;
|
||||
|
||||
if (n.responsePlaceholder != nil)
|
||||
action.textInputPlaceholder = nsStringToJuce (n.responsePlaceholder);
|
||||
}
|
||||
|
||||
actions.add (action);
|
||||
}
|
||||
|
||||
if (! isEarlierThanYosemite)
|
||||
{
|
||||
if (n.additionalActions != nil)
|
||||
{
|
||||
for (NSUserNotificationAction* a in n.additionalActions)
|
||||
{
|
||||
Action action;
|
||||
action.identifier = nsStringToJuce (a.identifier);
|
||||
action.title = nsStringToJuce (a.title);
|
||||
|
||||
actions.add (action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return notif;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
var getNotificationPropertiesFromDictionaryVar (const var& dictionaryVar)
|
||||
{
|
||||
auto* dictionaryVarObject = dictionaryVar.getDynamicObject();
|
||||
|
||||
if (dictionaryVarObject == nullptr)
|
||||
return {};
|
||||
|
||||
const auto& properties = dictionaryVarObject->getProperties();
|
||||
|
||||
DynamicObject::Ptr propsVarObject = new DynamicObject();
|
||||
|
||||
for (int i = 0; i < properties.size(); ++i)
|
||||
{
|
||||
auto propertyName = properties.getName (i).toString();
|
||||
|
||||
if (propertyName == "aps")
|
||||
continue;
|
||||
|
||||
propsVarObject->setProperty (propertyName, properties.getValueAt (i));
|
||||
}
|
||||
|
||||
return var (propsVarObject.get());
|
||||
}
|
||||
|
||||
PushNotifications::Notification nsDictionaryToJuceNotification (NSDictionary* dictionary)
|
||||
{
|
||||
const var dictionaryVar = nsDictionaryToVar (dictionary);
|
||||
|
||||
const var apsVar = dictionaryVar.getProperty ("aps", {});
|
||||
|
||||
if (! apsVar.isObject())
|
||||
return {};
|
||||
|
||||
var alertVar = apsVar.getProperty ("alert", {});
|
||||
|
||||
const var titleVar = alertVar.getProperty ("title", {});
|
||||
const var bodyVar = alertVar.isObject() ? alertVar.getProperty ("body", {}) : alertVar;
|
||||
|
||||
const var categoryVar = apsVar.getProperty ("category", {});
|
||||
const var soundVar = apsVar.getProperty ("sound", {});
|
||||
const var badgeVar = apsVar.getProperty ("badge", {});
|
||||
const var threadIdVar = apsVar.getProperty ("thread-id", {});
|
||||
|
||||
PushNotifications::Notification notification;
|
||||
|
||||
notification.title = titleVar .toString();
|
||||
notification.body = bodyVar .toString();
|
||||
notification.groupId = threadIdVar.toString();
|
||||
notification.category = categoryVar.toString();
|
||||
notification.soundToPlay = URL (soundVar.toString());
|
||||
notification.badgeNumber = (int) badgeVar;
|
||||
notification.properties = getNotificationPropertiesFromDictionaryVar (dictionaryVar);
|
||||
|
||||
return notification;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct PushNotificationsDelegate
|
||||
{
|
||||
PushNotificationsDelegate() : delegate ([getClass().createInstance() init])
|
||||
{
|
||||
Class::setThis (delegate, this);
|
||||
|
||||
id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
|
||||
|
||||
SEL selector = NSSelectorFromString (@"setPushNotificationsDelegate:");
|
||||
|
||||
if ([appDelegate respondsToSelector: selector])
|
||||
[appDelegate performSelector: selector withObject: delegate];
|
||||
|
||||
[NSUserNotificationCenter defaultUserNotificationCenter].delegate = delegate;
|
||||
}
|
||||
|
||||
virtual ~PushNotificationsDelegate()
|
||||
{
|
||||
[NSUserNotificationCenter defaultUserNotificationCenter].delegate = nil;
|
||||
}
|
||||
|
||||
virtual void registeredForRemoteNotifications (NSData* deviceToken) = 0;
|
||||
|
||||
virtual void failedToRegisterForRemoteNotifications (NSError* error) = 0;
|
||||
|
||||
virtual void didReceiveRemoteNotification (NSDictionary* userInfo) = 0;
|
||||
|
||||
virtual void didDeliverNotification (NSUserNotification* notification) = 0;
|
||||
|
||||
virtual void didActivateNotification (NSUserNotification* notification) = 0;
|
||||
|
||||
virtual bool shouldPresentNotification (NSUserNotification* notification) = 0;
|
||||
|
||||
protected:
|
||||
ScopedPointer<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>> delegate;
|
||||
|
||||
private:
|
||||
struct Class : public ObjCClass<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>>
|
||||
{
|
||||
Class() : ObjCClass<NSObject<NSApplicationDelegate, NSUserNotificationCenterDelegate>> ("JucePushNotificationsDelegate_")
|
||||
{
|
||||
addIvar<PushNotificationsDelegate*> ("self");
|
||||
|
||||
addMethod (@selector (application:didRegisterForRemoteNotificationsWithDeviceToken:), registeredForRemoteNotifications, "v@:@@");
|
||||
addMethod (@selector (application:didFailToRegisterForRemoteNotificationsWithError:), failedToRegisterForRemoteNotifications, "v@:@@");
|
||||
addMethod (@selector (application:didReceiveRemoteNotification:), didReceiveRemoteNotification, "v@:@@");
|
||||
addMethod (@selector (userNotificationCenter:didDeliverNotification:), didDeliverNotification, "v@:@@");
|
||||
addMethod (@selector (userNotificationCenter:didActivateNotification:), didActivateNotification, "v@:@@");
|
||||
addMethod (@selector (userNotificationCenter:shouldPresentNotification:), shouldPresentNotification, "B@:@@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static PushNotificationsDelegate& getThis (id self) { return *getIvar<PushNotificationsDelegate*> (self, "self"); }
|
||||
static void setThis (id self, PushNotificationsDelegate* d) { object_setInstanceVariable (self, "self", d); }
|
||||
|
||||
//==============================================================================
|
||||
static void registeredForRemoteNotifications (id self, SEL, NSApplication*,
|
||||
NSData* deviceToken) { getThis (self).registeredForRemoteNotifications (deviceToken); }
|
||||
|
||||
static void failedToRegisterForRemoteNotifications (id self, SEL, NSApplication*,
|
||||
NSError* error) { getThis (self).failedToRegisterForRemoteNotifications (error); }
|
||||
|
||||
static void didReceiveRemoteNotification (id self, SEL, NSApplication*,
|
||||
NSDictionary* userInfo) { getThis (self).didReceiveRemoteNotification (userInfo); }
|
||||
|
||||
static void didDeliverNotification (id self, SEL, NSUserNotificationCenter*,
|
||||
NSUserNotification* notification) { getThis (self).didDeliverNotification (notification); }
|
||||
|
||||
static void didActivateNotification (id self, SEL, NSUserNotificationCenter*,
|
||||
NSUserNotification* notification) { getThis (self).didActivateNotification (notification); }
|
||||
|
||||
static bool shouldPresentNotification (id self, SEL, NSUserNotificationCenter*,
|
||||
NSUserNotification* notification) { return getThis (self).shouldPresentNotification (notification); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static Class& getClass()
|
||||
{
|
||||
static Class c;
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool PushNotifications::Notification::isValid() const noexcept { return true; }
|
||||
|
||||
//==============================================================================
|
||||
struct PushNotifications::Pimpl : private PushNotificationsDelegate
|
||||
{
|
||||
Pimpl (PushNotifications& p)
|
||||
: owner (p)
|
||||
{
|
||||
}
|
||||
|
||||
void requestPermissionsWithSettings (const PushNotifications::Settings& settingsToUse)
|
||||
{
|
||||
if (isEarlierThanLion)
|
||||
return;
|
||||
|
||||
settings = settingsToUse;
|
||||
|
||||
NSRemoteNotificationType types = NSUInteger ((bool) settings.allowBadge);
|
||||
|
||||
if (isAtLeastMountainLion)
|
||||
types |= ((bool) settings.allowSound << 1 | (bool) settings.allowAlert << 2);
|
||||
|
||||
[[NSApplication sharedApplication] registerForRemoteNotificationTypes: types];
|
||||
}
|
||||
|
||||
void requestSettingsUsed()
|
||||
{
|
||||
if (isEarlierThanLion)
|
||||
{
|
||||
// no settings available
|
||||
owner.listeners.call (&PushNotifications::Listener::notificationSettingsReceived, {});
|
||||
return;
|
||||
}
|
||||
|
||||
settings.allowBadge = [NSApplication sharedApplication].enabledRemoteNotificationTypes & NSRemoteNotificationTypeBadge;
|
||||
|
||||
if (isAtLeastMountainLion)
|
||||
{
|
||||
settings.allowSound = [NSApplication sharedApplication].enabledRemoteNotificationTypes & NSRemoteNotificationTypeSound;
|
||||
settings.allowAlert = [NSApplication sharedApplication].enabledRemoteNotificationTypes & NSRemoteNotificationTypeAlert;
|
||||
}
|
||||
|
||||
owner.listeners.call (&PushNotifications::Listener::notificationSettingsReceived, settings);
|
||||
}
|
||||
|
||||
bool areNotificationsEnabled() const { return true; }
|
||||
|
||||
void sendLocalNotification (const Notification& n)
|
||||
{
|
||||
auto* notification = PushNotificationsDelegateDetailsOsx::juceNotificationToNSUserNotification (n, isEarlierThanMavericks, isEarlierThanYosemite);
|
||||
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] scheduleNotification: notification];
|
||||
}
|
||||
|
||||
void getDeliveredNotifications() const
|
||||
{
|
||||
Array<PushNotifications::Notification> notifs;
|
||||
|
||||
for (NSUserNotification* n in [NSUserNotificationCenter defaultUserNotificationCenter].deliveredNotifications)
|
||||
notifs.add (PushNotificationsDelegateDetailsOsx::nsUserNotificationToJuceNotification (n, isEarlierThanMavericks, isEarlierThanYosemite));
|
||||
|
||||
owner.listeners.call (&Listener::deliveredNotificationsListReceived, notifs);
|
||||
}
|
||||
|
||||
void removeAllDeliveredNotifications()
|
||||
{
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications];
|
||||
}
|
||||
|
||||
void removeDeliveredNotification (const String& identifier)
|
||||
{
|
||||
PushNotifications::Notification n;
|
||||
n.identifier = identifier;
|
||||
|
||||
auto nsNotification = PushNotificationsDelegateDetailsOsx::juceNotificationToNSUserNotification (n, isEarlierThanMavericks, isEarlierThanYosemite);
|
||||
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification: nsNotification];
|
||||
}
|
||||
|
||||
void setupChannels (const Array<ChannelGroup>& groups, const Array<Channel>& channels)
|
||||
{
|
||||
ignoreUnused (groups, channels);
|
||||
}
|
||||
|
||||
void getPendingLocalNotifications() const
|
||||
{
|
||||
Array<PushNotifications::Notification> notifs;
|
||||
|
||||
for (NSUserNotification* n in [NSUserNotificationCenter defaultUserNotificationCenter].scheduledNotifications)
|
||||
notifs.add (PushNotificationsDelegateDetailsOsx::nsUserNotificationToJuceNotification (n, isEarlierThanMavericks, isEarlierThanYosemite));
|
||||
|
||||
owner.listeners.call (&PushNotifications::Listener::pendingLocalNotificationsListReceived, notifs);
|
||||
}
|
||||
|
||||
void removePendingLocalNotification (const String& identifier)
|
||||
{
|
||||
PushNotifications::Notification n;
|
||||
n.identifier = identifier;
|
||||
|
||||
auto nsNotification = PushNotificationsDelegateDetailsOsx::juceNotificationToNSUserNotification (n, isEarlierThanMavericks, isEarlierThanYosemite);
|
||||
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] removeScheduledNotification: nsNotification];
|
||||
}
|
||||
|
||||
void removeAllPendingLocalNotifications()
|
||||
{
|
||||
for (NSUserNotification* n in [NSUserNotificationCenter defaultUserNotificationCenter].scheduledNotifications)
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] removeScheduledNotification: n];
|
||||
}
|
||||
|
||||
String getDeviceToken()
|
||||
{
|
||||
// You need to call requestPermissionsWithSettings() first.
|
||||
jassert (initialised);
|
||||
|
||||
return deviceToken;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//PushNotificationsDelegate
|
||||
void registeredForRemoteNotifications (NSData* deviceTokenToUse) override
|
||||
{
|
||||
auto* deviceTokenString = [[[[deviceTokenToUse description]
|
||||
stringByReplacingOccurrencesOfString: nsStringLiteral ("<") withString: nsStringLiteral ("")]
|
||||
stringByReplacingOccurrencesOfString: nsStringLiteral (">") withString: nsStringLiteral ("")]
|
||||
stringByReplacingOccurrencesOfString: nsStringLiteral (" ") withString: nsStringLiteral ("")];
|
||||
|
||||
deviceToken = nsStringToJuce (deviceTokenString);
|
||||
|
||||
initialised = true;
|
||||
|
||||
owner.listeners.call (&PushNotifications::Listener::deviceTokenRefreshed, deviceToken);
|
||||
}
|
||||
|
||||
void failedToRegisterForRemoteNotifications (NSError* error) override
|
||||
{
|
||||
ignoreUnused (error);
|
||||
|
||||
deviceToken.clear();
|
||||
}
|
||||
|
||||
void didReceiveRemoteNotification (NSDictionary* userInfo) override
|
||||
{
|
||||
auto n = PushNotificationsDelegateDetailsOsx::nsDictionaryToJuceNotification (userInfo);
|
||||
|
||||
owner.listeners.call (&PushNotifications::Listener::handleNotification, true, n);
|
||||
}
|
||||
|
||||
void didDeliverNotification (NSUserNotification* notification) override
|
||||
{
|
||||
ignoreUnused (notification);
|
||||
}
|
||||
|
||||
void didActivateNotification (NSUserNotification* notification) override
|
||||
{
|
||||
auto n = PushNotificationsDelegateDetailsOsx::nsUserNotificationToJuceNotification (notification, isEarlierThanMavericks, isEarlierThanYosemite);
|
||||
|
||||
if (notification.activationType == NSUserNotificationActivationTypeContentsClicked)
|
||||
{
|
||||
owner.listeners.call (&PushNotifications::Listener::handleNotification, notification.remote, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto actionIdentifier = (! isEarlierThanYosemite && notification.additionalActivationAction != nil)
|
||||
? nsStringToJuce (notification.additionalActivationAction.identifier)
|
||||
: nsStringToJuce (notification.actionButtonTitle);
|
||||
|
||||
auto reply = notification.activationType == NSUserNotificationActivationTypeReplied
|
||||
? nsStringToJuce ([notification.response string])
|
||||
: String();
|
||||
|
||||
owner.listeners.call (&PushNotifications::Listener::handleNotificationAction, notification.remote, n, actionIdentifier, reply);
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldPresentNotification (NSUserNotification* notification) override { return true; }
|
||||
|
||||
void subscribeToTopic (const String& topic) { ignoreUnused (topic); }
|
||||
void unsubscribeFromTopic (const String& topic) { ignoreUnused (topic); }
|
||||
|
||||
void sendUpstreamMessage (const String& serverSenderId,
|
||||
const String& collapseKey,
|
||||
const String& messageId,
|
||||
const String& messageType,
|
||||
int timeToLive,
|
||||
const StringPairArray& additionalData)
|
||||
{
|
||||
ignoreUnused (serverSenderId, collapseKey, messageId, messageType);
|
||||
ignoreUnused (timeToLive, additionalData);
|
||||
}
|
||||
|
||||
private:
|
||||
PushNotifications& owner;
|
||||
|
||||
const bool isEarlierThanLion = std::floor (NSFoundationVersionNumber) < std::floor (NSFoundationVersionNumber10_7);
|
||||
const bool isAtLeastMountainLion = std::floor (NSFoundationVersionNumber) >= NSFoundationVersionNumber10_7;
|
||||
const bool isEarlierThanMavericks = std::floor (NSFoundationVersionNumber) < NSFoundationVersionNumber10_9;
|
||||
const bool isEarlierThanYosemite = std::floor (NSFoundationVersionNumber) <= NSFoundationVersionNumber10_9;
|
||||
|
||||
bool initialised = false;
|
||||
String deviceToken;
|
||||
|
||||
PushNotifications::Settings settings;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Loading…
Add table
Add a link
Reference in a new issue