mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-19 04:09:03 +00:00
Global Notification support - pt2 (#1171)
* Create custom notifications for Guild, Party & Quest invitations Merge custom notifications with the ones coming from server. Skip marking custom notifications as seen or dismissing them. * Create actionable notification item views Set result code based on accept/reject button click * Handle accept & reject results from actionable notifications Accept / reject quests & group invites based on notification type Reload user after accept/reject to refresh notifications * Create observable from custom notifications also & combine with server notifications * Better styles for small buttons * Handle displaying quest data for quest invitation notification * Add translations related to notifications
This commit is contained in:
parent
56fab73305
commit
8eed9cb197
29 changed files with 703 additions and 44 deletions
117
Habitica/res/layout/notification_item_actionable.xml
Normal file
117
Habitica/res/layout/notification_item_actionable.xml
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/notification_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="20dp"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/message_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_weight="1"
|
||||
android:lineSpacingExtra="5dp"
|
||||
android:text="Message" />
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/quest_detail_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:shrinkColumns="1"
|
||||
android:stretchColumns="1"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quest_objective_label"
|
||||
style="@style/Caption3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:textStyle="bold"
|
||||
tools:text="Collect:" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/quest_objective_text"
|
||||
style="@style/Caption3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="List of items" />
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:id="@+id/difficulty_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/difficulty_label"
|
||||
style="@style/Caption3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:textStyle="bold"
|
||||
tools:text="Difficulty:" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<RatingBar
|
||||
android:id="@+id/quest_difficulty"
|
||||
style="@style/QuestRatingBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:isIndicator="true"
|
||||
android:numStars="4"
|
||||
android:stepSize="0.5"
|
||||
tools:rating="2.5" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
</TableLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/reject_button"
|
||||
style="@style/HabiticaButton.Red.Small"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/quest.reject" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/accept_button"
|
||||
style="@style/HabiticaButton.Green.Small"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/quest.accept" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -822,4 +822,17 @@
|
|||
<string name="gift_confirmation_text">Подареният от Вас абонамент беше изпратен, и Вие също получихте абонамент.</string>
|
||||
<string name="discover">Откриване</string>
|
||||
<string name="damage_paused">Щетите са спрени</string>
|
||||
<string name="notifications">Известия</string>
|
||||
<string name="no_notifications_title">Няма непрочетени известия!</string>
|
||||
<string name="no_notifications_text">Феите на известията Ви ръкопляскат бурно! Добра работа!</string>
|
||||
<string name="dismiss_all">Премахване на всички</string>
|
||||
<string name="new_bailey_update">Ново обновление от Бейли!</string>
|
||||
<string name="new_msg_guild"><![CDATA[Има нови публикации в <b>%1$s</b>]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Има нови публикации в групата Ви — <b>%1$s</b>]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Имате <b>%1$s неразпределени показателни точки</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Имате нов <b>тайнствен предмет</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Получихте покана за присъединяване към групата <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Получихте покана за присъединяване към частната гилдия <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Получихте покана за присъединяване към гилдията <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Получихте покана за присъединяване в мисията <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -790,15 +790,27 @@ Die Quest-Schriftrolle wird an den Quest-Besitzer zurückgegeben.</string>
|
|||
<string name="setup_task_reward_notes">Schau Fernsehen, spiel ein Spiel, iss etwas Süßes, es liegt ganz an Dir!</string>
|
||||
<string name="visit_website">Internetseite besuchen</string>
|
||||
<string name="gift_title">Wen würdest Du gerne beschenken?</string>
|
||||
<string name="expand_notes">Mehr lesen</string>
|
||||
<string name="collapse_notes">Weniger anzeigen</string>
|
||||
<string name="last_login">Letzte Anmeldung</string>
|
||||
<string name="total_checkins">Gesamtanmeldungen</string>
|
||||
<string name="two_handed">Zweihändig</string>
|
||||
<string name="confirmUsername">Benutzernamen bestätigen</string>
|
||||
<string name="username_level">\@%s ・Lvl %d</string>
|
||||
<string name="verification_pet">Eines dieser Veteranen-Haustiere wartet auf Dich wenn Du die Bestätigung abgeschlossen hast!</string>
|
||||
<string name="gift_subscription">Abonnement verschenken</string>
|
||||
<string name="create_party">Gruppe erstellen</string>
|
||||
|
||||
<string name="expand_notes">Mehr lesen</string>
|
||||
<string name="collapse_notes">Weniger anzeigen</string>
|
||||
<string name="last_login">Letzte Anmeldung</string>
|
||||
<string name="total_checkins">Gesamtanmeldungen</string>
|
||||
<string name="two_handed">Zweihändig</string>
|
||||
<string name="confirmUsername">Benutzernamen bestätigen</string>
|
||||
<string name="username_level">\@%s ・Lvl %d</string>
|
||||
<string name="verification_pet">Eines dieser Veteranen-Haustiere wartet auf Dich wenn Du die Bestätigung abgeschlossen hast!</string>
|
||||
<string name="gift_subscription">Abonnement verschenken</string>
|
||||
<string name="create_party">Gruppe erstellen</string>
|
||||
<string name="notifications">Mitteilungen</string>
|
||||
<string name="no_notifications_title">Du bist auf dem Laufenden!</string>
|
||||
<string name="no_notifications_text">Die Mitteilungsfeen geben dir eine heftige Runde Applaus! Gut gemacht!</string>
|
||||
<string name="dismiss_all">Alle entfernen</string>
|
||||
<string name="new_bailey_update">Neues Update von Bailey!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> hat neue Beiträge]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Deine Gruppe, <b>%1$s</b>, hat neue Beiträge]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Du kannst <b>%1$s Attributpunkt(e)</b> verteilen]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Du hast einen neuen <b>Überraschungsgegenstand</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Du wurdest zu der Gruppe <b>%1$s</b> eingeladen]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Du wurdest eingeladen, der privaten Gilde <b>%1$s</b> beizutreten.]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Du wurdest eingeladen, der Gilde <b>%1$s</b> beizutreten.]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Du wurdest zur Quest <b>%1$s</b> eingeladen]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -574,4 +574,17 @@
|
|||
<string name="nevermind">Never mind</string>
|
||||
<string name="resetting_account">Resetting Account</string>
|
||||
<string name="deleting_account">Deleting Account</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
<string name="no_notifications_title">You’re all caught up!</string>
|
||||
<string name="no_notifications_text">The notification fairies give you a raucous round of applause! Well done!</string>
|
||||
<string name="dismiss_all">Dismiss All</string>
|
||||
<string name="new_bailey_update">New Bailey Update!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> has new posts]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Your Party, <b>%1$s</b>, has new posts]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[You have <b>%1$s unallocated Stat Points</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[You have new <b>Mystery Items</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[You were invited to join the Party <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[You were invited to join the private Guild <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[You were invited to join the Guild <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[You were invited to the Quest <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -823,4 +823,17 @@
|
|||
<string name="gift_confirmation_text">Tu suscripción regalo ha sido enviada y tu suscripción ha sido aplicada a tu cuenta.</string>
|
||||
<string name="discover">Descubre</string>
|
||||
<string name="damage_paused">Daño pausado</string>
|
||||
<string name="notifications">Notificaciones</string>
|
||||
<string name="no_notifications_title">¡Estás al día!</string>
|
||||
<string name="no_notifications_text">Las hadas de las notificaciones te aplauden atronadoramente. ¡Bien hecho!</string>
|
||||
<string name="dismiss_all">Ignorar todas</string>
|
||||
<string name="new_bailey_update">¡Nueva Actualización de Bailey!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> tiene nuevos mensajes]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Tu Equipo, <b>%1$s</b>, tiene nuevos mensajes]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Tienes <b>%1$s Puntos de Estadísticas sin asignar</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Tienes <b>Objetos Misteriosos</b> nuevos]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Has sido invitado a unirte al Equipo <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Has sido invitado a unirte al Gremio privado <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Has sido invitado a unirte al Gremio <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Has sido invitado a la misión <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -820,4 +820,17 @@
|
|||
<string name="gift_confirmation_title">Votre cadeau a été envoyé !</string>
|
||||
<string name="gift_confirmation_text_g1g1">Votre abonnement offert a été envoyé, et votre abonnement a été rattaché à votre compte.</string>
|
||||
<string name="gift_confirmation_text">Votre abonnement offert a été envoyé, et votre abonnement a été rattaché à votre compte.</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
<string name="no_notifications_title">Vous êtes à jour !</string>
|
||||
<string name="no_notifications_text">Les fées de la notification vous font un tonnerre d\'applaudissements ! Bien joué !</string>
|
||||
<string name="dismiss_all">Tout effacer</string>
|
||||
<string name="new_bailey_update">Nouvelles informations de Bailey !</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> a de nouveaux messages]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Votre équipe, <b>%1$s</b>, a de nouveaux messages]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Vous avez <b>%1$s points d\'attribut non alloués</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Vous avez de nouveaux <b>objets mystère</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Vous avez reçu une invitation à rejoindre l\'équipe <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Vous avez reçu une invitation à rejoindre la guilde privée <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Vous avez reçu une invitation à rejoindre la guilde <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[On vous invite à rejoindre la quête <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -823,4 +823,17 @@ Le Dailies mancate e le cattive Abitudini non li danneggiano molto, e hanno semp
|
|||
<string name="gift_confirmation_text">L\'abbonamento regalato è stato ricevuto e l\'abbonamento corrispondente applicato al tuo profilo.</string>
|
||||
<string name="discover">Scopri</string>
|
||||
<string name="damage_paused">Danni sospesi</string>
|
||||
<string name="notifications">Notifiche</string>
|
||||
<string name="no_notifications_title">Sei in pari!</string>
|
||||
<string name="no_notifications_text">Le fate delle notifche ti danno un rauco turno di applausi! Ben fatto!</string>
|
||||
<string name="dismiss_all">Nascondi tutto</string>
|
||||
<string name="new_bailey_update">Nuovo aggiornamento da Bailey!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> ha nuovi messaggi]]></string>
|
||||
<string name="new_msg_party"><![CDATA[La tua squadra, <b>%1$s</b>, ha nuovi messaggi]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Hai <b>%1$s Punti Statistica non allocati</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Hai dei nuovi <b>Oggetti Misteriosi</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Hai ricevuto un invito per unirti alla Squadra <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Hai ricevuto un invito per unirti alla Gilda privata <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Hai ricevuto un invito per unirti alla Gilda <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Hai ricevuto un invito per la missione <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -822,4 +822,17 @@
|
|||
<string name="server">サーバー</string>
|
||||
<string name="gift_confirmation_title">プレゼントを贈りました!</string>
|
||||
<string name="discover">探す</string>
|
||||
<string name="notifications">通知</string>
|
||||
<string name="no_notifications_title">全ての通知をチェックしました!</string>
|
||||
<string name="no_notifications_text">通知の妖精はパチパチとあなたに拍手を送っています! えらい!</string>
|
||||
<string name="dismiss_all">すべて閉じる</string>
|
||||
<string name="new_bailey_update">Baileyから新しいお知らせがあります!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> に新しい投稿があります]]></string>
|
||||
<string name="new_msg_party"><![CDATA[あなたのパーティー、<b>%1$s</b> に新しい投稿があります]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[<b>%1$sポイントが割り当てできます。</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[新しい<b>ミステリー アイテム</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[パーティー「<b>%1$s</b>」に招待されました。]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[<b>%1$s</b> プライベートギルドに招待されました。]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[<b>%1$s</b> ギルドに招待されました。]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[<b>%1$s</b> クエストに招待されました。]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -804,4 +804,17 @@
|
|||
<string name="send_gift">Verzend geschenk</string>
|
||||
<string name="server">server</string>
|
||||
<string name="gift_confirmation_title">Je geschenk is verzonden!</string>
|
||||
<string name="notifications">Meldingen</string>
|
||||
<string name="no_notifications_title">Je bent volledig klaar</string>
|
||||
<string name="no_notifications_text">De meldingsfeeën geven je een staande ovatie! Goed gedaan!</string>
|
||||
<string name="dismiss_all">Allen afwijzen</string>
|
||||
<string name="new_bailey_update">Nieuwe update van Bailey</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> heeft nieuwe berichten]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Je Gezelschap, <b>%1$s</b>, heeft nieuwe berichten]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Je hebt <b>%1$s niet toegekende statuspunten</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Je hebt nieuwe <b>Mysterieuze items</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Je werd uitgenodigd om je aan te sluiten bij de Groep <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Je werd uitgenodigd om je aan te sluiten bij het Gilde <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Je werd uitgenodigd om je aan te sluiten bij de Gilde <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Je bent uitgenodigd voor de Queeste <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -676,4 +676,17 @@
|
|||
<string name="questShop_owner_long">Ian Przewodnik Misji</string>
|
||||
<string name="seasonalShop_owner_long">Sezonowa Czarodziejka</string>
|
||||
<string name="rage_attack">Atak szału:</string>
|
||||
<string name="notifications">Powiadomienia</string>
|
||||
<string name="no_notifications_title">Teraz jesteś na bieżąco!</string>
|
||||
<string name="no_notifications_text">Wróżki powiadomień składają ci gromkie brawa. Dobra robota!</string>
|
||||
<string name="dismiss_all">Odrzuć wszystko</string>
|
||||
<string name="new_bailey_update">Nowości od Bailey</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> ma nowe posty]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Twoja drużyna <b>%1$s</b> ma nowe posty]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Masz <b>nieprzydzielone Punkty Atrybutów: %1$s</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Masz nowy <b>Tajemniczy Przedmiot</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Zostałeś/aś zaproszony/a do Dryżyny <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Zostałeś/aś zaproszony/a do prywatnej Gildii <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Zostałeś/aś zaproszony/a do Gildii <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Zostałeś/aś zaproszony/a do Misji <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -821,4 +821,17 @@
|
|||
<string name="gift_confirmation_title">Seu presente foi enviado!</string>
|
||||
<string name="gift_confirmation_text_g1g1">Sua assinatura de presente foi enviada e uma outra assinatura foi aplicada à sua conta.</string>
|
||||
<string name="gift_confirmation_text">Sua assinatura de presente foi enviada e uma outra assinatura foi aplicada à sua conta.</string>
|
||||
<string name="notifications">Notificações</string>
|
||||
<string name="no_notifications_title">Você está com tudo em dia!</string>
|
||||
<string name="no_notifications_text">As fadas da notificação lhe deram uma rodada de aplausos barulhentos! Muito bem!</string>
|
||||
<string name="dismiss_all">Dispensar Tudo</string>
|
||||
<string name="new_bailey_update">Nova atualização da Bailey!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> tem novas publicações]]></string>
|
||||
<string name="new_msg_party"><![CDATA[Seu grupo, <b>%1$s</b>, tem novas publicações]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Você tem <b>%1$s</b> Pontos de Atributos não distribuidos]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Você possui novos <b>Itens Surpresa</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Você foi convidado para entrar em um Grupo <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Você foi convidado para entrar em uma Guilda privada <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Você foi convidado para entrar em uma Guilda <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Você foi convidado para a Missão <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -494,4 +494,17 @@
|
|||
<string name="collection_quest">Recolha de Missão</string>
|
||||
<string name="quest_owner_rewards">Recompensas do Dono de Missão</string>
|
||||
<string name="tavern_description">Bem-vindo à Pousada! Puxe uma cadeira para conversar, ou efetue uma pausa das suas tarefas.</string>
|
||||
<string name="notifications">Notificações</string>
|
||||
<string name="no_notifications_title">Já sabes tudo o que se passa!</string>
|
||||
<string name="no_notifications_text">As fadas das notificações dão-te uma ruidosa salva de palmas! Bom trabalho!</string>
|
||||
<string name="dismiss_all">Dispensar Todos</string>
|
||||
<string name="new_bailey_update">Nova atualização de Bailey!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> tem novas mensagens]]></string>
|
||||
<string name="new_msg_party"><![CDATA[A sua Equipa, <b>%1$s</b>, tem novas mensagens]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Tens <b>%1$s Ponto(s) de Atributo por alocar</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Você tem <b>Items Mistério</b> novos]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Foi convidado a juntar-se à Equipa <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Foi convidado a juntar-se à Guilda privada <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Foi convidado a juntar-se à Guilda <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Foste convidado para a Missão <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -798,4 +798,17 @@
|
|||
<string name="equipment_con">ТЕЛ:</string>
|
||||
<string name="equipment_int">ИНТ:</string>
|
||||
<string name="equipment_per">ВОС:</string>
|
||||
<string name="notifications">Уведомления</string>
|
||||
<string name="no_notifications_title">Вы все вспомнили!</string>
|
||||
<string name="no_notifications_text">Феи уведомлений вам тихо рукоплещут! Отлично сработано!</string>
|
||||
<string name="dismiss_all">Сбросить все уведомления</string>
|
||||
<string name="new_bailey_update">Обновление от Бэйли!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b>, есть новые сообщения]]></string>
|
||||
<string name="new_msg_party"><![CDATA[В команде <b>%1$s</b> есть новые сообщения]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[Вы не распределили <b>%1$s очков</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[У вас новый <b>Таинственный предмет</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[Вас пригласили в команду <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[Вас пригласили присоединиться к частной гильдии <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[Вас пригласили в гильдию <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[Вас пригласили на квест <b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -808,4 +808,17 @@
|
|||
<string name="visit_website">websiteyi ziyaret et</string>
|
||||
<string name="gift_subscription">Abonelik Hediye Et</string>
|
||||
<string name="send_gift">Hediye Gönder</string>
|
||||
<string name="notifications">Bildirimler</string>
|
||||
<string name="no_notifications_title">Bildirimleri temizledin!</string>
|
||||
<string name="no_notifications_text">Bildirim perileri seni şevkle alkışlıyor! Bravo!</string>
|
||||
<string name="dismiss_all">Okundu Olarak İşaretle</string>
|
||||
<string name="new_bailey_update">Yeni Bailey Güncellemesi!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> adlı Loncada yeni mesajlar var]]></string>
|
||||
<string name="new_msg_party"><![CDATA[<b>%1$s</b> adlı Takımında yeni mesajlar var]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[<b>%1$s adet dağıtılmamış Nitelik Puanın var.</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[Yeni <b>Gizemli Eşyaların</b> var]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[<b>%1$s</b> Takımına davet edildin]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[<b>%1$s</b> adlı özel Loncaya davet edildin]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[<b>%1$s</b> adlı Loncaya davet edildin]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[<b>%1$s</b> Görevine davet edildin]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -739,4 +739,17 @@
|
|||
<string name="short_name">簡短的名稱</string>
|
||||
<string name="unlock_attribute_points">分配屬性點在10等時解鎖</string>
|
||||
<string name="moderator">管理員</string>
|
||||
<string name="notifications">通知</string>
|
||||
<string name="no_notifications_title">已查看所有新訊息!</string>
|
||||
<string name="no_notifications_text">通知仙女給您一陣熱烈的掌聲!做得好!</string>
|
||||
<string name="dismiss_all">清除全部</string>
|
||||
<string name="new_bailey_update">Bailey的新信息!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b>有新的貼文]]></string>
|
||||
<string name="new_msg_party"><![CDATA[您的隊伍<b>%1$s</b>有新的貼文]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[你有<b>%1$s點未分配屬性點</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[您有新的<b>神秘裝備</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[您受邀加入<b>%1$s</b>隊伍]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[您受邀加入<b>%1$s</b>私人公會]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[您受邀加入<b>%1$s</b>您受邀加入]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[您受邀加入<b>%1$s</b>副本]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -729,4 +729,17 @@
|
|||
<string name="next_day_reminder_title">今天完成任务了么?</string>
|
||||
<string name="next_day_reminder_text">升级后有许多可解锁和发现的,所以继续你的任务。祝玩得愉快!</string>
|
||||
<string name="two_handed">双手握持</string>
|
||||
<string name="notifications">通知</string>
|
||||
<string name="no_notifications_title">您全部都完成了!</string>
|
||||
<string name="no_notifications_text">小信使仙女们围着你欢快得鼓起了热烈的掌声!恭喜,做得太棒了!</string>
|
||||
<string name="dismiss_all">关闭全部</string>
|
||||
<string name="new_bailey_update">新的贝利更新!</string>
|
||||
<string name="new_msg_guild"><![CDATA[<b>%1$s</b> 有新消息]]></string>
|
||||
<string name="new_msg_party"><![CDATA[您的队伍 <b>%1$s</b> 有新消息]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[你有<b>%1$s没分配的属性点</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[你有新的<b>神秘物品</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[你被邀请加入队伍<b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[你被邀请加入一个私人工会<b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[你被邀请加入一个工会<b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[你被邀请加入任务<b>%1$s</b>]]></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@
|
|||
<dimen name="bb_default_elevation">8dp</dimen>
|
||||
<dimen name="bb_fake_shadow_height">4dp</dimen>
|
||||
<dimen name="button_height">38dp</dimen>
|
||||
<dimen name="button_height_small">24dp</dimen>
|
||||
<dimen name="button_text_size">16sp</dimen>
|
||||
<dimen name="alert_side_padding">26dp</dimen>
|
||||
<dimen name="downwards_drop_shadow_height">16dp</dimen>
|
||||
|
|
|
|||
|
|
@ -867,6 +867,11 @@
|
|||
<string name="new_msg_party"><![CDATA[Your Party, <b>%1$s</b>, has new posts]]></string>
|
||||
<string name="unallocated_stats_points"><![CDATA[You have <b>%1$s unallocated Stat Points</b>]]></string>
|
||||
<string name="new_subscriber_item"><![CDATA[You have new <b>Mystery Items</b>]]></string>
|
||||
<string name="invited_to_party_notification"><![CDATA[You were invited to join the Party <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_private_guild"><![CDATA[You were invited to join the private Guild <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_public_guild"><![CDATA[You were invited to join the Guild <b>%1$s</b>]]></string>
|
||||
<string name="invited_to_quest"><![CDATA[You were invited to the Quest <b>%1$s</b>]]></string>
|
||||
<string name="defeat">Defeat</string>
|
||||
<string name="create">Create</string>
|
||||
<string name="only_leader_create_challenge">Only leader can create Challenges</string>
|
||||
<string name="create_party">Create Party</string>
|
||||
|
|
|
|||
|
|
@ -464,6 +464,14 @@
|
|||
<item name="android:text">?textColorPrimaryDark</item>
|
||||
</style>
|
||||
|
||||
<style name="HabiticaButton.Small" parent="HabiticaButton">
|
||||
<item name="android:paddingTop">@dimen/button_padding_vertical_small</item>
|
||||
<item name="android:paddingBottom">@dimen/button_padding_vertical_small</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
<item name="android:minHeight">@dimen/button_height_small</item>
|
||||
<item name="android:layout_height">@dimen/button_height_small</item>
|
||||
</style>
|
||||
|
||||
<style name="HabiticaButton.Gray" parent="HabiticaButton">
|
||||
<item name="android:background">@drawable/layout_rounded_bg_gray_700</item>
|
||||
<item name="android:textColor">@color/brand_400</item>
|
||||
|
|
@ -482,6 +490,10 @@
|
|||
<item name="android:background">@drawable/layout_rounded_bg_blue</item>
|
||||
</style>
|
||||
|
||||
<style name="HabiticaButton.Red.Small" parent="HabiticaButton.Small">
|
||||
<item name="android:background">@drawable/layout_rounded_bg_red</item>
|
||||
</style>
|
||||
|
||||
<style name="SegmentTitle" parent="Headline">
|
||||
<item name="android:layout_marginBottom">@dimen/spacing_medium</item>
|
||||
</style>
|
||||
|
|
@ -490,6 +502,10 @@
|
|||
<item name="android:background">@drawable/layout_rounded_bg_green</item>
|
||||
</style>
|
||||
|
||||
<style name="HabiticaButton.Green.Small" parent="HabiticaButton.Small">
|
||||
<item name="android:background">@drawable/layout_rounded_bg_green</item>
|
||||
</style>
|
||||
|
||||
<style name="HabiticaButton.Yellow" parent="HabiticaButton">
|
||||
<item name="android:background">@drawable/layout_rounded_bg_yellow</item>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ class NotificationsManager (private val context: Context) {
|
|||
}
|
||||
|
||||
fun getNotifications(): Flowable<List<Notification>> {
|
||||
return this.notifications.toFlowable(BackpressureStrategy.LATEST)
|
||||
return this.notifications
|
||||
.startWith(emptyList<Notification>())
|
||||
.toFlowable(BackpressureStrategy.LATEST)
|
||||
}
|
||||
|
||||
fun getNotification(id: String): Notification? {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,19 @@ import com.habitrpg.android.habitica.models.notifications.*
|
|||
|
||||
class Notification {
|
||||
enum class Type(val type: String) {
|
||||
// Notification types coming from the server
|
||||
LOGIN_INCENTIVE("LOGIN_INCENTIVE"),
|
||||
NEW_STUFF("NEW_STUFF"),
|
||||
NEW_CHAT_MESSAGE("NEW_CHAT_MESSAGE"),
|
||||
NEW_MYSTERY_ITEMS("NEW_MYSTERY_ITEMS"),
|
||||
GROUP_TASK_NEEDS_WORK("GROUP_TASK_NEEDS_WORK"),
|
||||
GROUP_TASK_APPROVED("GROUP_TASK_APPROVED"),
|
||||
UNALLOCATED_STATS_POINTS("UNALLOCATED_STATS_POINTS");
|
||||
UNALLOCATED_STATS_POINTS("UNALLOCATED_STATS_POINTS"),
|
||||
|
||||
// Custom notification types (created by this app)
|
||||
GUILD_INVITATION("GUILD_INVITATION"),
|
||||
PARTY_INVITATION("PARTY_INVITATION"),
|
||||
QUEST_INVITATION("QUEST_INVITATION");
|
||||
}
|
||||
|
||||
var id: String = ""
|
||||
|
|
@ -28,6 +34,9 @@ class Notification {
|
|||
Type.GROUP_TASK_NEEDS_WORK.type -> GroupTaskNeedsWorkData::class.java
|
||||
Type.GROUP_TASK_APPROVED.type -> GroupTaskApprovedData::class.java
|
||||
Type.UNALLOCATED_STATS_POINTS.type -> UnallocatedPointsData::class.java
|
||||
Type.GUILD_INVITATION.type -> GuildInvitationData::class.java
|
||||
Type.PARTY_INVITATION.type -> PartyInvitationData::class.java
|
||||
Type.QUEST_INVITATION.type -> QuestInvitationData::class.java
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ public class GuildInvite extends RealmObject {
|
|||
@PrimaryKey
|
||||
private String id;
|
||||
|
||||
private Boolean publicGuild;
|
||||
|
||||
/**
|
||||
* @return The inviter
|
||||
*/
|
||||
|
|
@ -52,4 +54,12 @@ public class GuildInvite extends RealmObject {
|
|||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Boolean getPublicGuild() {
|
||||
return publicGuild;
|
||||
}
|
||||
|
||||
public void setPublicGuild(Boolean publicGuild) {
|
||||
this.publicGuild = publicGuild;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,9 @@ open class Invitations : RealmObject() {
|
|||
var userId: String? = null
|
||||
|
||||
internal var user: User? = null
|
||||
/**
|
||||
* @return The party invite
|
||||
*/
|
||||
/**
|
||||
* @param party The party
|
||||
*/
|
||||
|
||||
var party: PartyInvite? = null
|
||||
var parties: RealmList<PartyInvite>? = null
|
||||
private var guilds: RealmList<GuildInvite>? = null
|
||||
|
||||
/**
|
||||
|
|
@ -38,10 +34,14 @@ open class Invitations : RealmObject() {
|
|||
fun removeInvitation(groupID: String) {
|
||||
if (party?.id == groupID) {
|
||||
party = null
|
||||
} else {
|
||||
guilds?.removeAll {
|
||||
it.id == groupID
|
||||
}
|
||||
}
|
||||
|
||||
guilds?.removeAll {
|
||||
it.id == groupID
|
||||
}
|
||||
|
||||
parties?.removeAll {
|
||||
it.id == groupID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.habitrpg.android.habitica.models.notifications
|
||||
|
||||
import com.habitrpg.android.habitica.models.invitations.GuildInvite
|
||||
|
||||
open class GuildInvitationData : NotificationData {
|
||||
|
||||
var invitation: GuildInvite? = null
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.habitrpg.android.habitica.models.notifications
|
||||
|
||||
import com.habitrpg.android.habitica.models.invitations.PartyInvite
|
||||
|
||||
open class PartyInvitationData : NotificationData {
|
||||
|
||||
var invitation: PartyInvite? = null
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.habitrpg.android.habitica.models.notifications
|
||||
|
||||
open class QuestInvitationData : NotificationData {
|
||||
|
||||
var questKey: String? = null
|
||||
|
||||
}
|
||||
|
|
@ -399,6 +399,18 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
MainNavigationController
|
||||
)
|
||||
}
|
||||
|
||||
if (resultCode == NOTIFICATION_ACCEPT && data?.hasExtra("notificationId") == true) {
|
||||
notificationsViewModel?.accept(
|
||||
data.getStringExtra("notificationId")
|
||||
)
|
||||
}
|
||||
|
||||
if (resultCode == NOTIFICATION_REJECT && data?.hasExtra("notificationId") == true) {
|
||||
notificationsViewModel?.reject(
|
||||
data.getStringExtra("notificationId")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// region Events
|
||||
|
|
@ -747,5 +759,7 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
|
|||
const val SELECT_CLASS_RESULT = 11
|
||||
const val GEM_PURCHASE_REQUEST = 111
|
||||
const val NOTIFICATION_CLICK = 222
|
||||
const val NOTIFICATION_ACCEPT = 223
|
||||
const val NOTIFICATION_REJECT = 224
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,26 +4,32 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.data.InventoryRepository
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.Notification
|
||||
import com.habitrpg.android.habitica.models.inventory.QuestContent
|
||||
import com.habitrpg.android.habitica.models.notifications.*
|
||||
import com.habitrpg.android.habitica.ui.activities.MainActivity.Companion.NOTIFICATION_ACCEPT
|
||||
import com.habitrpg.android.habitica.ui.activities.MainActivity.Companion.NOTIFICATION_CLICK
|
||||
import com.habitrpg.android.habitica.ui.activities.MainActivity.Companion.NOTIFICATION_REJECT
|
||||
import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel
|
||||
import io.reactivex.functions.Consumer
|
||||
import kotlinx.android.synthetic.main.activity_notifications.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener {
|
||||
|
||||
@Inject
|
||||
lateinit var inventoryRepository: InventoryRepository
|
||||
|
||||
lateinit var viewModel: NotificationsViewModel
|
||||
|
||||
lateinit var inflater: LayoutInflater
|
||||
|
|
@ -108,11 +114,15 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
Notification.Type.NEW_MYSTERY_ITEMS.type -> createMysteryItemsNotification(it)
|
||||
Notification.Type.GROUP_TASK_NEEDS_WORK.type -> createGroupTaskNeedsWorkNotification(it)
|
||||
Notification.Type.GROUP_TASK_APPROVED.type -> createGroupTaskApprovedNotification(it)
|
||||
//TODO rest of the notification types
|
||||
Notification.Type.PARTY_INVITATION.type -> createPartyInvitationNotification(it)
|
||||
Notification.Type.GUILD_INVITATION.type -> createGuildInvitationNotification(it)
|
||||
Notification.Type.QUEST_INVITATION.type -> createQuestInvitationNotification(it)
|
||||
else -> null
|
||||
}
|
||||
|
||||
notification_items.addView(item)
|
||||
if (item != null) {
|
||||
notification_items.addView(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +142,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
val data = notification.data as? NewChatMessageData
|
||||
val stringId = if (viewModel.isPartyMessage(data)) R.string.new_msg_party else R.string.new_msg_guild
|
||||
|
||||
return createNotificationItem(
|
||||
return createDismissableNotificationItem(
|
||||
notification,
|
||||
fromHtml(getString(stringId, data?.group?.name))
|
||||
)
|
||||
|
|
@ -142,7 +152,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
val data = notification.data as? NewStuffData
|
||||
val text = fromHtml("<b>" + getString(R.string.new_bailey_update) + "</b><br>" + data?.title)
|
||||
|
||||
return createNotificationItem(
|
||||
return createDismissableNotificationItem(
|
||||
notification,
|
||||
text,
|
||||
R.drawable.notifications_bailey
|
||||
|
|
@ -152,7 +162,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
private fun createUnallocatedStatsNotification(notification: Notification): View? {
|
||||
val data = notification.data as? UnallocatedPointsData
|
||||
|
||||
return createNotificationItem(
|
||||
return createDismissableNotificationItem(
|
||||
notification,
|
||||
fromHtml(getString(R.string.unallocated_stats_points, data?.points.toString())),
|
||||
R.drawable.notification_stat_sparkles
|
||||
|
|
@ -160,7 +170,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
}
|
||||
|
||||
private fun createMysteryItemsNotification(notification: Notification): View? {
|
||||
return createNotificationItem(
|
||||
return createDismissableNotificationItem(
|
||||
notification,
|
||||
fromHtml(getString(R.string.new_subscriber_item)),
|
||||
R.drawable.notification_mystery_item
|
||||
|
|
@ -171,7 +181,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
val data = notification.data as? GroupTaskNeedsWorkData
|
||||
val message = convertGroupMessageHtml(data?.message ?: "")
|
||||
|
||||
return createNotificationItem(
|
||||
return createDismissableNotificationItem(
|
||||
notification,
|
||||
fromHtml(message),
|
||||
null,
|
||||
|
|
@ -183,7 +193,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
val data = notification.data as? GroupTaskApprovedData
|
||||
val message = convertGroupMessageHtml(data?.message ?: "")
|
||||
|
||||
return createNotificationItem(
|
||||
return createDismissableNotificationItem(
|
||||
notification,
|
||||
fromHtml(message),
|
||||
null,
|
||||
|
|
@ -204,7 +214,7 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
return message.replace(pattern, "strong")
|
||||
}
|
||||
|
||||
private fun createNotificationItem(
|
||||
private fun createDismissableNotificationItem(
|
||||
notification: Notification,
|
||||
messageText: CharSequence,
|
||||
imageResourceId: Int? = null,
|
||||
|
|
@ -239,6 +249,100 @@ class NotificationsActivity : BaseActivity(), androidx.swiperefreshlayout.widget
|
|||
return item
|
||||
}
|
||||
|
||||
private fun createPartyInvitationNotification(notification: Notification): View? {
|
||||
val data = notification.data as? PartyInvitationData
|
||||
|
||||
return createActionableNotificationItem(
|
||||
notification,
|
||||
fromHtml(getString(R.string.invited_to_party_notification, data?.invitation?.name))
|
||||
)
|
||||
}
|
||||
|
||||
private fun createGuildInvitationNotification(notification: Notification): View? {
|
||||
val data = notification.data as? GuildInvitationData
|
||||
val stringId = if (data?.invitation?.publicGuild == false) R.string.invited_to_private_guild else R.string.invited_to_public_guild
|
||||
|
||||
return createActionableNotificationItem(
|
||||
notification,
|
||||
fromHtml(getString(stringId, data?.invitation?.name))
|
||||
)
|
||||
}
|
||||
|
||||
private fun createQuestInvitationNotification(notification: Notification): View? {
|
||||
val data = notification.data as? QuestInvitationData
|
||||
|
||||
val view = createActionableNotificationItem(notification, "")
|
||||
|
||||
// hide view until we have loaded quest data and populated the values
|
||||
view.visibility = View.GONE
|
||||
|
||||
compositeSubscription.add(inventoryRepository.getQuestContent(data?.questKey ?: "")
|
||||
.firstElement()
|
||||
.subscribe(Consumer {
|
||||
updateQuestInvitationView(view, it)
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
private fun updateQuestInvitationView(view: View, questContent: QuestContent) {
|
||||
val messageTextView = view.findViewById(R.id.message_text) as? TextView
|
||||
messageTextView?.text = fromHtml(getString(R.string.invited_to_quest, questContent.text))
|
||||
|
||||
val questObjectiveLabelView = view.findViewById(R.id.quest_objective_label) as? TextView
|
||||
val questObjectiveTextView = view.findViewById(R.id.quest_objective_text) as? TextView
|
||||
val questDifficultyLabelView = view.findViewById(R.id.difficulty_label) as? TextView
|
||||
questDifficultyLabelView?.text = getText(R.string.difficulty)
|
||||
questDifficultyLabelView?.append(":")
|
||||
val questDifficultyView = view.findViewById(R.id.quest_difficulty) as? RatingBar
|
||||
|
||||
if (questContent.isBossQuest) {
|
||||
questObjectiveLabelView?.text = getString(R.string.defeat)
|
||||
questObjectiveTextView?.text = questContent.boss?.name
|
||||
|
||||
questDifficultyView?.rating = questContent.boss?.str ?: 1f
|
||||
} else {
|
||||
questObjectiveLabelView?.text = getString(R.string.collect)
|
||||
val collectionList = questContent.collect?.map { it.count.toString() + " " + it.text }
|
||||
questObjectiveTextView?.text = TextUtils.join(", ", collectionList)
|
||||
|
||||
questDifficultyView?.rating = 1f
|
||||
}
|
||||
|
||||
questObjectiveLabelView?.append(":")
|
||||
val questDetailView = view.findViewById(R.id.quest_detail_view) as? View
|
||||
questDetailView?.visibility = View.VISIBLE
|
||||
view.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun createActionableNotificationItem(
|
||||
notification: Notification,
|
||||
messageText: CharSequence
|
||||
): View {
|
||||
val item = inflater.inflate(R.layout.notification_item_actionable, notification_items, false)
|
||||
|
||||
val acceptButton = item.findViewById(R.id.accept_button) as? Button
|
||||
acceptButton?.setOnClickListener {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra("notificationId", notification.id)
|
||||
setResult(NOTIFICATION_ACCEPT, resultIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
val rejectButton = item.findViewById(R.id.reject_button) as? Button
|
||||
rejectButton?.setOnClickListener {
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra("notificationId", notification.id)
|
||||
setResult(NOTIFICATION_REJECT, resultIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
val messageTextView = item.findViewById(R.id.message_text) as? TextView
|
||||
messageTextView?.text = messageText
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
private fun fromHtml(text: String): CharSequence {
|
||||
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)
|
||||
|
|
|
|||
|
|
@ -3,15 +3,24 @@ package com.habitrpg.android.habitica.ui.viewmodels
|
|||
import android.os.Bundle
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.components.UserComponent
|
||||
import com.habitrpg.android.habitica.data.SocialRepository
|
||||
import com.habitrpg.android.habitica.extensions.notNull
|
||||
import com.habitrpg.android.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.helpers.NotificationsManager
|
||||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.Notification
|
||||
import com.habitrpg.android.habitica.models.notifications.GuildInvitationData
|
||||
import com.habitrpg.android.habitica.models.notifications.NewChatMessageData
|
||||
import com.habitrpg.android.habitica.models.notifications.PartyInvitationData
|
||||
import com.habitrpg.android.habitica.models.notifications.QuestInvitationData
|
||||
import com.habitrpg.android.habitica.models.social.UserParty
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import io.reactivex.BackpressureStrategy
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.functions.BiFunction
|
||||
import io.reactivex.functions.Consumer
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -19,9 +28,12 @@ open class NotificationsViewModel : BaseViewModel() {
|
|||
@Inject
|
||||
lateinit var notificationsManager: NotificationsManager
|
||||
|
||||
@Inject
|
||||
lateinit var socialRepository: SocialRepository
|
||||
|
||||
/**
|
||||
* A list of notification types handled by this component.
|
||||
* NOTE: Those not listed here won't be shown in the notification panel
|
||||
* NOTE: Those not listed here won't be shown in the notification panel (except the custom ones)
|
||||
*/
|
||||
private val supportedNotificationTypes = listOf(
|
||||
Notification.Type.NEW_STUFF.type,
|
||||
|
|
@ -32,28 +44,54 @@ open class NotificationsViewModel : BaseViewModel() {
|
|||
Notification.Type.UNALLOCATED_STATS_POINTS.type
|
||||
)
|
||||
|
||||
/**
|
||||
* A list of notification types that are "actionable" (ones that have accept/reject buttons).
|
||||
*/
|
||||
private val actionableNotificationTypes = listOf(
|
||||
Notification.Type.GUILD_INVITATION.type,
|
||||
Notification.Type.PARTY_INVITATION.type,
|
||||
Notification.Type.QUEST_INVITATION.type
|
||||
)
|
||||
|
||||
/**
|
||||
* Keep track of users party so we can determine which chat notifications are party chat
|
||||
* instead of guild chat notifications.
|
||||
*/
|
||||
private var party: UserParty? = null
|
||||
|
||||
/**
|
||||
* Custom notification types created by this class (from user data).
|
||||
* Will be combined with the notifications coming from server.
|
||||
*/
|
||||
private val customNotifications: BehaviorSubject<List<Notification>>
|
||||
|
||||
override fun inject(component: UserComponent) {
|
||||
component.inject(this)
|
||||
}
|
||||
|
||||
init {
|
||||
customNotifications = BehaviorSubject.create()
|
||||
customNotifications.onNext(emptyList())
|
||||
|
||||
disposable.add(userRepository.getUser()
|
||||
.subscribe(Consumer {
|
||||
party = it.party
|
||||
customNotifications.onNext(convertInvitationsToNotifications(it))
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
|
||||
|
||||
fun getNotifications(): Flowable<List<Notification>> {
|
||||
return notificationsManager.getNotifications()
|
||||
val serverNotifications = notificationsManager.getNotifications()
|
||||
.map { filterSupportedTypes(it) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
||||
return Flowable.combineLatest(
|
||||
serverNotifications,
|
||||
customNotifications.toFlowable(BackpressureStrategy.LATEST),
|
||||
BiFunction<List<Notification>, List<Notification>, List<Notification>> {
|
||||
serverNotificationsList, customNotificationsList -> serverNotificationsList + customNotificationsList
|
||||
}
|
||||
).observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
fun getNotificationCount(): Flowable<Int> {
|
||||
|
|
@ -64,7 +102,7 @@ open class NotificationsViewModel : BaseViewModel() {
|
|||
|
||||
fun allNotificationsSeen(): Flowable<Boolean> {
|
||||
return getNotifications()
|
||||
.map { it.all { notification -> notification.seen == true } }
|
||||
.map { it.all { notification -> notification.seen != false } }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +125,44 @@ open class NotificationsViewModel : BaseViewModel() {
|
|||
return notifications.filter { supportedNotificationTypes.contains(it.type) }
|
||||
}
|
||||
|
||||
private fun convertInvitationsToNotifications(user: User): List<Notification> {
|
||||
val notifications = arrayListOf<Notification>()
|
||||
|
||||
notifications.addAll(user.invitations?.parties?.map {
|
||||
val notification = Notification()
|
||||
notification.id = "custom-party-invitation-" + it.id
|
||||
notification.type = Notification.Type.PARTY_INVITATION.type
|
||||
val data = PartyInvitationData()
|
||||
data.invitation = it
|
||||
notification.data = data
|
||||
notification
|
||||
} ?: emptyList())
|
||||
|
||||
notifications.addAll(user.invitations?.getGuilds()?.map {
|
||||
val notification = Notification()
|
||||
notification.id = "custom-guild-invitation-" + it.id
|
||||
notification.type = Notification.Type.GUILD_INVITATION.type
|
||||
val data = GuildInvitationData()
|
||||
data.invitation = it
|
||||
notification.data = data
|
||||
notification
|
||||
} ?: emptyList())
|
||||
|
||||
val quest = user.party?.quest
|
||||
if (quest != null && quest.RSVPNeeded) {
|
||||
val notification = Notification()
|
||||
notification.id = "custom-quest-invitation-" + user.party?.id
|
||||
notification.type = Notification.Type.QUEST_INVITATION.type
|
||||
val data = QuestInvitationData()
|
||||
data.questKey = quest.key
|
||||
notification.data = data
|
||||
|
||||
notifications.add(notification)
|
||||
}
|
||||
|
||||
return notifications
|
||||
}
|
||||
|
||||
fun isPartyMessage(data: NewChatMessageData?): Boolean {
|
||||
if (party == null || data?.group?.id == null) {
|
||||
return false
|
||||
|
|
@ -95,26 +171,45 @@ open class NotificationsViewModel : BaseViewModel() {
|
|||
return party?.id == data.group?.id
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the given notification an "artificial" custom notification (created by this class)
|
||||
* instead of one of the ones coming from server.
|
||||
*/
|
||||
private fun isCustomNotification(notification: Notification): Boolean {
|
||||
return notification.id.startsWith("custom-")
|
||||
}
|
||||
|
||||
fun dismissNotification(notification: Notification) {
|
||||
if (isCustomNotification(notification)) {
|
||||
return
|
||||
}
|
||||
|
||||
disposable.add(userRepository.readNotification(notification.id)
|
||||
.subscribe(Consumer {}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
|
||||
fun dismissAllNotifications(notifications: List<Notification>) {
|
||||
if (notifications.isEmpty()) {
|
||||
val dismissableIds = notifications
|
||||
.filter { !isCustomNotification(it) }
|
||||
.filter { !actionableNotificationTypes.contains(it.type) }
|
||||
.map { it.id }
|
||||
|
||||
if (dismissableIds.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val notificationIds = HashMap<String, List<String>>()
|
||||
notificationIds["notificationIds"] = notifications.map { notification -> notification.id }
|
||||
notificationIds["notificationIds"] = dismissableIds
|
||||
|
||||
disposable.add(userRepository.readNotifications(notificationIds)
|
||||
.subscribe(Consumer {}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
|
||||
fun markNotificationsAsSeen(notifications: List<Notification>) {
|
||||
val unseenIds = notifications.filter { notification -> notification.seen != true }
|
||||
.map { notification -> notification.id }
|
||||
val unseenIds = notifications
|
||||
.filter { !isCustomNotification(it) }
|
||||
.filter { it.seen == false }
|
||||
.map { it.id }
|
||||
|
||||
if (unseenIds.isEmpty()) {
|
||||
return
|
||||
|
|
@ -155,4 +250,71 @@ open class NotificationsViewModel : BaseViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
fun accept(notificationId: String) {
|
||||
val notification = customNotifications.value?.find { it.id == notificationId } ?: return
|
||||
|
||||
when (notification.type) {
|
||||
Notification.Type.GUILD_INVITATION.type -> {
|
||||
val data = notification.data as GuildInvitationData
|
||||
acceptGroupInvitation(data.invitation?.id)
|
||||
}
|
||||
Notification.Type.PARTY_INVITATION.type -> {
|
||||
val data = notification.data as PartyInvitationData
|
||||
acceptGroupInvitation(data.invitation?.id)
|
||||
}
|
||||
Notification.Type.QUEST_INVITATION.type -> acceptQuestInvitation()
|
||||
}
|
||||
}
|
||||
|
||||
fun reject(notificationId: String) {
|
||||
val notification = customNotifications.value?.find { it.id == notificationId } ?: return
|
||||
|
||||
when (notification.type) {
|
||||
Notification.Type.GUILD_INVITATION.type -> {
|
||||
val data = notification.data as GuildInvitationData
|
||||
rejectGroupInvite(data.invitation?.id)
|
||||
}
|
||||
Notification.Type.PARTY_INVITATION.type -> {
|
||||
val data = notification.data as PartyInvitationData
|
||||
rejectGroupInvite(data.invitation?.id)
|
||||
}
|
||||
Notification.Type.QUEST_INVITATION.type -> rejectQuestInvitation()
|
||||
}
|
||||
}
|
||||
|
||||
fun acceptGroupInvitation(groupId: String?) {
|
||||
groupId.notNull {
|
||||
disposable.add(socialRepository.joinGroup(it)
|
||||
.subscribe(Consumer {
|
||||
refreshNotifications()
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
}
|
||||
|
||||
fun rejectGroupInvite(groupId: String?) {
|
||||
groupId.notNull {
|
||||
disposable.add(socialRepository.rejectGroupInvite(it)
|
||||
.subscribe(Consumer {
|
||||
refreshNotifications()
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun acceptQuestInvitation() {
|
||||
party?.id.notNull {
|
||||
disposable.add(socialRepository.acceptQuest(null, it)
|
||||
.subscribe(Consumer {
|
||||
refreshNotifications()
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun rejectQuestInvitation() {
|
||||
party?.id.notNull {
|
||||
disposable.add(socialRepository.rejectQuest(null, it)
|
||||
.subscribe(Consumer {
|
||||
refreshNotifications()
|
||||
}, RxErrorHandler.handleEmptyError()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue