chats: add new notification type pleroma:chat_mention (wip)
This commit is contained in:
parent
d6e7853ddf
commit
828198dab7
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 25,
|
||||
"identityHash": "ee8ddca7a73aef753951c2e2522cbb28",
|
||||
"identityHash": "7ab8482b8d5dcb97c4c8932f578879f2",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "TootEntity",
|
||||
|
@ -92,7 +92,7 @@
|
|||
},
|
||||
{
|
||||
"tableName": "AccountEntity",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsEmojiReactions` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL, `defaultFormattingSyntax` TEXT NOT NULL)",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsFollowRequested` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationsPolls` INTEGER NOT NULL, `notificationsEmojiReactions` INTEGER NOT NULL, `notificationsChatMessages` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `alwaysOpenSpoiler` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL, `notificationsFilter` TEXT NOT NULL, `defaultFormattingSyntax` TEXT NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
@ -190,6 +190,12 @@
|
|||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationsChatMessages",
|
||||
"columnName": "notificationsChatMessages",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "notificationSound",
|
||||
"columnName": "notificationSound",
|
||||
|
@ -873,7 +879,7 @@
|
|||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ee8ddca7a73aef753951c2e2522cbb28')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7ab8482b8d5dcb97c4c8932f578879f2')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -19,7 +19,12 @@
|
|||
<string name="notification_emoji_format">%s среагировал с %s на ваш пост</string>
|
||||
<string name="notification_emoji_name">Эмодзи реакции</string>
|
||||
<string name="notification_emoji_description">Уведомления о новых эмодзи реакциях</string>
|
||||
<string name="notification_chat_message_format">%s отправил вам сообщение</string>
|
||||
<string name="notification_chat_message_name">Сообщения</string>
|
||||
<string name="notification_chat_message_description">Уведомления о новых сообщениях</string>
|
||||
<string name="pref_title_default_formatting">Синтаксис форматирования по умолчанию(если поддерживается)</string>
|
||||
<string name="pref_title_notification_filter_emoji">на мои посты отреагировали</string>
|
||||
<string name="pref_title_notification_filter_chat_messages">получено новое сообщение</string>
|
||||
<string name="pref_title_hide_muted_users">Скрывать заглушенных пользователей</string>
|
||||
<string name="link">Ссылка</string>
|
||||
</resources>
|
||||
|
|
|
@ -26,9 +26,13 @@
|
|||
<string name="notification_emoji_format">%s reacted with %s to your post</string>
|
||||
<string name="notification_emoji_name">Emoji Reactions</string>
|
||||
<string name="notification_emoji_description">Notifications about new emoji reactions</string>
|
||||
<string name="notification_chat_message_format">%s sent you a message</string>
|
||||
<string name="notification_chat_message_name">Chat Messages</string>
|
||||
<string name="notification_chat_message_description">Notifications about new chat messages</string>
|
||||
|
||||
<string name="pref_title_default_formatting">Default formatting syntax(if supported by instance)</string>
|
||||
<string name="pref_title_notification_filter_emoji">my posts are reacted with emojis</string>
|
||||
<string name="pref_title_notification_filter_chat_messages">received a chat message</string>
|
||||
<string name="pref_title_hide_muted_users">Hide muted users</string>
|
||||
<string name="pref_title_enable_big_emojis">Enable bigger custom emojis</string>
|
||||
<string name="pref_title_enable_experimental_stickers">Enable experimental Pleroma-FE stickers(if available)</string>
|
||||
|
@ -37,6 +41,8 @@
|
|||
<string name="attachment_type_video">Video</string>
|
||||
<string name="attachment_type_audio">Audio</string>
|
||||
<string name="attachment_type_unknown">Attachment</string>
|
||||
|
||||
<string name="link">Link</string> <!-- Web Link -->
|
||||
|
||||
<!-- REPLACEMENT FOR TUSKY STRINGS -->
|
||||
<string name="action_toggle_visibility">Post visibility</string>
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24mm"
|
||||
height="24mm"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="ic_bbcode.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.959798"
|
||||
inkscape:cx="32.222537"
|
||||
inkscape:cy="16.813518"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1876"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="44"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-273)">
|
||||
<g
|
||||
aria-label="[ / ]"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:578.50018311;font-family:Roboto;-inkscape-font-specification:Roboto;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
id="text821">
|
||||
<path
|
||||
d="m 5.4784346,278.1925 v 1.04731 H 4.1624082 v 11.5204 h 1.3160264 v 1.04731 H 2.8877229 V 278.1925 Z"
|
||||
style="font-size:14.11111069px;line-height:578.50018311;stroke-width:0.26458332"
|
||||
id="path823" />
|
||||
<path
|
||||
d="M 14.532145,279.62566 10.3498,290.51905 H 9.2542592 l 4.1892358,-10.89339 z"
|
||||
style="font-size:14.11111069px;line-height:578.50018311;stroke-width:0.26458332"
|
||||
id="path825" />
|
||||
<path
|
||||
d="m 18.507785,279.23981 v -1.04731 h 2.604492 v 13.61502 h -2.604492 v -1.04731 h 1.322917 v -11.5204 z"
|
||||
style="font-size:14.11111069px;line-height:578.50018311;stroke-width:0.26458332"
|
||||
id="path827" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24mm"
|
||||
height="24mm"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="ic_html.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.959798"
|
||||
inkscape:cx="29.06581"
|
||||
inkscape:cy="16.813518"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1876"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="44"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-273)">
|
||||
<g
|
||||
aria-label="</>"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:578.50018311;font-family:Roboto;-inkscape-font-specification:Roboto;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
||||
id="text821">
|
||||
<path
|
||||
d="m 7.9864639,288.23494 -5.636176,-2.61138 v -0.99908 l 5.636176,-2.60449 v 1.35048 l -4.299479,1.77078 4.299479,1.74321 z"
|
||||
style="font-size:14.11111069px;line-height:578.50018311;stroke-width:0.26458332"
|
||||
id="path888" />
|
||||
<path
|
||||
d="m 14.428792,279.5533 -4.182346,10.89339 h -1.09554 l 4.189236,-10.89339 z"
|
||||
style="font-size:14.11111069px;line-height:578.50018311;stroke-width:0.26458332"
|
||||
id="path890" />
|
||||
<path
|
||||
d="m 15.765489,282.00621 5.884223,2.60449 v 1.00597 l -5.884223,2.61138 v -1.31603 l 4.561306,-1.81212 -4.561306,-1.77766 z"
|
||||
style="font-size:14.11111069px;line-height:578.50018311;stroke-width:0.26458332"
|
||||
id="path892" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24mm"
|
||||
height="24mm"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="ic_sticker.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="4"
|
||||
inkscape:cx="5.4548189"
|
||||
inkscape:cy="71.290414"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="svg8"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1876"
|
||||
inkscape:window-height="1051"
|
||||
inkscape:window-x="44"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-global="true"
|
||||
inkscape:snap-smooth-nodes="false"
|
||||
inkscape:snap-midpoints="true" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path
|
||||
sodipodi:type="inkscape:offset"
|
||||
inkscape:radius="0.61723572"
|
||||
inkscape:original="M 17.623047 3.0683594 C 17.509421 3.0655494 17.393876 3.0680084 17.279297 3.078125 L 6.4902344 3.078125 C 4.5726672 3.0249708 2.9115899 4.8344018 3.0839844 6.7363281 C 3.0869044 10.385764 3.0795738 14.036202 3.0898438 17.685547 C 3.1383328 19.540878 4.9086202 21.084854 6.75 20.921875 L 11.855469 20.921875 L 12.105469 20.921875 L 12.355469 20.669922 L 20.644531 12.349609 L 20.927734 12.064453 L 20.927734 11.849609 C 20.927794 9.9997499 20.927719 8.1505896 20.923828 6.3007812 C 20.878728 4.5685513 19.327443 3.1105255 17.623047 3.0683594 z M 12.095703 4.0761719 C 13.93776 4.0746119 15.779621 4.0764408 17.621094 4.0917969 C 19.0166 4.1998379 20.08292 5.57683 19.927734 6.9511719 L 19.927734 11.849609 L 13.728516 11.849609 C 13.471455 11.849609 13.22575 11.902783 13.001953 11.998047 C 12.778155 12.093317 12.576116 12.230525 12.40625 12.400391 C 12.236384 12.570256 12.099172 12.772297 12.003906 12.996094 C 11.908636 13.219891 11.855469 13.465594 11.855469 13.722656 L 11.855469 19.921875 C 10.175931 19.921532 8.4977933 19.918927 6.8183594 19.908203 C 5.2022402 19.843685 3.9152358 18.271407 4.0839844 16.679688 C 4.0924326 13.222849 4.0677822 9.7667037 4.0976562 6.3105469 C 4.2045509 5.0752806 5.3270093 4.0566644 6.5683594 4.078125 C 8.4101806 4.082465 10.253646 4.0777473 12.095703 4.0761719 z M 14.162109 12.849609 L 15.355469 12.849609 L 18.732422 12.849609 L 12.855469 18.75 L 12.855469 15.349609 L 12.855469 14.15625 C 12.855469 13.977032 12.892568 13.804462 12.958984 13.648438 C 13.025404 13.492411 13.121807 13.352801 13.240234 13.234375 C 13.35866 13.115948 13.498271 13.019543 13.654297 12.953125 C 13.810323 12.886705 13.982892 12.849609 14.162109 12.849609 z "
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:40;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="path4812"
|
||||
d="m 17.638672,2.4511719 c -0.11531,-0.00285 -0.236952,0.00108 -0.359375,0.00977 H 6.5078125 C 4.1925376,2.396759 2.2610006,4.5009931 2.46875,6.7929688 l -0.00195,-0.056641 c 0.00292,3.6482799 -0.00442,7.2998419 0.00586,10.9511719 a 0.61729744,0.61729744 0 0 0 0,0.01367 c 0.058506,2.238617 2.1150294,4.032162 4.3320313,3.835937 L 6.75,21.539062 h 5.105469 0.25 a 0.61729744,0.61729744 0 0 0 0.4375,-0.18164 l 0.25,-0.251953 8.289062,-8.320313 L 21.365234,12.5 a 0.61729744,0.61729744 0 0 0 0.179688,-0.435547 v -0.214844 c 6e-5,-1.8498887 -1.4e-5,-3.7001239 -0.0039,-5.5507809 a 0.61729744,0.61729744 0 0 0 0,-0.013672 C 21.486566,4.1938021 19.685497,2.5018096 17.638672,2.4511719 Z m -5.542969,2.2421875 c 1.829572,-0.00155 3.657616,5.622e-4 5.484375,0.015625 1.014403,0.082688 1.848797,1.1605015 1.734375,2.1738281 a 0.61729744,0.61729744 0 0 0 -0.0039,0.068359 v 4.2812501 h -5.582031 c -0.34218,0 -0.671313,0.07066 -0.96875,0.197266 -0.297129,0.126486 -0.563672,0.309764 -0.789063,0.535156 -0.225391,0.225389 -0.40867,0.491924 -0.535156,0.789062 -0.126626,0.297454 -0.197266,0.626581 -0.197266,0.96875 v 5.580078 C 9.7727653,19.301874 8.3083381,19.300307 6.84375,19.291016 5.6139527,19.24192 4.5676965,17.9663 4.6972656,16.744141 a 0.61729744,0.61729744 0 0 0 0.00391,-0.0625 c 0.00842,-3.446433 -0.015574,-6.8868576 0.013672,-10.322266 0.079886,-0.892733 0.9478119,-1.6795516 1.84375,-1.6640625 a 0.61729744,0.61729744 0 0 0 0.00781,0 c 1.8438457,0.00434 3.6879418,-3.783e-4 5.5292968,-0.00195 z m 2.066406,8.7734376 h 1.19336 1.890625 l -3.773438,3.789062 v -1.90625 -1.193359 c 0,-0.09404 0.02007,-0.184299 0.05469,-0.265625 0.03409,-0.08008 0.08309,-0.155357 0.148437,-0.220703 0.06535,-0.06535 0.140636,-0.114354 0.220703,-0.148438 0.08132,-0.03462 0.171582,-0.05469 0.265625,-0.05469 z"
|
||||
transform="translate(8.2803066e-4,-0.00103277)" />
|
||||
</svg>
|
After Width: | Height: | Size: 6.5 KiB |
|
@ -54,6 +54,7 @@ import com.keylesspalace.tusky.components.scheduled.ScheduledTootActivity
|
|||
import com.keylesspalace.tusky.components.search.SearchActivity
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Notification
|
||||
import com.keylesspalace.tusky.fragment.SFragment
|
||||
import com.keylesspalace.tusky.interfaces.AccountSelectionListener
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity
|
||||
|
@ -74,6 +75,10 @@ import dagger.android.DispatchingAndroidInjector
|
|||
import dagger.android.HasAndroidInjector
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
import javax.inject.Inject
|
||||
|
||||
class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInjector {
|
||||
|
@ -187,6 +192,51 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
|
|||
// Setup push notifications
|
||||
if (NotificationHelper.areNotificationsEnabled(this, accountManager)) {
|
||||
NotificationHelper.enablePullNotifications(this)
|
||||
|
||||
// Use when WorkManager doesn't want to work
|
||||
/*
|
||||
val accountList = accountManager.getAllAccountsOrderedByActive()
|
||||
for (account in accountList) {
|
||||
if (account.notificationsEnabled) {
|
||||
try {
|
||||
Log.d(TAG, "getting Notifications for " + account.fullName)
|
||||
// don't care about withMuted because they are always silently ignored
|
||||
val notificationsResponse = mastodonApi.notificationsWithAuth(
|
||||
String.format("Bearer %s", account.accessToken),
|
||||
account.domain, true,
|
||||
setOf(Notification.Type.CHAT_MESSAGE.presentation)
|
||||
).enqueue(object: Callback<List<Notification>> {
|
||||
override fun onFailure(call: Call<List<Notification>>, t: Throwable) {
|
||||
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call<List<Notification>>, response: Response<List<Notification>>) {
|
||||
val notifications = response.body()
|
||||
val newId = account.lastNotificationId
|
||||
var newestId = ""
|
||||
var isFirstOfBatch = true
|
||||
notifications?.reversed()?.forEach { notification ->
|
||||
val currentId = notification.id
|
||||
if (newestId.isLessThan(currentId)) {
|
||||
newestId = currentId
|
||||
}
|
||||
if (newId.isLessThan(currentId)) {
|
||||
NotificationHelper.make(this@MainActivity, notification, account, isFirstOfBatch)
|
||||
isFirstOfBatch = false
|
||||
}
|
||||
}
|
||||
account.lastNotificationId = newestId
|
||||
accountManager.saveAccount(account)
|
||||
}
|
||||
})
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "error receiving notifications", e)
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
} else {
|
||||
NotificationHelper.disablePullNotifications(this)
|
||||
}
|
||||
|
|
|
@ -82,6 +82,10 @@ class ChatsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
|||
content.setTypeface(null, Typeface.ITALIC)
|
||||
|
||||
content.resources.getString(it.attachment.describeAttachmentType())
|
||||
} else if (it.card != null) {
|
||||
content.setTypeface(null, Typeface.ITALIC)
|
||||
|
||||
content.resources.getString(R.string.link)
|
||||
} else ""
|
||||
|
||||
content.text = if(it.accountId == localUserId) {
|
||||
|
|
|
@ -52,6 +52,7 @@ import com.keylesspalace.tusky.MainActivity;
|
|||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.db.AccountEntity;
|
||||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
import com.keylesspalace.tusky.entity.ChatMessage;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Poll;
|
||||
import com.keylesspalace.tusky.entity.PollOption;
|
||||
|
@ -90,6 +91,8 @@ public class NotificationHelper {
|
|||
|
||||
public static final String COMPOSE_ACTION = "COMPOSE_ACTION";
|
||||
|
||||
public static final String CHAT_REPLY_ACTION = "CHAT_REPLY_ACTION";
|
||||
|
||||
public static final String KEY_REPLY = "KEY_REPLY";
|
||||
|
||||
public static final String KEY_SENDER_ACCOUNT_ID = "KEY_SENDER_ACCOUNT_ID";
|
||||
|
@ -112,6 +115,8 @@ public class NotificationHelper {
|
|||
|
||||
public static final String KEY_CITED_AUTHOR_LOCAL = "KEY_CITED_AUTHOR_LOCAL";
|
||||
|
||||
public static final String KEY_CHAT_ID = "KEY_CHAT_ID";
|
||||
|
||||
/**
|
||||
* notification channels used on Android O+
|
||||
**/
|
||||
|
@ -122,6 +127,7 @@ public class NotificationHelper {
|
|||
public static final String CHANNEL_FAVOURITE = "CHANNEL_FAVOURITE";
|
||||
public static final String CHANNEL_POLL = "CHANNEL_POLL";
|
||||
public static final String CHANNEL_EMOJI_REACTION = "CHANNEL_EMOJI_REACTION";
|
||||
public static final String CHANNEL_CHAT_MESSAGES = "CHANNEL_CHAT_MESSAGES";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -151,13 +157,13 @@ public class NotificationHelper {
|
|||
}
|
||||
|
||||
// Pleroma extension: don't notify about seen notifications
|
||||
if (body.getPleroma() != null && body.getPleroma().getSeen() == true) {
|
||||
if (body.getPleroma() != null && body.getPleroma().getSeen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (body.getStatus() != null &&
|
||||
(body.getStatus().isUserMuted() == true ||
|
||||
body.getStatus().isThreadMuted() == true)) {
|
||||
(body.getStatus().isUserMuted() ||
|
||||
body.getStatus().isThreadMuted())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -218,30 +224,45 @@ public class NotificationHelper {
|
|||
builder.setLargeIcon(accountAvatar);
|
||||
|
||||
// Reply to mention action; RemoteInput is available from KitKat Watch, but buttons are available from Nougat
|
||||
if (body.getType() == Notification.Type.MENTION
|
||||
&& android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
RemoteInput replyRemoteInput = new RemoteInput.Builder(KEY_REPLY)
|
||||
.setLabel(context.getString(R.string.label_quick_reply))
|
||||
.build();
|
||||
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
if(body.getType() == Notification.Type.MENTION) {
|
||||
RemoteInput replyRemoteInput = new RemoteInput.Builder(KEY_REPLY)
|
||||
.setLabel(context.getString(R.string.label_quick_reply))
|
||||
.build();
|
||||
|
||||
PendingIntent quickReplyPendingIntent = getStatusReplyIntent(REPLY_ACTION, context, body, account);
|
||||
PendingIntent quickReplyPendingIntent = getStatusReplyIntent(REPLY_ACTION, context, body, account);
|
||||
|
||||
NotificationCompat.Action quickReplyAction =
|
||||
new NotificationCompat.Action.Builder(R.drawable.ic_reply_24dp,
|
||||
context.getString(R.string.action_quick_reply), quickReplyPendingIntent)
|
||||
.addRemoteInput(replyRemoteInput)
|
||||
.build();
|
||||
NotificationCompat.Action quickReplyAction =
|
||||
new NotificationCompat.Action.Builder(R.drawable.ic_reply_24dp,
|
||||
context.getString(R.string.action_quick_reply), quickReplyPendingIntent)
|
||||
.addRemoteInput(replyRemoteInput)
|
||||
.build();
|
||||
|
||||
builder.addAction(quickReplyAction);
|
||||
builder.addAction(quickReplyAction);
|
||||
|
||||
PendingIntent composePendingIntent = getStatusReplyIntent(COMPOSE_ACTION, context, body, account);
|
||||
PendingIntent composePendingIntent = getStatusReplyIntent(COMPOSE_ACTION, context, body, account);
|
||||
|
||||
NotificationCompat.Action composeAction =
|
||||
new NotificationCompat.Action.Builder(R.drawable.ic_reply_24dp,
|
||||
context.getString(R.string.action_compose_shortcut), composePendingIntent)
|
||||
.build();
|
||||
NotificationCompat.Action composeAction =
|
||||
new NotificationCompat.Action.Builder(R.drawable.ic_reply_24dp,
|
||||
context.getString(R.string.action_compose_shortcut), composePendingIntent)
|
||||
.build();
|
||||
|
||||
builder.addAction(composeAction);
|
||||
builder.addAction(composeAction);
|
||||
} else if(body.getType() == Notification.Type.CHAT_MESSAGE) {
|
||||
RemoteInput replyRemoteInput = new RemoteInput.Builder(KEY_REPLY)
|
||||
.setLabel(context.getString(R.string.label_quick_reply))
|
||||
.build();
|
||||
|
||||
PendingIntent quickReplyPendingIntent = getStatusReplyIntent(CHAT_REPLY_ACTION, context, body, account);
|
||||
|
||||
NotificationCompat.Action quickReplyAction =
|
||||
new NotificationCompat.Action.Builder(R.drawable.ic_reply_24dp,
|
||||
context.getString(R.string.action_quick_reply), quickReplyPendingIntent)
|
||||
.addRemoteInput(replyRemoteInput)
|
||||
.build();
|
||||
|
||||
builder.addAction(quickReplyAction);
|
||||
}
|
||||
}
|
||||
|
||||
builder.setSubText(account.getFullName());
|
||||
|
@ -326,35 +347,40 @@ public class NotificationHelper {
|
|||
}
|
||||
|
||||
private static PendingIntent getStatusReplyIntent(String action, Context context, Notification body, AccountEntity account) {
|
||||
Status status = body.getStatus();
|
||||
|
||||
String citedLocalAuthor = status.getAccount().getLocalUsername();
|
||||
String citedText = status.getContent().toString();
|
||||
String inReplyToId = status.getId();
|
||||
Status actionableStatus = status.getActionableStatus();
|
||||
Status.Visibility replyVisibility = actionableStatus.getVisibility();
|
||||
String contentWarning = actionableStatus.getSpoilerText();
|
||||
Status.Mention[] mentions = actionableStatus.getMentions();
|
||||
List<String> mentionedUsernames = new ArrayList<>();
|
||||
mentionedUsernames.add(actionableStatus.getAccount().getUsername());
|
||||
for (Status.Mention mention : mentions) {
|
||||
mentionedUsernames.add(mention.getUsername());
|
||||
}
|
||||
mentionedUsernames.removeAll(Collections.singleton(account.getUsername()));
|
||||
mentionedUsernames = new ArrayList<>(new LinkedHashSet<>(mentionedUsernames));
|
||||
|
||||
Intent replyIntent = new Intent(context, SendStatusBroadcastReceiver.class)
|
||||
.setAction(action)
|
||||
.putExtra(KEY_CITED_AUTHOR_LOCAL, citedLocalAuthor)
|
||||
.putExtra(KEY_CITED_TEXT, citedText)
|
||||
.putExtra(KEY_SENDER_ACCOUNT_ID, account.getId())
|
||||
.putExtra(KEY_SENDER_ACCOUNT_IDENTIFIER, account.getIdentifier())
|
||||
.putExtra(KEY_SENDER_ACCOUNT_FULL_NAME, account.getFullName())
|
||||
.putExtra(KEY_NOTIFICATION_ID, notificationId)
|
||||
.putExtra(KEY_CITED_STATUS_ID, inReplyToId)
|
||||
.putExtra(KEY_VISIBILITY, replyVisibility)
|
||||
.putExtra(KEY_SPOILER, contentWarning)
|
||||
.putExtra(KEY_MENTIONS, mentionedUsernames.toArray(new String[0]));
|
||||
.setAction(action)
|
||||
.putExtra(KEY_SENDER_ACCOUNT_ID, account.getId())
|
||||
.putExtra(KEY_SENDER_ACCOUNT_IDENTIFIER, account.getIdentifier())
|
||||
.putExtra(KEY_SENDER_ACCOUNT_FULL_NAME, account.getFullName())
|
||||
.putExtra(KEY_NOTIFICATION_ID, notificationId);
|
||||
|
||||
if(action == CHAT_REPLY_ACTION) {
|
||||
replyIntent.putExtra(KEY_CHAT_ID, body.getChatMessage().getChatId());
|
||||
} else {
|
||||
Status status = body.getStatus();
|
||||
|
||||
String citedLocalAuthor = status.getAccount().getLocalUsername();
|
||||
String citedText = status.getContent().toString();
|
||||
String inReplyToId = status.getId();
|
||||
Status actionableStatus = status.getActionableStatus();
|
||||
Status.Visibility replyVisibility = actionableStatus.getVisibility();
|
||||
String contentWarning = actionableStatus.getSpoilerText();
|
||||
Status.Mention[] mentions = actionableStatus.getMentions();
|
||||
List<String> mentionedUsernames = new ArrayList<>();
|
||||
mentionedUsernames.add(actionableStatus.getAccount().getUsername());
|
||||
for (Status.Mention mention : mentions) {
|
||||
mentionedUsernames.add(mention.getUsername());
|
||||
}
|
||||
mentionedUsernames.removeAll(Collections.singleton(account.getUsername()));
|
||||
mentionedUsernames = new ArrayList<>(new LinkedHashSet<>(mentionedUsernames));
|
||||
|
||||
replyIntent.putExtra(KEY_CITED_AUTHOR_LOCAL, citedLocalAuthor)
|
||||
.putExtra(KEY_CITED_TEXT, citedText)
|
||||
.putExtra(KEY_CITED_STATUS_ID, inReplyToId)
|
||||
.putExtra(KEY_VISIBILITY, replyVisibility)
|
||||
.putExtra(KEY_SPOILER, contentWarning)
|
||||
.putExtra(KEY_MENTIONS, mentionedUsernames.toArray(new String[0]));
|
||||
}
|
||||
|
||||
return PendingIntent.getBroadcast(context.getApplicationContext(),
|
||||
notificationId,
|
||||
|
@ -374,7 +400,8 @@ public class NotificationHelper {
|
|||
CHANNEL_BOOST + account.getIdentifier(),
|
||||
CHANNEL_FAVOURITE + account.getIdentifier(),
|
||||
CHANNEL_POLL + account.getIdentifier(),
|
||||
CHANNEL_EMOJI_REACTION + account.getIdentifier()
|
||||
CHANNEL_EMOJI_REACTION + account.getIdentifier(),
|
||||
CHANNEL_CHAT_MESSAGES + account.getIdentifier()
|
||||
};
|
||||
int[] channelNames = {
|
||||
R.string.notification_mention_name,
|
||||
|
@ -384,6 +411,7 @@ public class NotificationHelper {
|
|||
R.string.notification_favourite_name,
|
||||
R.string.notification_poll_name,
|
||||
R.string.notification_emoji_name,
|
||||
R.string.notification_chat_message_name,
|
||||
};
|
||||
int[] channelDescriptions = {
|
||||
R.string.notification_mention_descriptions,
|
||||
|
@ -392,7 +420,8 @@ public class NotificationHelper {
|
|||
R.string.notification_boost_description,
|
||||
R.string.notification_favourite_description,
|
||||
R.string.notification_poll_description,
|
||||
R.string.notification_emoji_description
|
||||
R.string.notification_emoji_description,
|
||||
R.string.notification_chat_message_description,
|
||||
};
|
||||
|
||||
List<NotificationChannel> channels = new ArrayList<>(6);
|
||||
|
@ -489,7 +518,7 @@ public class NotificationHelper {
|
|||
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS, TimeUnit.MILLISECONDS
|
||||
)
|
||||
.addTag(NOTIFICATION_PULL_TAG)
|
||||
.setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
|
||||
//.setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
|
||||
.build();
|
||||
|
||||
workManager.enqueue(workRequest);
|
||||
|
@ -550,6 +579,8 @@ public class NotificationHelper {
|
|||
return account.getNotificationsPolls();
|
||||
case EMOJI_REACTION:
|
||||
return account.getNotificationsEmojiReactions();
|
||||
case CHAT_MESSAGE:
|
||||
return account.getNotificationsChatMessages();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -572,6 +603,8 @@ public class NotificationHelper {
|
|||
return CHANNEL_POLL + account.getIdentifier();
|
||||
case EMOJI_REACTION:
|
||||
return CHANNEL_EMOJI_REACTION + account.getIdentifier();
|
||||
case CHAT_MESSAGE:
|
||||
return CHANNEL_CHAT_MESSAGES + account.getIdentifier();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -653,6 +686,9 @@ public class NotificationHelper {
|
|||
} else {
|
||||
return context.getString(R.string.poll_ended_voted);
|
||||
}
|
||||
case CHAT_MESSAGE:
|
||||
return String.format(context.getString(R.string.notification_chat_message_format),
|
||||
accountName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -686,6 +722,16 @@ public class NotificationHelper {
|
|||
}
|
||||
return builder.toString();
|
||||
}
|
||||
case CHAT_MESSAGE:
|
||||
if (!TextUtils.isEmpty(notification.getChatMessage().getContent())) {
|
||||
return notification.getChatMessage().getContent().toString();
|
||||
} else if(notification.getChatMessage().getAttachment() != null) {
|
||||
return context.getString(notification.getChatMessage().getAttachment().describeAttachmentType());
|
||||
} else if(notification.getChatMessage().getCard() != null) {
|
||||
return context.getString(R.string.link);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,8 @@ class NotificationWorker(
|
|||
// don't care about withMuted because they are always silently ignored
|
||||
val notificationsResponse = mastodonApi.notificationsWithAuth(
|
||||
String.format("Bearer %s", account.accessToken),
|
||||
account.domain, true
|
||||
account.domain, true,
|
||||
setOf(Notification.Type.CHAT_MESSAGE.presentation)
|
||||
).execute()
|
||||
val notifications = notificationsResponse.body()
|
||||
if (notificationsResponse.isSuccessful && notifications != null) {
|
||||
|
|
|
@ -44,6 +44,7 @@ data class AccountEntity(@field:PrimaryKey(autoGenerate = true) var id: Long,
|
|||
var notificationsFavorited: Boolean = true,
|
||||
var notificationsPolls: Boolean = true,
|
||||
var notificationsEmojiReactions: Boolean = true,
|
||||
var notificationsChatMessages: Boolean = true,
|
||||
var notificationSound: Boolean = true,
|
||||
var notificationVibration: Boolean = true,
|
||||
var notificationLight: Boolean = true,
|
||||
|
|
|
@ -347,7 +347,7 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
public static final Migration MIGRATION_23_24 = new Migration(23, 24) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `notificationsFollowRequested` INTEGER NOT NULL DEFAULT 0");
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `notificationsFollowRequested` INTEGER NOT NULL DEFAULT 1");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -371,6 +371,7 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
"`emojis` TEXT NOT NULL," +
|
||||
"PRIMARY KEY (`localId`, `messageId`))");
|
||||
database.execSQL("ALTER TABLE `InstanceEntity` ADD COLUMN `chatLimit` INTEGER");
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `notificationsChatMessages` INTEGER NOT NULL DEFAULT 1");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import io.reactivex.Single
|
|||
@Dao
|
||||
abstract class ChatsDao {
|
||||
|
||||
// TODO: must be ordering by date but it leads to issues
|
||||
@Query("""SELECT c.chatId, c.localId, c.accountId, c.lastMessageId, c.unread, c.updatedAt,
|
||||
a.serverId as 'a_serverId', a.timelineUserId as 'a_timelineUserId',
|
||||
a.localUsername as 'a_localUsername', a.username as 'a_username',
|
||||
|
|
|
@ -60,9 +60,9 @@ class NetworkModule {
|
|||
addInterceptor(InstanceSwitchAuthInterceptor(accountManager))
|
||||
if (BuildConfig.DEBUG) {
|
||||
addInterceptor(HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BASIC
|
||||
//level = HttpLoggingInterceptor.Level.BASIC
|
||||
//level = HttpLoggingInterceptor.Level.HEADERS
|
||||
//level = HttpLoggingInterceptor.Level.BODY
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package com.keylesspalace.tusky.entity
|
|||
import com.google.gson.*
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.google.gson.annotations.JsonAdapter
|
||||
import java.util.*
|
||||
|
||||
data class PleromaNotification(
|
||||
@SerializedName("is_seen") val seen: Boolean
|
||||
|
@ -29,7 +30,9 @@ data class Notification(
|
|||
val account: Account,
|
||||
val status: Status?,
|
||||
val pleroma: PleromaNotification? = null,
|
||||
val emoji: String? = null) {
|
||||
val emoji: String? = null,
|
||||
@SerializedName("chat_message") val chatMessage: ChatMessage? = null,
|
||||
@SerializedName("created_at") val createdAt: Date? = null ) {
|
||||
|
||||
@JsonAdapter(NotificationTypeAdapter::class)
|
||||
enum class Type(val presentation: String) {
|
||||
|
@ -40,7 +43,8 @@ data class Notification(
|
|||
FOLLOW("follow"),
|
||||
POLL("poll"),
|
||||
EMOJI_REACTION("pleroma:emoji_reaction"),
|
||||
FOLLOW_REQUEST("follow_request");
|
||||
FOLLOW_REQUEST("follow_request"),
|
||||
CHAT_MESSAGE("pleroma:chat_mention");
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -52,7 +56,7 @@ data class Notification(
|
|||
}
|
||||
return UNKNOWN
|
||||
}
|
||||
val asList = listOf(MENTION, REBLOG, FAVOURITE, FOLLOW, POLL, EMOJI_REACTION, FOLLOW_REQUEST)
|
||||
val asList = listOf(MENTION, REBLOG, FAVOURITE, FOLLOW, POLL, EMOJI_REACTION, FOLLOW_REQUEST, CHAT_MESSAGE)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
|
|
@ -778,6 +778,10 @@ public class NotificationsFragment extends SFragment implements
|
|||
List<Notification.Type> notificationsList = Notification.Type.Companion.getAsList();
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Notification.Type type : notificationsList) {
|
||||
// ignore chat messages, as we don't work with them in main notification fragment
|
||||
if(type == Notification.Type.CHAT_MESSAGE)
|
||||
continue;
|
||||
|
||||
list.add(getNotificationText(type));
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,17 @@ class NotificationPreferencesFragment : PreferenceFragmentCompat(), Injectable {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
switchPreference {
|
||||
setTitle(R.string.pref_title_notification_filter_chat_messages)
|
||||
key = PrefKeys.NOTIFICATION_FILTER_CHAT_MESSAGES
|
||||
isIconSpaceReserved = false
|
||||
isChecked = activeAccount.notificationsChatMessages
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
updateAccount { it.notificationsChatMessages = newValue as Boolean }
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preferenceCategory(R.string.pref_title_notification_alerts) { category ->
|
||||
|
|
|
@ -109,7 +109,8 @@ interface MastodonApi {
|
|||
fun notificationsWithAuth(
|
||||
@Header("Authorization") auth: String,
|
||||
@Header(DOMAIN_HEADER) domain: String,
|
||||
@Query("with_muted") withMuted: Boolean?
|
||||
@Query("with_muted") withMuted: Boolean?,
|
||||
@Query("include_types[]") includeTypes: Set<String>?
|
||||
): Call<List<Notification>>
|
||||
|
||||
@POST("api/v1/notifications/clear")
|
||||
|
|
|
@ -18,6 +18,7 @@ package com.keylesspalace.tusky.receiver
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
|
@ -31,6 +32,7 @@ import com.keylesspalace.tusky.entity.Status
|
|||
import com.keylesspalace.tusky.service.SendTootService
|
||||
import com.keylesspalace.tusky.service.TootToSend
|
||||
import com.keylesspalace.tusky.components.notifications.NotificationHelper
|
||||
import com.keylesspalace.tusky.service.MessageToSend
|
||||
import com.keylesspalace.tusky.util.randomAlphanumericString
|
||||
import dagger.android.AndroidInjection
|
||||
import javax.inject.Inject
|
||||
|
@ -55,38 +57,59 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
|
|||
val mentions = intent.getStringArrayExtra(NotificationHelper.KEY_MENTIONS)
|
||||
val citedText = intent.getStringExtra(NotificationHelper.KEY_CITED_TEXT)
|
||||
val localAuthorId = intent.getStringExtra(NotificationHelper.KEY_CITED_AUTHOR_LOCAL)
|
||||
val chatId = intent.getStringExtra(NotificationHelper.KEY_CHAT_ID)
|
||||
|
||||
val account = accountManager.getAccountById(senderId)
|
||||
|
||||
val notificationManager = NotificationManagerCompat.from(context)
|
||||
|
||||
if (account == null) {
|
||||
Log.w(TAG, "Account \"$senderId\" not found in database. Aborting quick reply!")
|
||||
|
||||
if (intent.action == NotificationHelper.REPLY_ACTION) {
|
||||
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier)
|
||||
.setSmallIcon(R.drawable.ic_notify)
|
||||
.setColor(ContextCompat.getColor(context, (R.color.tusky_blue)))
|
||||
.setGroup(senderFullName)
|
||||
.setDefaults(0) // So it doesn't ring twice, notify only in Target callback
|
||||
|
||||
builder.setContentTitle(context.getString(R.string.error_generic))
|
||||
builder.setContentText(context.getString(R.string.error_sender_account_gone))
|
||||
|
||||
builder.setSubText(senderFullName)
|
||||
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
builder.setOnlyAlertOnce(true)
|
||||
|
||||
notificationManager.notify(notificationId, builder.build())
|
||||
return
|
||||
}
|
||||
|
||||
if (intent.action == NotificationHelper.COMPOSE_ACTION) {
|
||||
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||
|
||||
notificationManager.cancel(notificationId)
|
||||
|
||||
accountManager.setActiveAccount(senderId)
|
||||
|
||||
val composeIntent = ComposeActivity.startIntent(context, ComposeOptions(
|
||||
inReplyToId = citedStatusId,
|
||||
replyVisibility = visibility,
|
||||
contentWarning = spoiler,
|
||||
mentionedUsernames = mentions.toSet(),
|
||||
replyingStatusAuthor = localAuthorId,
|
||||
replyingStatusContent = citedText
|
||||
))
|
||||
|
||||
composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
context.startActivity(composeIntent)
|
||||
} else {
|
||||
val message = getReplyMessage(intent)
|
||||
|
||||
if (account == null) {
|
||||
Log.w(TAG, "Account \"$senderId\" not found in database. Aborting quick reply!")
|
||||
|
||||
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier)
|
||||
.setSmallIcon(R.drawable.ic_notify)
|
||||
.setColor(ContextCompat.getColor(context, (R.color.tusky_blue)))
|
||||
.setGroup(senderFullName)
|
||||
.setDefaults(0) // So it doesn't ring twice, notify only in Target callback
|
||||
|
||||
builder.setContentTitle(context.getString(R.string.error_generic))
|
||||
builder.setContentText(context.getString(R.string.error_sender_account_gone))
|
||||
|
||||
builder.setSubText(senderFullName)
|
||||
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
builder.setOnlyAlertOnce(true)
|
||||
|
||||
notificationManager.notify(notificationId, builder.build())
|
||||
} else {
|
||||
val sendIntent = if(intent.action == NotificationHelper.REPLY_ACTION) {
|
||||
val text = mentions.joinToString(" ", postfix = " ") { "@$it" } + message.toString()
|
||||
|
||||
val sendIntent = SendTootService.sendTootIntent(
|
||||
SendTootService.sendTootIntent(
|
||||
context,
|
||||
TootToSend(
|
||||
text,
|
||||
|
@ -110,45 +133,28 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
|
|||
0
|
||||
)
|
||||
)
|
||||
|
||||
context.startService(sendIntent)
|
||||
|
||||
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier)
|
||||
.setSmallIcon(R.drawable.ic_notify)
|
||||
.setColor(ContextCompat.getColor(context, (R.color.tusky_blue)))
|
||||
.setGroup(senderFullName)
|
||||
.setDefaults(0) // So it doesn't ring twice, notify only in Target callback
|
||||
|
||||
builder.setContentTitle(context.getString(R.string.status_sent))
|
||||
builder.setContentText(context.getString(R.string.status_sent_long))
|
||||
|
||||
builder.setSubText(senderFullName)
|
||||
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
builder.setOnlyAlertOnce(true)
|
||||
|
||||
notificationManager.notify(notificationId, builder.build())
|
||||
} else {
|
||||
SendTootService.sendMessageIntent(context,
|
||||
MessageToSend(message.toString(), null, null, account.id, chatId!!, 0))
|
||||
}
|
||||
} else if (intent.action == NotificationHelper.COMPOSE_ACTION) {
|
||||
|
||||
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||
context.startService(sendIntent)
|
||||
|
||||
notificationManager.cancel(notificationId)
|
||||
val builder = NotificationCompat.Builder(context, NotificationHelper.CHANNEL_MENTION + senderIdentifier)
|
||||
.setSmallIcon(R.drawable.ic_notify)
|
||||
.setColor(ContextCompat.getColor(context, (R.color.tusky_blue)))
|
||||
.setGroup(senderFullName)
|
||||
.setDefaults(0) // So it doesn't ring twice, notify only in Target callback
|
||||
|
||||
accountManager.setActiveAccount(senderId)
|
||||
builder.setContentTitle(context.getString(R.string.status_sent))
|
||||
builder.setContentText(context.getString(R.string.status_sent_long))
|
||||
|
||||
val composeIntent = ComposeActivity.startIntent(context, ComposeOptions(
|
||||
inReplyToId = citedStatusId,
|
||||
replyVisibility = visibility,
|
||||
contentWarning = spoiler,
|
||||
mentionedUsernames = mentions.toSet(),
|
||||
replyingStatusAuthor = localAuthorId,
|
||||
replyingStatusContent = citedText
|
||||
))
|
||||
builder.setSubText(senderFullName)
|
||||
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||
builder.setOnlyAlertOnce(true)
|
||||
|
||||
composeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
context.startActivity(composeIntent)
|
||||
notificationManager.notify(notificationId, builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ object PrefKeys {
|
|||
const val NOTIFICATION_ALERT_VIBRATE = "notificationAlertVibrate"
|
||||
const val NOTIFICATION_ALERT_SOUND = "notificationAlertSound"
|
||||
const val NOTIFICATION_FILTER_POLLS = "notificationFilterPolls"
|
||||
const val NOTIFICATION_FILTER_CHAT_MESSAGES = "notificationFilterChatMessages"
|
||||
const val NOTIFICATION_FILTER_FAVS = "notificationFilterFavourites"
|
||||
const val NOTIFICATION_FILTER_REBLOGS = "notificationFilterReblogs"
|
||||
const val NOTIFICATION_FILTER_FOLLOW_REQUESTS = "notificationFilterFollowRequests"
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
package com.keylesspalace.tusky.viewdata
|
||||
|
||||
import android.text.Spanned
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Attachment
|
||||
import com.keylesspalace.tusky.entity.Card
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import java.util.*
|
||||
|
||||
|
||||
abstract class ChatViewData {
|
||||
abstract fun getViewDataId() : Int
|
||||
abstract fun deepEquals(o: ChatViewData) : Boolean
|
||||
|
||||
class Concrete(val account : Account,
|
||||
val id: String,
|
||||
val unread: Long,
|
||||
val lastMessage: ChatMessageViewData.Concrete?,
|
||||
val updatedAt: Date ) : ChatViewData() {
|
||||
override fun getViewDataId(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
|
||||
override fun deepEquals(o: ChatViewData): Boolean {
|
||||
if (o !is Concrete) return false
|
||||
return Objects.equals(o.account, account)
|
||||
&& Objects.equals(o.id, id)
|
||||
&& o.unread == unread
|
||||
&& (lastMessage == o.lastMessage || (lastMessage != null && o.lastMessage != null && o.lastMessage.deepEquals(lastMessage)))
|
||||
&& Objects.equals(o.updatedAt, updatedAt)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return Objects.hash(account, id, unread, lastMessage, updatedAt)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
return deepEquals(other as Concrete)
|
||||
}
|
||||
}
|
||||
|
||||
class Placeholder(val id: String, val isLoading: Boolean) : ChatViewData() {
|
||||
override fun getViewDataId(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
|
||||
override fun deepEquals(o: ChatViewData): Boolean {
|
||||
if( o !is Placeholder ) return false
|
||||
return o.isLoading == isLoading && o.id == id
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = if (isLoading) 1 else 0
|
||||
result = 31 * result + id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
return deepEquals(other as Placeholder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ChatMessageViewData {
|
||||
abstract fun getViewDataId() : Int
|
||||
abstract fun deepEquals(o: ChatMessageViewData) : Boolean
|
||||
|
||||
class Concrete(val id: String,
|
||||
val content: Spanned?,
|
||||
val chatId: String,
|
||||
val accountId: String,
|
||||
val createdAt: Date,
|
||||
val attachment: Attachment?,
|
||||
val emojis: List<Emoji>,
|
||||
val card: Card?) : ChatMessageViewData()
|
||||
{
|
||||
override fun getViewDataId(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
|
||||
override fun deepEquals(o: ChatMessageViewData): Boolean {
|
||||
if( o !is Concrete ) return false
|
||||
|
||||
return Objects.equals(o.id, id)
|
||||
&& Objects.equals(o.content, content)
|
||||
&& Objects.equals(o.chatId, chatId)
|
||||
&& Objects.equals(o.accountId, accountId)
|
||||
&& Objects.equals(o.createdAt, createdAt)
|
||||
&& Objects.equals(o.attachment, attachment)
|
||||
&& Objects.equals(o.emojis, emojis)
|
||||
&& Objects.equals(o.card, card)
|
||||
}
|
||||
|
||||
override fun hashCode() : Int {
|
||||
return Objects.hash(id, content, chatId, accountId, createdAt, attachment, card)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
return deepEquals(other as Concrete)
|
||||
}
|
||||
}
|
||||
|
||||
class Placeholder(val id: String, val isLoading: Boolean) : ChatMessageViewData() {
|
||||
override fun getViewDataId(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
|
||||
override fun deepEquals(o: ChatMessageViewData): Boolean {
|
||||
if( o !is Placeholder) return false
|
||||
return o.isLoading == isLoading && o.id == id
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = if (isLoading) 1 else 0
|
||||
result = 31 * result + id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
return deepEquals(other as Placeholder)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue