diff --git a/.gitignore b/.gitignore
index 6e6e04e44..80f87efef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,3 +54,4 @@ fabric.properties
Habitica/res/values/secret_strings.xml
habitica.properties
habitica.resources
+Habitica/google-services.json
diff --git a/.travis.yml b/.travis.yml
index 15b9c450c..52df7c594 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -41,5 +41,6 @@ android:
script:
- cp habitica.properties.travis habitica.properties
- cp habitica.resources.example habitica.resources
+ - cp Habitica/google-services.json.example Habitica/google-services.json
- ./gradlew assembleDebug
- ./gradlew testDebugUnitTest --info
diff --git a/Habitica/AndroidManifest.xml b/Habitica/AndroidManifest.xml
index 1d5bea92c..acf754425 100644
--- a/Habitica/AndroidManifest.xml
+++ b/Habitica/AndroidManifest.xml
@@ -122,12 +122,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Username
E-mail
https://habitica.com
+
+
+ ACCEPT_PARTY_INVITE
+ REJECT_PARTY_INVITE
+ ACCEPT_GUILD_INVITE
+ REJECT_GUILD_INVITE
+ ACCEPT_QUEST_INVITE
+ REJECT_QUEST_INVITE
\ No newline at end of file
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 876d3f9da..0aa13106f 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -22,6 +22,17 @@
Activate Reminder
Set Reminder Time
+ User Push Notifications
+ Push Notifications
+ You won a Challenge!
+ Received a Private Message
+ Gifted Gems
+ Gifted Subscription
+ Invited to Party
+ Invited to Guiild
+ Your Quest has Begun
+ Invited to Quest
+
Value
New todo
diff --git a/Habitica/res/xml/preferences_fragment.xml b/Habitica/res/xml/preferences_fragment.xml
index e88c4312f..46d5b2e1b 100644
--- a/Habitica/res/xml/preferences_fragment.xml
+++ b/Habitica/res/xml/preferences_fragment.xml
@@ -75,4 +75,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java
index c0c6af461..f4d1cc3d4 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/HabitDatabase.java
@@ -7,5 +7,5 @@ public class HabitDatabase {
public static final String NAME = "Habitica";
- public static final int VERSION = 23;
+ public static final int VERSION = 24;
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
index 1f4a1450e..988db627a 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
@@ -1,8 +1,10 @@
package com.habitrpg.android.habitica.components;
import com.habitrpg.android.habitica.HabiticaApplication;
+import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager;
import com.habitrpg.android.habitica.modules.ApiModule;
import com.habitrpg.android.habitica.modules.AppModule;
+import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver;
import com.habitrpg.android.habitica.ui.activities.AboutActivity;
import com.habitrpg.android.habitica.ui.activities.ClassSelectionActivity;
import com.habitrpg.android.habitica.ui.activities.GroupFormActivity;
@@ -156,4 +158,8 @@ public interface AppComponent {
void inject(ShopsFragment shopsFragment);
void inject(ShopFragment shopFragment);
+
+ void inject(PushNotificationManager pushNotificationManager);
+
+ void inject(LocalNotificationActionReceiver localNotificationActionReceiver);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/GuildInviteLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/GuildInviteLocalNotification.java
new file mode 100644
index 000000000..a728ac0cd
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/GuildInviteLocalNotification.java
@@ -0,0 +1,56 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/1/16.
+ */
+public class GuildInviteLocalNotification extends HabiticaLocalNotification {
+
+ @Override
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Resources res = context.getResources();
+
+ Intent acceptInviteIntent = new Intent(context, LocalNotificationActionReceiver.class);
+ acceptInviteIntent.setAction(res.getString(R.string.accept_guild_invite));
+ acceptInviteIntent.putExtra("groupID", this.data.get("groupID"));
+ PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(
+ context,
+ 3000,
+ acceptInviteIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.addAction(0, "Accept", pendingIntentAccept);
+
+ Intent rejectInviteIntent = new Intent(context, LocalNotificationActionReceiver.class);
+ rejectInviteIntent.setAction(res.getString(R.string.reject_guild_invite));
+ rejectInviteIntent.putExtra("groupID", this.data.get("groupID"));
+ PendingIntent pendingIntentReject = PendingIntent.getBroadcast(
+ context,
+ 2000,
+ rejectInviteIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.addAction(0, "Reject", pendingIntentReject);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaFirebaseInstanceIDService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaFirebaseInstanceIDService.java
new file mode 100644
index 000000000..c9504930a
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaFirebaseInstanceIDService.java
@@ -0,0 +1,28 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.util.Log;
+
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.iid.FirebaseInstanceIdService;
+import com.habitrpg.android.habitica.APIHelper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * Created by keithholliday on 6/24/16.
+ */
+public class HabiticaFirebaseInstanceIDService extends FirebaseInstanceIdService {
+
+ public PushNotificationManager pushNotificationManager;
+
+ @Override
+ public void onTokenRefresh() {
+ pushNotificationManager = PushNotificationManager.getInstance(this);
+ String refreshedToken = FirebaseInstanceId.getInstance().getToken();
+ pushNotificationManager.setRefreshedToken(refreshedToken);
+ }
+
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaFirebaseMessagingService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaFirebaseMessagingService.java
new file mode 100644
index 000000000..a4c66251c
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaFirebaseMessagingService.java
@@ -0,0 +1,17 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.util.Log;
+
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+/**
+ * Created by keithholliday on 6/24/16.
+ */
+public class HabiticaFirebaseMessagingService extends FirebaseMessagingService {
+ @Override
+ public void onMessageReceived(RemoteMessage remoteMessage) {
+ PushNotificationManager pushNotificationManager = PushNotificationManager.getInstance(this);
+ pushNotificationManager.displayNotification(remoteMessage);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaLocalNotification.java
new file mode 100644
index 000000000..bad509da4
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaLocalNotification.java
@@ -0,0 +1,47 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.content.Context;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.annotation.CallSuper;
+import android.support.v4.app.NotificationCompat;
+
+import com.habitrpg.android.habitica.R;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 6/28/16.
+ */
+public abstract class HabiticaLocalNotification {
+
+ protected Map data;
+ protected Context context;
+ protected String title;
+ protected String message;
+
+ protected NotificationCompat.Builder notificationBuilder;
+
+ @CallSuper
+ public void notifyLocally(Context context, String title, String message) {
+ this.context = context;
+ this.title = title;
+ this.message = message;
+
+ Uri path = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+
+ this.notificationBuilder =
+ new NotificationCompat.Builder(context)
+ .setSmallIcon(R.drawable.ic_gryphon)
+ .setContentTitle(title)
+ .setContentText(message)
+ .setAutoCancel(true)
+ .setSound(path);
+ }
+
+ public void setExtras(Map data) {
+ this.data = data;
+ }
+
+ protected abstract void setNotificationActions();
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaLocalNotificationFactory.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaLocalNotificationFactory.java
new file mode 100644
index 000000000..3abb8db9d
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/HabiticaLocalNotificationFactory.java
@@ -0,0 +1,35 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+/**
+ * Created by keithholliday on 6/28/16.
+ */
+public class HabiticaLocalNotificationFactory {
+
+ //use getShape method to get object of type shape
+ public HabiticaLocalNotification build(String notificationType){
+ if(notificationType == null){
+ return null;
+ }
+
+ if (notificationType.equalsIgnoreCase(PushNotificationManager.PARTY_INVITE_PUSH_NOTIFICATION_KEY)) {
+ return new PartyInviteLocalNotification();
+ } else if (notificationType.contains(PushNotificationManager.RECEIVED_PRIVATE_MESSAGE_PUSH_NOTIFICATION_KEY)) {
+ return new ReceivedPrivateMessageLocalNotification();
+ } else if (notificationType.contains(PushNotificationManager.RECEIVED_GEMS_PUSH_NOTIFICATION_KEY)) {
+ return new ReceivedGemsGiftLocalNotification();
+ } else if (notificationType.contains(PushNotificationManager.RECEIVED_SUBSCRIPTION_GIFT_PUSH_NOTIFICATION_KEY)) {
+ return new ReceivedSubscriptionGiftLocalNotification();
+ } else if (notificationType.contains(PushNotificationManager.GUILD_INVITE_PUSH_NOTIFICATION_KEY)) {
+ return new GuildInviteLocalNotification();
+ } else if (notificationType.contains(PushNotificationManager.QUEST_INVITE_PUSH_NOTIFICATION_KEY)) {
+ return new QuestInviteLocalNotification();
+ } else if (notificationType.contains(PushNotificationManager.QUEST_BEGUN_PUSH_NOTIFICATION_KEY)) {
+ return new QuestBegunLocalNotification();
+ } else if (notificationType.contains(PushNotificationManager.WON_CHALLENGE_PUSH_NOTIFICATION_KEY)) {
+ return new WonChallengeLocalNotification();
+ }
+
+ return null;
+ }
+
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/PartyInviteLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/PartyInviteLocalNotification.java
new file mode 100644
index 000000000..3b1e2d5e3
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/PartyInviteLocalNotification.java
@@ -0,0 +1,56 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.RingtoneManager;
+import android.net.Uri;
+
+import android.support.v4.app.NotificationCompat;
+import android.util.Log;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver;
+import com.habitrpg.android.habitica.ui.activities.MainActivity;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 6/28/16.
+ */
+public class PartyInviteLocalNotification extends HabiticaLocalNotification {
+
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Resources res = context.getResources();
+
+ Intent acceptInviteIntent = new Intent(context, LocalNotificationActionReceiver.class);
+ acceptInviteIntent.setAction(res.getString(R.string.accept_party_invite));
+ PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(
+ context,
+ 3000,
+ acceptInviteIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.addAction(0, "Accept", pendingIntentAccept);
+
+ Intent rejectInviteIntent = new Intent(context, LocalNotificationActionReceiver.class);
+ rejectInviteIntent.setAction(res.getString(R.string.reject_party_invite));
+ PendingIntent pendingIntentReject = PendingIntent.getBroadcast(
+ context,
+ 2000,
+ rejectInviteIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.addAction(0, "Reject", pendingIntentReject);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/PushNotificationManager.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/PushNotificationManager.java
new file mode 100644
index 000000000..8b0ec84a0
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/PushNotificationManager.java
@@ -0,0 +1,159 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.messaging.RemoteMessage;
+import com.habitrpg.android.habitica.APIHelper;
+import com.habitrpg.android.habitica.HabiticaApplication;
+import com.habitrpg.android.habitica.callbacks.HabitRPGUserCallback;
+import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
+import com.magicmicky.habitrpgwrapper.lib.models.PushDevice;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * Created by keithholliday on 6/27/16.
+ */
+public class PushNotificationManager {
+
+ private static PushNotificationManager instance = null;
+ public static String DEVICE_TOKEN_PREFERENCE_KEY = "device-token-preference";
+
+ public static String PARTY_INVITE_PUSH_NOTIFICATION_KEY = "invitedParty";
+ public static String RECEIVED_PRIVATE_MESSAGE_PUSH_NOTIFICATION_KEY = "newPM";
+ public static String RECEIVED_GEMS_PUSH_NOTIFICATION_KEY = "giftedGems";
+ public static String RECEIVED_SUBSCRIPTION_GIFT_PUSH_NOTIFICATION_KEY = "giftedSubscription";
+ public static String GUILD_INVITE_PUSH_NOTIFICATION_KEY = "invitedGuild";
+ public static String QUEST_INVITE_PUSH_NOTIFICATION_KEY = "questInvitation";
+ public static String QUEST_BEGUN_PUSH_NOTIFICATION_KEY = "questStarted";
+ public static String WON_CHALLENGE_PUSH_NOTIFICATION_KEY = "wonChallenge";
+
+
+ @Inject
+ public APIHelper apiHelper;
+
+ private String refreshedToken;
+ private SharedPreferences sharedPreferences;
+ private Context context;
+ private HabitRPGUser user;
+
+ protected PushNotificationManager(Context context) {
+ HabiticaApplication.getInstance(context).getComponent().inject(this);
+ sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ }
+
+ public void setUser(HabitRPGUser user) {
+ this.user = user;
+ }
+
+ public static PushNotificationManager getInstance(Context context) {
+ if(instance == null) {
+ instance = new PushNotificationManager(context);
+ }
+
+ instance.refreshedToken = instance.sharedPreferences.getString(DEVICE_TOKEN_PREFERENCE_KEY, "");
+ instance.context = context;
+
+ return instance;
+ }
+
+ public void setRefreshedToken (String refreshedToken) {
+ if (this.refreshedToken == null) {
+ return;
+ }
+
+ this.refreshedToken = refreshedToken;
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putString(DEVICE_TOKEN_PREFERENCE_KEY, refreshedToken);
+ editor.commit();
+ }
+
+ //@TODO: Use preferences
+ public void addPushDeviceUsingStoredToken () {
+ if (this.refreshedToken == null || this.refreshedToken.isEmpty()) {
+ this.refreshedToken = FirebaseInstanceId.getInstance().getToken();
+ }
+
+ if (this.refreshedToken == null || this.refreshedToken.isEmpty()) {
+ return;
+ }
+
+ if (this.user == null || this.userHasPushDevice()) {
+ return;
+ }
+
+ if (!this.userIsSubscribedToNotifications()) {
+ return;
+ }
+
+ Map pushDeviceData = new HashMap();
+ pushDeviceData.put("regId", this.refreshedToken);
+ pushDeviceData.put("type", "android");
+ apiHelper.apiService.addPushDevice(pushDeviceData)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ }
+
+ public void removePushDeviceUsingStoredToken () {
+ apiHelper.apiService.deletePushDevice(this.refreshedToken)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ }
+
+ private Boolean userHasPushDevice() {
+ for(PushDevice pushDevice : this.user.getPushDevices()) {
+ if(pushDevice.getRegId().equals(this.refreshedToken)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void displayNotification (RemoteMessage remoteMessage) {
+ String remoteMessageIdentifier = remoteMessage.getData().get("identifier");
+
+ HabiticaLocalNotificationFactory notificationFactory = new HabiticaLocalNotificationFactory();
+ HabiticaLocalNotification notification = notificationFactory.build(remoteMessageIdentifier);
+ if (userIsSubscribedToNotificationType(remoteMessageIdentifier) && notification != null) {
+ notification.setExtras(remoteMessage.getData());
+ notification.notifyLocally(this.context, remoteMessage.getData().get("title"), remoteMessage.getData().get("body"));
+ }
+ }
+
+ private boolean userIsSubscribedToNotifications() {
+ return sharedPreferences.getBoolean("pushNotifications", true);
+ }
+
+ private boolean userIsSubscribedToNotificationType(String type) {
+ String key = "";
+
+ //@TODO: If user has push turned off to send
+
+ if (type.equals(PARTY_INVITE_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_invited_to_party";
+ } else if (type.contains(RECEIVED_PRIVATE_MESSAGE_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_received_a_private_message";
+ } else if (type.contains(RECEIVED_GEMS_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_gifted_gems";
+ } else if (type.contains(RECEIVED_SUBSCRIPTION_GIFT_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_gifted_subscription";
+ } else if (type.contains(GUILD_INVITE_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_invited_to_guild";
+ } else if (type.contains(QUEST_INVITE_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_invited_to_quest";
+ } else if (type.contains(QUEST_BEGUN_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_your_quest_has_begun";
+ } else if (type.contains(WON_CHALLENGE_PUSH_NOTIFICATION_KEY)) {
+ key = "preference_push_you_won_challenge";
+ }
+
+ return sharedPreferences.getBoolean(key, true);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/QuestBegunLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/QuestBegunLocalNotification.java
new file mode 100644
index 000000000..f49d32ec5
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/QuestBegunLocalNotification.java
@@ -0,0 +1,38 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.ui.activities.MainActivity;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/1/16.
+ */
+public class QuestBegunLocalNotification extends HabiticaLocalNotification {
+ @Override
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10000, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Intent intent = new Intent(context, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ context,
+ 3000,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.setContentIntent(pendingIntent);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/QuestInviteLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/QuestInviteLocalNotification.java
new file mode 100644
index 000000000..87ddbc61e
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/QuestInviteLocalNotification.java
@@ -0,0 +1,52 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/1/16.
+ */
+public class QuestInviteLocalNotification extends HabiticaLocalNotification {
+ @Override
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10000, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Resources res = context.getResources();
+
+ Intent acceptInviteIntent = new Intent(context, LocalNotificationActionReceiver.class);
+ acceptInviteIntent.setAction(res.getString(R.string.accept_quest_invite));
+ PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(
+ context,
+ 3000,
+ acceptInviteIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.addAction(0, "Accept", pendingIntentAccept);
+
+ Intent rejectInviteIntent = new Intent(context, LocalNotificationActionReceiver.class);
+ rejectInviteIntent.setAction(res.getString(R.string.reject_quest_invite));
+ PendingIntent pendingIntentReject = PendingIntent.getBroadcast(
+ context,
+ 2000,
+ rejectInviteIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.addAction(0, "Reject", pendingIntentReject);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedGemsGiftLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedGemsGiftLocalNotification.java
new file mode 100644
index 000000000..7e4d394c4
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedGemsGiftLocalNotification.java
@@ -0,0 +1,40 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver;
+import com.habitrpg.android.habitica.ui.activities.MainActivity;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/1/16.
+ */
+public class ReceivedGemsGiftLocalNotification extends HabiticaLocalNotification {
+ @Override
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Intent intent = new Intent(context, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ context,
+ 3000,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.setContentIntent(pendingIntent);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedPrivateMessageLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedPrivateMessageLocalNotification.java
new file mode 100644
index 000000000..e36f9b605
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedPrivateMessageLocalNotification.java
@@ -0,0 +1,46 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.RemoteInput;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.receivers.LocalNotificationActionReceiver;
+import com.habitrpg.android.habitica.ui.activities.MainActivity;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/1/16.
+ */
+public class ReceivedPrivateMessageLocalNotification extends HabiticaLocalNotification {
+
+ @Override
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Intent intent = new Intent(context, LocalNotificationActionReceiver.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ context,
+ 3000,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+
+ notificationBuilder.setContentIntent(pendingIntent);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedSubscriptionGiftLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedSubscriptionGiftLocalNotification.java
new file mode 100644
index 000000000..e2658ff6f
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/ReceivedSubscriptionGiftLocalNotification.java
@@ -0,0 +1,38 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.ui.activities.MainActivity;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/1/16.
+ */
+public class ReceivedSubscriptionGiftLocalNotification extends HabiticaLocalNotification {
+ @Override
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Intent intent = new Intent(context, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ context,
+ 3000,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.setContentIntent(pendingIntent);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/WonChallengeLocalNotification.java b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/WonChallengeLocalNotification.java
new file mode 100644
index 000000000..62e709169
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/notifications/WonChallengeLocalNotification.java
@@ -0,0 +1,38 @@
+package com.habitrpg.android.habitica.helpers.notifications;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.ui.activities.MainActivity;
+
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/2/16.
+ */
+public class WonChallengeLocalNotification extends HabiticaLocalNotification {
+ @Override
+ public void notifyLocally(Context context, String title, String message) {
+ super.notifyLocally(context, title, message);
+ this.setNotificationActions();
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
+ notificationManager.notify(10, notificationBuilder.build());
+ }
+
+ protected void setNotificationActions() {
+ Intent intent = new Intent(context, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ context,
+ 3000,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ notificationBuilder.setContentIntent(pendingIntent);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/LocalNotificationActionReceiver.java b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/LocalNotificationActionReceiver.java
new file mode 100644
index 000000000..506b41c67
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/LocalNotificationActionReceiver.java
@@ -0,0 +1,97 @@
+package com.habitrpg.android.habitica.receivers;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.habitrpg.android.habitica.APIHelper;
+import com.habitrpg.android.habitica.HabiticaApplication;
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.callbacks.HabitRPGUserCallback;
+import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
+
+import javax.inject.Inject;
+
+/**
+ * Created by keithholliday on 6/30/16.
+ */
+public class LocalNotificationActionReceiver extends BroadcastReceiver implements HabitRPGUserCallback.OnUserReceived {
+ @Inject
+ public APIHelper apiHelper;
+
+ private HabitRPGUser user;
+ private String action;
+ private Resources resources;
+ private Intent intent;
+ private Context context;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ HabiticaApplication.getInstance(context).getComponent().inject(this);
+ this.resources = context.getResources();
+
+ this.action = intent.getAction();
+ this.intent = intent;
+ this.context = context;
+
+ this.apiHelper.apiService.getUser()
+ .compose(this.apiHelper.configureApiCallObserver())
+ .subscribe(new HabitRPGUserCallback(this), throwable -> {});
+ }
+
+ @Override
+ public void onUserReceived(HabitRPGUser user) {
+ this.user = user;
+ this.handleLocalNotificationAction(action);
+ }
+
+ private void handleLocalNotificationAction(String action) {
+ NotificationManager notificationManager = (NotificationManager) this.context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancelAll();
+
+ //@TODO: This is a good place for a factory and event emitter pattern
+ if (action.equals(this.resources.getString(R.string.accept_party_invite))) {
+ if (this.user.getInvitations().getParty() == null) return;
+ String partyId = this.user.getInvitations().getParty().getId();
+ apiHelper.apiService.joinGroup(partyId)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ } else if (action.equals(this.resources.getString(R.string.reject_party_invite))) {
+ if (this.user.getInvitations().getParty() == null) return;
+ String partyId = this.user.getInvitations().getParty().getId();
+ apiHelper.apiService.rejectGroupInvite(partyId)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ } else if (action.equals(this.resources.getString(R.string.accept_quest_invite))) {
+ if (this.user.getParty() == null) return;
+ String partyId = this.user.getParty().getId();
+ apiHelper.apiService.acceptQuest(partyId)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ } else if (action.equals(this.resources.getString(R.string.reject_quest_invite))) {
+ if (this.user.getParty() == null) return;
+ String partyId = this.user.getParty().getId();
+ apiHelper.apiService.rejectQuest(partyId)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ } else if (action.equals(this.resources.getString(R.string.accept_guild_invite))) {
+ Bundle extras = this.intent.getExtras();
+ String guildId = extras.getString("groupID");
+ if (guildId == null) return;
+ apiHelper.apiService.joinGroup(guildId)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ } else if (action.equals(this.resources.getString(R.string.reject_guild_invite))) {
+ Bundle extras = this.intent.getExtras();
+ String guildId = extras.getString("groupID");
+ if (guildId == null) return;
+ apiHelper.apiService.rejectGroupInvite(guildId)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(aVoid -> {}, throwable -> {});
+ }
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java
index 364968838..a36181a04 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java
@@ -84,55 +84,6 @@ public class LoginActivity extends BaseActivity
TextView mForgotPWTV;
private Menu menu;
private CallbackManager callbackManager;
- private View.OnClickListener mLoginNormalClick = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mProgressBar.setVisibility(View.VISIBLE);
- if (isRegistering) {
- String username, email, password, cpassword;
- username = String.valueOf(mUsernameET.getText()).trim();
- email = String.valueOf(mEmail.getText()).trim();
- password = String.valueOf(mPasswordET.getText());
- cpassword = String.valueOf(mConfirmPassword.getText());
- if (username.length() == 0 || password.length() == 0 || email.length() == 0 || cpassword.length() == 0) {
- showValidationError(R.string.login_validation_error_fieldsmissing);
- return;
- }
- apiHelper.registerUser(username, email, password, cpassword)
- .compose(apiHelper.configureApiCallObserver())
- .subscribe(LoginActivity.this, throwable -> {
- hideProgress();
- });
- } else {
- String username, password;
- username = String.valueOf(mUsernameET.getText()).trim();
- password = String.valueOf(mPasswordET.getText());
- if (username.length() == 0 || password.length() == 0) {
- showValidationError(R.string.login_validation_error_fieldsmissing);
- return;
- }
- apiHelper.connectUser(username, password)
- .compose(apiHelper.configureApiCallObserver())
- .subscribe(LoginActivity.this, throwable -> {
- hideProgress();
- });
- }
- }
- };
- private View.OnClickListener mForgotPWClick = v -> {
- String url = BuildConfig.BASE_URL;
- Intent i = new Intent(Intent.ACTION_VIEW);
- i.setData(Uri.parse(url));
- startActivity(i);
- };
-
- public static void show(final View v) {
- v.setVisibility(View.VISIBLE);
- }
-
- public static void hide(final View v) {
- v.setVisibility(View.GONE);
- }
@Override
protected int getLayoutResId() {
@@ -214,6 +165,54 @@ public class LoginActivity extends BaseActivity
hide(this.mConfirmPasswordRow);
}
}
+ }
+
+ private View.OnClickListener mLoginNormalClick = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mProgressBar.setVisibility(View.VISIBLE);
+ if (isRegistering) {
+ String username, email,password,cpassword;
+ username = String.valueOf(mUsernameET.getText()).trim();
+ email = String.valueOf(mEmail.getText()).trim();
+ password = String.valueOf(mPasswordET.getText());
+ cpassword = String.valueOf(mConfirmPassword.getText());
+ if (username.length() == 0 || password.length() == 0 || email.length() == 0 || cpassword.length() == 0) {
+ showValidationError(R.string.login_validation_error_fieldsmissing);
+ return;
+ }
+ apiHelper.registerUser(username,email,password, cpassword)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(LoginActivity.this, throwable -> {hideProgress();});
+ } else {
+ String username,password;
+ username = String.valueOf(mUsernameET.getText()).trim();
+ password = String.valueOf(mPasswordET.getText());
+ if (username.length() == 0 || password.length() == 0) {
+ showValidationError(R.string.login_validation_error_fieldsmissing);
+ return;
+ }
+ apiHelper.connectUser(username,password)
+ .compose(apiHelper.configureApiCallObserver())
+ .subscribe(LoginActivity.this, throwable -> {hideProgress();});
+ }
+ }
+ };
+
+ private View.OnClickListener mForgotPWClick = v -> {
+ String url = BuildConfig.BASE_URL;
+ Intent i = new Intent(Intent.ACTION_VIEW);
+ i.setData(Uri.parse(url));
+ startActivity(i);
+ };
+
+
+ public static void show(final View v) {
+ v.setVisibility(View.VISIBLE);
+ }
+
+ public static void hide(final View v) {
+ v.setVisibility(View.GONE);
}
private void startMainActivity() {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java
index a6dcd5465..bb81fb7a7 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.java
@@ -32,6 +32,7 @@ import com.habitrpg.android.habitica.events.commands.OpenMenuItemCommand;
import com.habitrpg.android.habitica.events.commands.SellItemCommand;
import com.habitrpg.android.habitica.events.commands.UnlockPathCommand;
import com.habitrpg.android.habitica.events.commands.UpdateUserCommand;
+import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager;
import com.habitrpg.android.habitica.ui.AvatarView;
import com.habitrpg.android.habitica.ui.AvatarWithBarsViewModel;
import com.habitrpg.android.habitica.ui.TutorialView;
@@ -206,6 +207,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha
return (Math.round(value * Math.pow(10, n))) / (Math.pow(10, n));
}
+ PushNotificationManager pushNotificationManager;
+
@Override
protected int getLayoutResId() {
return R.layout.activity_main;
@@ -222,6 +225,8 @@ public class MainActivity extends BaseActivity implements Action1, Ha
//Check if reminder alarm is set
scheduleReminder(this);
+ pushNotificationManager = PushNotificationManager.getInstance(this);
+
new Select().from(HabitRPGUser.class).where(Condition.column("id").eq(hostConfig.getUser())).async().querySingle(userTransactionListener);
setupToolbar(toolbar);
@@ -349,8 +354,9 @@ public class MainActivity extends BaseActivity implements Action1, Ha
displayDeathDialogIfNeeded();
if (!fromLocalDb) {
-
displayNewInboxMessagesBadge();
+ pushNotificationManager.setUser(user);
+ pushNotificationManager.addPushDeviceUsingStoredToken();
// Update the oldEntries
new Thread(() -> {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PrefsActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PrefsActivity.java
index cf74940b9..37e2f01d2 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PrefsActivity.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/PrefsActivity.java
@@ -6,6 +6,7 @@ import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.components.AppComponent;
import com.habitrpg.android.habitica.ui.fragments.preferences.AccountDetailsFragment;
import com.habitrpg.android.habitica.ui.fragments.preferences.PreferencesFragment;
+import com.habitrpg.android.habitica.ui.fragments.preferences.PushNotificationsPreferencesFragment;
import android.content.Context;
import android.content.SharedPreferences;
@@ -88,6 +89,10 @@ public class PrefsActivity extends BaseActivity implements
if (preferenceScreen.getKey().equals("accountDetails")) {
fragment = new AccountDetailsFragment();
}
+
+ if (preferenceScreen.getKey().equals("pushNotifications")) {
+ fragment = new PushNotificationsPreferencesFragment();
+ }
return fragment;
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java
index 1498261ce..72bfc2cf7 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PreferencesFragment.java
@@ -4,6 +4,7 @@ import com.habitrpg.android.habitica.APIHelper;
import com.habitrpg.android.habitica.HabiticaApplication;
import com.habitrpg.android.habitica.NotificationPublisher;
import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager;
import com.habitrpg.android.habitica.prefs.TimePreference;
import com.habitrpg.android.habitica.ui.activities.ClassSelectionActivity;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
@@ -21,6 +22,8 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.Log;
import java.util.Calendar;
@@ -33,8 +36,11 @@ public class PreferencesFragment extends BasePreferencesFragment implements
public APIHelper apiHelper;
private Context context;
private TimePreference timePreference;
+ private PreferenceScreen pushNotificationsPreference;
private Preference classSelectionPreference;
private HabitRPGUser user;
+ private PushNotificationManager pushNotificationManager;
+
private TransactionListener userTransactionListener = new TransactionListener() {
@Override
public void onResultReceived(HabitRPGUser habitRPGUser) {
@@ -64,6 +70,7 @@ public class PreferencesFragment extends BasePreferencesFragment implements
new Select().from(HabitRPGUser.class).where(Condition.column("id").eq(userID)).async().querySingle(userTransactionListener);
}
+ pushNotificationManager = PushNotificationManager.getInstance(this.getActivity());
}
@Override
@@ -72,6 +79,12 @@ public class PreferencesFragment extends BasePreferencesFragment implements
boolean useReminder = getPreferenceManager().getSharedPreferences().getBoolean("use_reminder", false);
timePreference.setEnabled(useReminder);
+
+ pushNotificationsPreference = (PreferenceScreen) findPreference("pushNotifications");
+ boolean userPushNotifications = getPreferenceManager().getSharedPreferences().getBoolean("usePushNotifications", true);
+ pushNotificationsPreference.setEnabled(userPushNotifications);
+
+
classSelectionPreference = findPreference("choose_class");
classSelectionPreference.setVisible(false);
}
@@ -176,6 +189,14 @@ public class PreferencesFragment extends BasePreferencesFragment implements
} else if (key.equals("reminder_time")) {
removeNotifications();
scheduleNotifications();
+ } else if (key.equals("usePushNotifications")) {
+ boolean userPushNotifications = sharedPreferences.getBoolean(key, false);
+ pushNotificationsPreference.setEnabled(userPushNotifications);
+ if (userPushNotifications) {
+ pushNotificationManager.addPushDeviceUsingStoredToken();
+ } else {
+ pushNotificationManager.removePushDeviceUsingStoredToken();
+ }
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PushNotificationsPreferencesFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PushNotificationsPreferencesFragment.java
new file mode 100644
index 000000000..92f1074e0
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/PushNotificationsPreferencesFragment.java
@@ -0,0 +1,31 @@
+package com.habitrpg.android.habitica.ui.fragments.preferences;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.v7.preference.Preference;
+import android.widget.Toast;
+
+import com.habitrpg.android.habitica.R;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 6/27/16.
+ */
+public class PushNotificationsPreferencesFragment extends BasePreferencesFragment implements
+ SharedPreferences.OnSharedPreferenceChangeListener {
+
+ @Override
+ protected void setupPreferences() {
+
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java
index df990a3cf..af6d08371 100644
--- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java
+++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/api/ApiService.java
@@ -208,6 +208,9 @@ public interface ApiService {
@POST("groups/{gid}/invite")
Observable inviteToGroup(@Path("gid") String groupId, @Body Map inviteData);
+ @POST("groups/{gid}/reject-invite")
+ Observable rejectGroupInvite(@Path("gid") String groupId);
+
@POST("groups/{gid}/quests/accept")
Observable acceptQuest(@Path("gid") String groupId);
@@ -235,10 +238,17 @@ public interface ApiService {
//Members URL
@POST("members/send-private-message")
Observable postPrivateMessage(@Body HashMap messageDetails);
-
+
@GET("shops/{identifier}")
Observable fetchShopInventory(@Path("identifier") String identifier);
+ //Push notifications
+ @POST("user/push-devices")
+ Observable addPushDevice(@Body Map pushDeviceData);
+
+ @DELETE("user/push-devices/{regId}")
+ Observable deletePushDevice(@Path("regId") String regId);
+
//DEBUG: These calls only work on a local development server
@POST("debug/add-ten-gems")
diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java
index 211d0ee4a..1092cfd45 100644
--- a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java
+++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/HabitRPGUser.java
@@ -4,6 +4,7 @@ import com.google.gson.annotations.SerializedName;
import com.habitrpg.android.habitica.HabitDatabase;
import com.habitrpg.android.habitica.ui.AvatarView;
+import com.magicmicky.habitrpgwrapper.lib.models.invitations.Invitations;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TasksOrder;
import com.raizlabs.android.dbflow.annotation.Column;
@@ -92,6 +93,14 @@ public class HabitRPGUser extends BaseModel {
foreignColumnName = "user_id")})
private ContributorInfo contributor;
+ @Column
+ @ForeignKey(references = {@ForeignKeyReference(columnName = "invitations_id",
+ columnType = String.class,
+ foreignColumnName = "user_id")})
+ private Invitations invitations;
+
+ private List pushDevices = new ArrayList();
+
private Purchases purchased;
private TasksOrder tasksOrder;
@@ -145,6 +154,13 @@ public class HabitRPGUser extends BaseModel {
this.contributor = contributor;
}
+ public Invitations getInvitations() {
+ return invitations;
+ }
+
+ public void setInvitations(Invitations invitations) {
+ this.invitations = invitations;
+ }
public UserParty getParty() {
return party;
@@ -282,6 +298,14 @@ public class HabitRPGUser extends BaseModel {
this.tasksOrder = tasksOrder;
}
+ public List getPushDevices() {
+ return this.pushDevices;
+ }
+
+ public void setPushDevices(List pushDevices) {
+ this.pushDevices = pushDevices;
+ }
+
@Override
public void save() {
// We need to set the user_id to all other objects
@@ -293,6 +317,9 @@ public class HabitRPGUser extends BaseModel {
authentication.user_id = id;
flags.user_id = id;
if (contributor != null) { contributor.user_id = id; }
+ contributor.user_id = id;
+ invitations.user_id = id;
+
ArrayList allTasks = new ArrayList();
if (dailys != null) {
diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/PushDevice.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/PushDevice.java
new file mode 100644
index 000000000..c70ec2a06
--- /dev/null
+++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/PushDevice.java
@@ -0,0 +1,34 @@
+package com.magicmicky.habitrpgwrapper.lib.models;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Created by keithholliday on 7/5/16.
+ */
+public class PushDevice {
+
+ @SerializedName("regId")
+ @Expose
+ private String regId;
+
+ @SerializedName("type")
+ @Expose
+ private String type;
+
+ public String getRegId() {
+ return this.regId;
+ }
+
+ public void setRegId(String regId) {
+ this.regId = regId;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/GuildInvite.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/GuildInvite.java
new file mode 100644
index 000000000..e3d1a7291
--- /dev/null
+++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/GuildInvite.java
@@ -0,0 +1,76 @@
+package com.magicmicky.habitrpgwrapper.lib.models.invitations;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Created by keithholliday on 7/2/16.
+ */
+public class GuildInvite {
+
+ @SerializedName("inviter")
+ @Expose
+ private String inviter;
+
+ @SerializedName("name")
+ @Expose
+ private String name;
+
+ @SerializedName("id")
+ @Expose
+ private String id;
+
+ /**
+ *
+ * @return
+ * The inviter
+ */
+ public String getInviter() {
+ return inviter;
+ }
+
+ /**
+ *
+ * @param inviter
+ * The inviter
+ */
+ public void setInviter(String inviter) {
+ this.inviter = inviter;
+ }
+
+ /**
+ *
+ * @return
+ * The name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ *
+ * @param name
+ * The name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ *
+ * @return
+ * The id
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ *
+ * @param id
+ * The id
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+}
diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/Invitations.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/Invitations.java
new file mode 100644
index 000000000..d09fda0e8
--- /dev/null
+++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/Invitations.java
@@ -0,0 +1,71 @@
+package com.magicmicky.habitrpgwrapper.lib.models.invitations;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+import com.habitrpg.android.habitica.HabitDatabase;
+import com.magicmicky.habitrpgwrapper.lib.models.invitations.PartyInvite;
+import com.raizlabs.android.dbflow.annotation.Column;
+import com.raizlabs.android.dbflow.annotation.NotNull;
+import com.raizlabs.android.dbflow.annotation.PrimaryKey;
+import com.raizlabs.android.dbflow.annotation.Table;
+import com.raizlabs.android.dbflow.structure.BaseModel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by keithholliday on 7/2/16.
+ */
+@Table(databaseName = HabitDatabase.NAME)
+public class Invitations extends BaseModel {
+
+ @Column
+ @PrimaryKey
+ @NotNull
+ public String user_id;
+
+ @SerializedName("party")
+ @Expose
+ private PartyInvite party;
+
+ @SerializedName("guilds")
+ @Expose
+ private List guilds = new ArrayList();
+
+ /**
+ *
+ * @return
+ * The party invite
+ */
+ public PartyInvite getParty() {
+ return party;
+ }
+
+ /**
+ *
+ * @param party
+ * The party
+ */
+ public void setParty(PartyInvite party) {
+ this.party = party;
+ }
+
+ /**
+ *
+ * @return
+ * The guilds invite
+ */
+ public List getGuilds() {
+ return guilds;
+ }
+
+ /**
+ *
+ * @param guilds
+ * The guilds
+ */
+ public void setGuilds(List guilds) {
+ this.guilds = guilds;
+ }
+}
diff --git a/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/PartyInvite.java b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/PartyInvite.java
new file mode 100644
index 000000000..05bb1e08c
--- /dev/null
+++ b/Habitica/src/main/java/com/magicmicky/habitrpgwrapper/lib/models/invitations/PartyInvite.java
@@ -0,0 +1,73 @@
+package com.magicmicky.habitrpgwrapper.lib.models.invitations;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * Created by keithholliday on 7/2/16.
+ */
+public class PartyInvite {
+ @SerializedName("id")
+ @Expose
+ private String id;
+ @SerializedName("name")
+ @Expose
+ private String name;
+ @SerializedName("inviter")
+ @Expose
+ private String inviter;
+
+ /**
+ *
+ * @return
+ * The id
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ *
+ * @param id
+ * The id
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ *
+ * @return
+ * The name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ *
+ * @param name
+ * The name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ *
+ * @return
+ * The inviter
+ */
+ public String getInviter() {
+ return inviter;
+ }
+
+ /**
+ *
+ * @param inviter
+ * The inviter
+ */
+ public void setInviter(String inviter) {
+ this.inviter = inviter;
+ }
+}
diff --git a/README.md b/README.md
index e671d23ce..284422afb 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ It's also on Google Play:
src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" />
-Having the application installed is a good way to be notified of new releases. However, clicking "Watch" on this
+Having the application installed is a good way to be notified of new releases. However, clicking "Watch" on this
repository will allow GitHub to email you whenever we publish a release.
@@ -54,6 +54,7 @@ Setup Habitica build config files by simply copying the example habitica files.
$ cp habitica.properties.example habitica.properties
$ cp habitica.resources.example habitica.resources
+ $ cp Habitica/google-services.json.example Habitica/google-services.json (Get .json from Firebase Console)
Note: this is the default production `habitica.properties` file for habitica.com. If you
want to use a local habitica server, please modify the values in the properties file accordingly.
diff --git a/build.gradle b/build.gradle
index 2ca638a10..0e19da6e8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,6 +8,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.android.databinding:dataBinder:1.0-rc4'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
+ classpath 'com.google.gms:google-services:3.0.0'
}
}