From a46f8f1c20990daf77ddaa80bc35dc8445448fe2 Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Thu, 29 Dec 2022 17:13:44 -0300 Subject: [PATCH 001/133] Adding a new fluent edit icon for the fab --- mastodon/src/main/res/drawable/bg_fab.xml | 2 +- mastodon/src/main/res/drawable/ic_edit_34.xml | 5 ---- .../res/drawable/ic_fluent_edit_28_filled.xml | 3 +++ .../src/main/res/layout/fragment_profile.xml | 14 +---------- .../res/layout/recycler_fragment_with_fab.xml | 15 +----------- mastodon/src/main/res/values/attrs.xml | 3 +++ mastodon/src/main/res/values/styles.xml | 23 +++++++++++++++++++ 7 files changed, 32 insertions(+), 33 deletions(-) delete mode 100644 mastodon/src/main/res/drawable/ic_edit_34.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_edit_28_filled.xml diff --git a/mastodon/src/main/res/drawable/bg_fab.xml b/mastodon/src/main/res/drawable/bg_fab.xml index 320e3e279..00025992d 100644 --- a/mastodon/src/main/res/drawable/bg_fab.xml +++ b/mastodon/src/main/res/drawable/bg_fab.xml @@ -3,7 +3,7 @@ android:color="?android:colorControlHighlight"> - + diff --git a/mastodon/src/main/res/drawable/ic_edit_34.xml b/mastodon/src/main/res/drawable/ic_edit_34.xml deleted file mode 100644 index 9e7fa0dd1..000000000 --- a/mastodon/src/main/res/drawable/ic_edit_34.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/mastodon/src/main/res/drawable/ic_fluent_edit_28_filled.xml b/mastodon/src/main/res/drawable/ic_fluent_edit_28_filled.xml new file mode 100644 index 000000000..1510e850c --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_edit_28_filled.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/layout/fragment_profile.xml b/mastodon/src/main/res/layout/fragment_profile.xml index 7828f92be..a6afddd68 100644 --- a/mastodon/src/main/res/layout/fragment_profile.xml +++ b/mastodon/src/main/res/layout/fragment_profile.xml @@ -323,19 +323,7 @@ - - + \ No newline at end of file diff --git a/mastodon/src/main/res/layout/recycler_fragment_with_fab.xml b/mastodon/src/main/res/layout/recycler_fragment_with_fab.xml index 4dcdac756..1ed27ed70 100644 --- a/mastodon/src/main/res/layout/recycler_fragment_with_fab.xml +++ b/mastodon/src/main/res/layout/recycler_fragment_with_fab.xml @@ -20,19 +20,6 @@ android:layout_height="match_parent" android:id="@+id/empty"/> - - + \ No newline at end of file diff --git a/mastodon/src/main/res/values/attrs.xml b/mastodon/src/main/res/values/attrs.xml index cb1c4d5ce..b170a87e2 100644 --- a/mastodon/src/main/res/values/attrs.xml +++ b/mastodon/src/main/res/values/attrs.xml @@ -5,10 +5,13 @@ + + + diff --git a/mastodon/src/main/res/values/styles.xml b/mastodon/src/main/res/values/styles.xml index 1af3e20fe..235c5f5a0 100644 --- a/mastodon/src/main/res/values/styles.xml +++ b/mastodon/src/main/res/values/styles.xml @@ -38,6 +38,9 @@ ?colorPrimary100 ?colorGray500 ?colorGray50 + ?colorBackgroundPopup + ?android:textColorPrimary + @style/Widget.Mastodon.Button.Compose @drawable/bg_button_primary_dark_on_light @drawable/bg_edittext_light @@ -132,6 +135,10 @@ ?colorGray700 ?colorGray300 ?colorGray800 + ?colorPrimary700 + ?colorGray100 + + @style/Widget.Mastodon.Button.Compose @drawable/bg_button_primary_light_on_dark @drawable/bg_edittext_dark @@ -199,6 +206,8 @@ @color/black ?colorGray900 @color/black + ?android:colorAccent + ?colorGray900 #000 @@ -236,6 +245,20 @@ ?colorGray25 + + @@ -345,7 +345,7 @@ ?colorPrimary600 ?colorGray50 - ?colorGray700 + ?colorBackgroundPopup ?colorGray50 ?colorGray400 From fc2e5112c06569c8161b86ec2f82f672b8dbabb0 Mon Sep 17 00:00:00 2001 From: sk Date: Fri, 23 Dec 2022 16:17:54 -0300 Subject: [PATCH 030/133] add option to open post with other account closes #182 --- .../android/ui/M3AlertDialogBuilder.java | 2 +- .../ui/displayitems/HeaderStatusDisplayItem.java | 15 +++++++++++++-- .../joinmastodon/android/ui/utils/UiUtils.java | 10 ++++++++++ mastodon/src/main/res/menu/post.xml | 1 + mastodon/src/main/res/values/strings_sk.xml | 4 +++- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/M3AlertDialogBuilder.java b/mastodon/src/main/java/org/joinmastodon/android/ui/M3AlertDialogBuilder.java index e140d58ec..566bde320 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/M3AlertDialogBuilder.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/M3AlertDialogBuilder.java @@ -32,7 +32,7 @@ public class M3AlertDialogBuilder extends AlertDialog.Builder{ View title=alert.findViewById(titleID); if(title!=null){ int pad=V.dp(24); - title.setPadding(pad, pad, pad, pad); + title.setPadding(pad, pad, pad, V.dp(18)); } } int titleDividerID=getContext().getResources().getIdentifier("titleDividerNoCustom", "id", "android"); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java index 07744eaa3..729033922 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java @@ -135,6 +135,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ avatar.setOutlineProvider(roundCornersOutline); avatar.setClipToOutline(true); more.setOnClickListener(this::onMoreClick); + more.setOnLongClickListener((v) -> { openWithAccount(); return true; }); visibility.setOnClickListener(v->item.parentFragment.onVisibilityIconClick(this)); optionsMenu=new PopupMenu(activity, more); @@ -182,8 +183,11 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ } }else if(id==R.id.delete){ UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{}); - }else if(id==R.id.pin || id==R.id.unpin){ - UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s->{}); + }else if(id==R.id.pin || id==R.id.unpin) { + UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s -> { + }); + }else if(id==R.id.open_with_account) { + openWithAccount(); }else if(id==R.id.mute){ UiUtils.confirmToggleMuteUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, relationship!=null && relationship.muting, r->{}); }else if(id==R.id.block){ @@ -220,6 +224,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ }); } + private void openWithAccount() { + UiUtils.pickAccount(item.parentFragment.getActivity(), (session, dialog) -> { + UiUtils.openURL(item.parentFragment.getActivity(), session.getID(), item.status.url); + return true; + }, R.string.sk_open_in_account); + } + @Override public void onBind(HeaderStatusDisplayItem item){ name.setText(item.parsedName); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index 9e57f3666..a011a845b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -56,6 +56,7 @@ import org.joinmastodon.android.api.requests.search.GetSearchResults; import org.joinmastodon.android.api.requests.statuses.DeleteStatus; import org.joinmastodon.android.api.requests.statuses.GetStatusByID; import org.joinmastodon.android.api.requests.statuses.SetStatusPinned; +import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.StatusCountersUpdatedEvent; import org.joinmastodon.android.events.FollowRequestHandledEvent; @@ -95,6 +96,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import androidx.annotation.AttrRes; +import androidx.annotation.DrawableRes; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.browser.customtabs.CustomTabsIntent; @@ -812,4 +814,12 @@ public class UiUtils{ public static boolean isMIUI(){ return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.code")); } + + public static void pickAccount(Context context, BiPredicate pick, @StringRes int title) { + List sessions=AccountSessionManager.getInstance().getLoggedInAccounts(); + new M3AlertDialogBuilder(context) + .setItems(sessions.stream().map(as->"@"+as.self.username+"@"+as.domain).toArray(String[]::new), (d, which)->pick.test(sessions.get(which), d)) + .setTitle(title == 0 ? R.string.choose_account : title) + .show(); + } } diff --git a/mastodon/src/main/res/menu/post.xml b/mastodon/src/main/res/menu/post.xml index b78f16622..9b876f64c 100644 --- a/mastodon/src/main/res/menu/post.xml +++ b/mastodon/src/main/res/menu/post.xml @@ -5,6 +5,7 @@ + diff --git a/mastodon/src/main/res/values/strings_sk.xml b/mastodon/src/main/res/values/strings_sk.xml index 6c31bd8d2..be97d90e6 100644 --- a/mastodon/src/main/res/values/strings_sk.xml +++ b/mastodon/src/main/res/values/strings_sk.xml @@ -92,4 +92,6 @@ Reblog with visibility Post about this Hashtags you follow - + Copy link to post + Open in other account + \ No newline at end of file From 6d8ecab7667146c87c2f2c6fafdd07db6429074d Mon Sep 17 00:00:00 2001 From: benjaminwolkchen Date: Fri, 23 Dec 2022 14:33:19 +0000 Subject: [PATCH 031/133] Translated using Weblate (German) Currently translated at 98.8% (85 of 86 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/ --- mastodon/src/main/res/values-de-rDE/strings_sk.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mastodon/src/main/res/values-de-rDE/strings_sk.xml b/mastodon/src/main/res/values-de-rDE/strings_sk.xml index 5d451de1e..5150539ff 100644 --- a/mastodon/src/main/res/values-de-rDE/strings_sk.xml +++ b/mastodon/src/main/res/values-de-rDE/strings_sk.xml @@ -82,4 +82,6 @@ %s unterstützt Übersetzung! %s scheint keine Übersetzung zu unterstützen. Es wird im Fediverse nachgeschlagen… + Reblog rückgängig machen + Rebloggen mit Sichtbarkeit \ No newline at end of file From 21f40e5b421ddc11d6591afc7387a02fa65ebb32 Mon Sep 17 00:00:00 2001 From: ling0412 Date: Fri, 23 Dec 2022 02:32:04 +0000 Subject: [PATCH 032/133] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (86 of 86 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/ --- .../src/main/res/values-zh-rCN/strings_sk.xml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/mastodon/src/main/res/values-zh-rCN/strings_sk.xml b/mastodon/src/main/res/values-zh-rCN/strings_sk.xml index 3d6dc13f6..c6a8ba180 100644 --- a/mastodon/src/main/res/values-zh-rCN/strings_sk.xml +++ b/mastodon/src/main/res/values-zh-rCN/strings_sk.xml @@ -47,4 +47,42 @@ 嘟文 嘟文通知 + 翻译 + 显示原文 + 允许多选 + 鲨鱼向你致敬!要想开始,请在下面输入你的账户所在实例的域名。 + 欢迎! + 清除最近使用的语言 + 您确定要清除最近使用的语言吗? + 使用 %s 翻译 + 语言: %s + 可用语言 + %s (%s) + example.social + 禁用选项卡之间的滑动 + 设置个人资料 + 发布偏好 + 配置过滤器 + 安全设置 + 规则 + 关于应用程序 + 捐赠 + 系统 + + 您确定要删除此通知吗? + 启用删除通知 + 删除通知 + 删除通知 + 发布按钮文本 + 自定义发布按钮文本 + 在时间轴中隐藏翻译按钮 + %s 支持翻译! + %s 似乎不支持翻译。 + 清除所有通知 + 删除所有 + 您确定要清除所有通知吗? + 在 Fediverse 上查找它…… + 撤销转发 + 转发可见性 + 关于这个嘟文 \ No newline at end of file From 3464cb4a05fa67055c4de96d90ee5bbc53ab8d77 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Thu, 22 Dec 2022 20:06:10 +0000 Subject: [PATCH 033/133] Translated using Weblate (Spanish) Currently translated at 100.0% (86 of 86 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/ --- mastodon/src/main/res/values-es-rES/strings_sk.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mastodon/src/main/res/values-es-rES/strings_sk.xml b/mastodon/src/main/res/values-es-rES/strings_sk.xml index 34ee34c2b..82d28a5c6 100644 --- a/mastodon/src/main/res/values-es-rES/strings_sk.xml +++ b/mastodon/src/main/res/values-es-rES/strings_sk.xml @@ -82,4 +82,7 @@ ¡%s admite traducción! %s no parece soportar la traducción. Buscándolo en Fediverse… + Publicar sobre esto + Deshacer reblogueo + Rebloguea con visibilidad \ No newline at end of file From c3ec64d1ffc54c399fd2fa9a94eb2a91ac76bf7b Mon Sep 17 00:00:00 2001 From: Choukajohn Date: Thu, 22 Dec 2022 16:08:48 +0000 Subject: [PATCH 034/133] Translated using Weblate (French) Currently translated at 100.0% (86 of 86 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/ --- mastodon/src/main/res/values-fr-rFR/strings_sk.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mastodon/src/main/res/values-fr-rFR/strings_sk.xml b/mastodon/src/main/res/values-fr-rFR/strings_sk.xml index a6c1c5d44..4df910701 100644 --- a/mastodon/src/main/res/values-fr-rFR/strings_sk.xml +++ b/mastodon/src/main/res/values-fr-rFR/strings_sk.xml @@ -82,4 +82,7 @@ %s ne semble pas prendre en charge la traduction. Voulez-vous vraiment supprimer toutes les notifications \? Le rechercher sur le Fediverse… + Rebloguer avec visibilité + Annuler le reblogage + Poster à ce sujet \ No newline at end of file From 7b40bc157d3c69a5480361ba54c5667223608db8 Mon Sep 17 00:00:00 2001 From: Linerly Date: Fri, 23 Dec 2022 08:50:43 +0000 Subject: [PATCH 035/133] Translated using Weblate (Indonesian) Currently translated at 100.0% (86 of 86 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/ --- mastodon/src/main/res/values-in-rID/strings_sk.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mastodon/src/main/res/values-in-rID/strings_sk.xml b/mastodon/src/main/res/values-in-rID/strings_sk.xml index 23ace7a36..1b5795501 100644 --- a/mastodon/src/main/res/values-in-rID/strings_sk.xml +++ b/mastodon/src/main/res/values-in-rID/strings_sk.xml @@ -82,4 +82,7 @@ Preferensi kiriman Pengaturan keamanan Hapus semua notifikasi + Urungkan pembagian + Kirim tentang ini + Bagikan dengan keterlihatan \ No newline at end of file From d919827bc8942e2795df80e56a3abb65e1d71a97 Mon Sep 17 00:00:00 2001 From: nitrogenez Date: Fri, 23 Dec 2022 15:58:15 +0000 Subject: [PATCH 036/133] Translated using Weblate (Ukrainian) Currently translated at 100.0% (86 of 86 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/ --- .../src/main/res/values-uk-rUA/strings_sk.xml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mastodon/src/main/res/values-uk-rUA/strings_sk.xml b/mastodon/src/main/res/values-uk-rUA/strings_sk.xml index ca3b5755c..3b4796303 100644 --- a/mastodon/src/main/res/values-uk-rUA/strings_sk.xml +++ b/mastodon/src/main/res/values-uk-rUA/strings_sk.xml @@ -59,4 +59,30 @@ example.social Вітаємо! Акулка вас вітає! Щоб розпочати, введіть нижче доменне ім’я вашого інстансу. + Налаштувати профіль + Налаштувати постинг + Налаштувати фільтри + Правила + Про застосунок + Донат + Системна + Червона + Видалити сповіщення + Видалити + Ви впевнені, що хочете видалити це сповіщення\? + Увімкнути видалення сповіщень + Текст кнопки \"опублікувати\" + Змінити текст кнопки \"опублікувати\" + Сховати кнопку \"перекласти\" у стрічці + %s підтримує переклад! + %s не підтримує переклад. + Очистити всі сповіщення + Ви впевнені, що хочете очистити всі сповіщення\? + Переглядаємо Федісвіт… + Скасувати репост + Репост з видимістю + Цитувати пост + Вимкнути перегортання вкладок + Налаштування безпеці + Видалити все \ No newline at end of file From 5414f5cf415e58592ff6eee532709895372d346f Mon Sep 17 00:00:00 2001 From: ling0412 Date: Fri, 23 Dec 2022 03:01:15 +0000 Subject: [PATCH 037/133] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (10 of 10 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/zh_Hans/ --- metadata/zh-Hans/changelogs/50.txt | 4 ++++ metadata/zh-Hans/changelogs/51.txt | 6 ++++++ metadata/zh-Hans/changelogs/55.txt | 4 ++++ metadata/zh-Hans/changelogs/56.txt | 6 ++++++ metadata/zh-Hans/changelogs/59.txt | 6 ++++++ metadata/zh-Hans/changelogs/61.txt | 5 +++++ metadata/zh-Hans/changelogs/62.txt | 11 +++++++++++ metadata/zh-Hans/full_description.txt | 15 +++++++++++++++ 8 files changed, 57 insertions(+) create mode 100644 metadata/zh-Hans/changelogs/50.txt create mode 100644 metadata/zh-Hans/changelogs/51.txt create mode 100644 metadata/zh-Hans/changelogs/55.txt create mode 100644 metadata/zh-Hans/changelogs/56.txt create mode 100644 metadata/zh-Hans/changelogs/59.txt create mode 100644 metadata/zh-Hans/changelogs/61.txt create mode 100644 metadata/zh-Hans/changelogs/62.txt create mode 100644 metadata/zh-Hans/full_description.txt diff --git a/metadata/zh-Hans/changelogs/50.txt b/metadata/zh-Hans/changelogs/50.txt new file mode 100644 index 000000000..f2391a479 --- /dev/null +++ b/metadata/zh-Hans/changelogs/50.txt @@ -0,0 +1,4 @@ +- 准备文件以便在F-Droid上发布 +- 修复自动更新程序 +- 将单色图标重新添加到启动器图标 +- 替换发布页脚中错误的不公开图标 diff --git a/metadata/zh-Hans/changelogs/51.txt b/metadata/zh-Hans/changelogs/51.txt new file mode 100644 index 000000000..6c5d221b8 --- /dev/null +++ b/metadata/zh-Hans/changelogs/51.txt @@ -0,0 +1,6 @@ +- 使得在回复时可以打开原帖(通过点击 "回复...... "一行)。 +- 合并上游的修改和错误修正 +- 删除未使用的 "App Center" 代码 +- 为Play Store添加没有联邦时间轴的版本 +- 添加自定义重定向URI以方便登录 +- 更改贡献链接 diff --git a/metadata/zh-Hans/changelogs/55.txt b/metadata/zh-Hans/changelogs/55.txt new file mode 100644 index 000000000..8020dbd53 --- /dev/null +++ b/metadata/zh-Hans/changelogs/55.txt @@ -0,0 +1,4 @@ +- 修复损坏的 HTML 标签并启用以 Markdown 格式呈现 +- 初始化 Weblate 翻译项目 +- 为联邦时间线添加切换 +- 版本 52-54 是针对 Google Play 版本的小幅调整 diff --git a/metadata/zh-Hans/changelogs/56.txt b/metadata/zh-Hans/changelogs/56.txt new file mode 100644 index 000000000..c50c861d1 --- /dev/null +++ b/metadata/zh-Hans/changelogs/56.txt @@ -0,0 +1,6 @@ +- @LucasGGamerM 自定义颜色主题 +- 由@LucasGGamerM 提交的新“megalodon”文字标识 +- 创作时更好的表情符号搜索 +- 调整投票(显示自己的投票,始终显示投票按钮,不要切断长答案) +- 为嘟文通知添加推送通知设置 +- Bug修复 diff --git a/metadata/zh-Hans/changelogs/59.txt b/metadata/zh-Hans/changelogs/59.txt new file mode 100644 index 000000000..75073abff --- /dev/null +++ b/metadata/zh-Hans/changelogs/59.txt @@ -0,0 +1,6 @@ +- 添加语言选择器 +- 添加翻译功能 +- 改进投票投票的语义(单选按钮和复选框) +- 添加选项以允许对民意调查中的多个选项进行投票 +- 新的登录屏幕 +- Bug修复 diff --git a/metadata/zh-Hans/changelogs/61.txt b/metadata/zh-Hans/changelogs/61.txt new file mode 100644 index 000000000..9e4f1093b --- /dev/null +++ b/metadata/zh-Hans/changelogs/61.txt @@ -0,0 +1,5 @@ +- 新的颜色主题:Material You 和 红 +- 所有主题的新深灰色调 +- 更明显的填充提升图标 +- 交互按钮的动画 +- 错误修正(某些嘟文崩溃,“列表为”,默认发布语言) diff --git a/metadata/zh-Hans/changelogs/62.txt b/metadata/zh-Hans/changelogs/62.txt new file mode 100644 index 000000000..275b04e27 --- /dev/null +++ b/metadata/zh-Hans/changelogs/62.txt @@ -0,0 +1,11 @@ +- 可定制的发布按钮 +- 在应用程序中打开 Fediverse 链接 +- 长按转发按钮以“引用”嘟文 +- 长按分享按钮时复制帖子网址 +- 实施删除通知(默认禁用) +- 不同通知类型的专用图标 +- 新的灰色 +- 添加设置以禁用选项卡之间的滑动 +- 添加各种链接到帐户设置 +- 切换显示/隐藏时间轴中的翻译按钮 +- 错误修正和调整 diff --git a/metadata/zh-Hans/full_description.txt b/metadata/zh-Hans/full_description.txt new file mode 100644 index 000000000..e0dee3ce1 --- /dev/null +++ b/metadata/zh-Hans/full_description.txt @@ -0,0 +1,15 @@ +Megalodon 是官方 Mastodon Android 应用的修改版本,添加了官方应用中缺少的重要功能,例如联合时间轴、不公开的帖子和图像描述查看器。 + +主要特点 + +- 不公开的帖子:公开发布而不让您的帖子出现在趋势、标签或公共时间轴中。 +- 联邦时间轴:查看您的实例连接到的所有其他 Fediverse 社区的人们的所有公开帖子。 +- 图片描述查看器:快速检查图片或视频是否附加了替代文字。 +- 置顶帖子:将您最重要的帖子置顶到您的个人资料,并使用“置顶”选项卡查看其他人固定的内容。 +- 关注话题标签:通过关注直接在您的主页时间线中查看来自特定话题标签的新帖子。 +- 回应关注请求:接受或拒绝来自您的通知或专用关注请求列表的关注请求。 +- 删除和重新起草:这个备受喜爱的功能使编辑成为可能,而无需实际的编辑功能。 +- 语言选择器:为您发布的每个帖子轻松选择语言,以便过滤器和翻译正常工作。 +- 翻译:在 Megalodon 内轻松翻译帖子! 该功能仅在在您的 Mastodon Web 上也可用时才有效。 +- 帖子可见性指示器:打开或回复帖子时,将显示一个指示帖子可见性的便捷图标。 +- 颜色主题:如果您不喜欢默认的粉红色(鲨鱼在默默地评判您),Moshidon 的颜色主题可以满足您的需求。 From f4596998aa2c972f6b918bbf9b73da698f5e7ca2 Mon Sep 17 00:00:00 2001 From: nitrogenez Date: Fri, 23 Dec 2022 16:14:18 +0000 Subject: [PATCH 038/133] Translated using Weblate (Ukrainian) Currently translated at 90.0% (9 of 10 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/ --- metadata/uk/changelogs/61.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 metadata/uk/changelogs/61.txt diff --git a/metadata/uk/changelogs/61.txt b/metadata/uk/changelogs/61.txt new file mode 100644 index 000000000..27fe306f6 --- /dev/null +++ b/metadata/uk/changelogs/61.txt @@ -0,0 +1,5 @@ +- Нові колірні теми: Material You й Червона +- Нові темно-сірі тони для всіх тем +- Більш виразний заповнений значок репоста +- Анімації для кнопок взаємодій +- Виправлення багів (виліт на деякіх постах, тощо) From c719ac22da6107896ce8589e6a59dcfb4d17f25b Mon Sep 17 00:00:00 2001 From: sk Date: Fri, 23 Dec 2022 17:35:16 -0300 Subject: [PATCH 039/133] improve settings items --- .../src/main/res/layout/item_settings_button.xml | 14 +++++++++----- .../src/main/res/layout/item_settings_switch.xml | 4 +++- .../src/main/res/layout/item_settings_text.xml | 2 +- .../src/main/res/values-de-rDE/strings_sk.xml | 16 +++++++--------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/mastodon/src/main/res/layout/item_settings_button.xml b/mastodon/src/main/res/layout/item_settings_button.xml index ea16648d8..0a4afebd8 100644 --- a/mastodon/src/main/res/layout/item_settings_button.xml +++ b/mastodon/src/main/res/layout/item_settings_button.xml @@ -1,11 +1,10 @@ - @@ -13,6 +12,7 @@ android:id="@+id/icon" android:layout_width="24dp" android:layout_height="24dp" + android:layout_marginStart="16dp" android:layout_marginEnd="32dp" android:importantForAccessibility="no" android:tint="?android:textColorPrimary" @@ -21,10 +21,11 @@ @@ -33,6 +34,9 @@ android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="32dp" + android:layout_weight="0" + android:layout_marginEnd="16dp" + android:maxWidth="140dp" android:background="@drawable/bg_inline_button" android:elevation="0dp" android:ellipsize="middle" diff --git a/mastodon/src/main/res/layout/item_settings_switch.xml b/mastodon/src/main/res/layout/item_settings_switch.xml index 3dec2e11e..6aa91e4dc 100644 --- a/mastodon/src/main/res/layout/item_settings_switch.xml +++ b/mastodon/src/main/res/layout/item_settings_switch.xml @@ -3,7 +3,8 @@ xmlns:tools="http://schemas.android.com/tools" android:orientation="horizontal" android:layout_width="match_parent" - android:layout_height="48dp" + android:layout_height="wrap_content" + android:minHeight="48dp" android:gravity="center_vertical" android:layoutDirection="locale"> @@ -22,6 +23,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:paddingVertical="8dp" android:textSize="16sp" android:textColor="?android:textColorPrimary" tools:text="@string/theme_true_black"/> diff --git a/mastodon/src/main/res/layout/item_settings_text.xml b/mastodon/src/main/res/layout/item_settings_text.xml index 923291dbc..bdd90d9ea 100644 --- a/mastodon/src/main/res/layout/item_settings_text.xml +++ b/mastodon/src/main/res/layout/item_settings_text.xml @@ -5,6 +5,7 @@ android:paddingHorizontal="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="48dp" android:gravity="center_vertical" android:layoutDirection="locale"> Laufschrift in Titelleisten deaktivieren Zu Megalodon beitragen Föderierte Timeline anzeigen - Beitrags-Benachrichtigungen + Beitrags-​Benachrichtigungen Farbschema Pink Violett @@ -58,13 +58,13 @@ Zuletzt verwendete Sprachen leeren Willkommen! beispiel.social - Der Hai sagt Hi! Um anzufangen, bitte gib den Domain-Namen deiner Heim-Instanz unten ein. + Der Hai sagt Hi! Um anzufangen, bitte gib den Domain-​Namen deiner Heim-Instanz unten ein. System Rot Profil einrichten Einstellungen für Beiträge Filter konfigurieren - Sicherheitseinstellungen + Sicherheits-​Einstellungen Regelwerk Über die App Spenden @@ -73,15 +73,13 @@ Benachrichtigung wirklich löschen\? Alle löschen Löschen von Benachrichtigungen aktivieren - Veröffentlichen-Button-Text - Übersetzen-Button in der Timeline ausblenden + Veröffentlichen-​Button-​Text + Übersetzen-​Button in der Timeline ausblenden Benachrichtigung löschen Alle Benachrichtigungen löschen - Veröffentlichen-Button-Text anpassen + Veröffentlichen-​Button-​Text anpassen Wirklich alle Benachrichtigungen löschen\? %s unterstützt Übersetzung! %s scheint keine Übersetzung zu unterstützen. - Es wird im Fediverse nachgeschlagen… - Reblog rückgängig machen - Rebloggen mit Sichtbarkeit + Suche im Fediverse… \ No newline at end of file From 315bcd5b1a514696dea973939dc735be18384394 Mon Sep 17 00:00:00 2001 From: sk Date: Fri, 23 Dec 2022 21:49:21 +0100 Subject: [PATCH 040/133] fix instance info v2 never getting saved --- .../api/session/AccountSessionManager.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java index 1db989f94..2a3dea401 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java @@ -13,8 +13,6 @@ import android.net.Uri; import android.os.Build; import android.util.Log; -import com.google.gson.JsonParseException; - import org.joinmastodon.android.BuildConfig; import org.joinmastodon.android.E; import org.joinmastodon.android.MainActivity; @@ -104,12 +102,11 @@ public class AccountSessionManager{ public void addAccount(Instance instance, Token token, Account self, Application app, AccountActivationInfo activationInfo){ instances.put(instance.uri, instance); - updateInstanceInfoV2(instance); AccountSession session=new AccountSession(token, self, app, instance.uri, activationInfo==null, activationInfo); sessions.put(session.getID(), session); lastActiveAccountID=session.getID(); writeAccountsFile(); - updateInstanceEmojis(instance, instance.uri); + updateMoreInstanceInfo(instance, instance.uri); if(PushSubscriptionManager.arePushNotificationsAvailable()){ session.getPushSubscriptionManager().registerAccountForPush(null); } @@ -328,10 +325,7 @@ public class AccountSessionManager{ @Override public void onSuccess(Instance instance){ instances.put(domain, instance); - updateInstanceEmojis(instance, domain); - try { - updateInstanceInfoV2(instance); - } catch (Exception ignored) {} + updateMoreInstanceInfo(instance, domain); } @Override @@ -342,16 +336,18 @@ public class AccountSessionManager{ .execNoAuth(domain); } - public void updateInstanceInfoV2(Instance instance) { + public void updateMoreInstanceInfo(Instance instance, String domain) { new GetInstance.V2().setCallback(new Callback<>() { @Override public void onSuccess(Instance.V2 v2) { if (instance != null) instance.v2 = v2; - writeAccountsFile(); + updateInstanceEmojis(instance, domain); } @Override - public void onError(ErrorResponse errorResponse) {} + public void onError(ErrorResponse errorResponse) { + updateInstanceEmojis(instance, domain); + } }).execNoAuth(instance.uri); } From 444a9afabe3570f47a3d7240875dc228d50e9361 Mon Sep 17 00:00:00 2001 From: sk Date: Fri, 23 Dec 2022 22:59:06 +0100 Subject: [PATCH 041/133] disable block domain from post --- .../ui/displayitems/HeaderStatusDisplayItem.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java index 729033922..4a9645fd0 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java @@ -350,12 +350,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ mute.setTitle(item.parentFragment.getString(relationship!=null && relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername())); block.setTitle(item.parentFragment.getString(relationship!=null && relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername())); report.setTitle(item.parentFragment.getString(R.string.report_user, account.getDisplayUsername())); - if(!account.isLocal()){ - blockDomain.setVisible(true); - blockDomain.setTitle(item.parentFragment.getString(relationship!=null && relationship.domainBlocking ? R.string.unblock_domain : R.string.block_domain, account.getDomain())); - }else{ + // disabled in megalodon. domain blocks from a post clutters the context menu and looks out of place +// if(!account.isLocal()){ +// blockDomain.setVisible(true); +// blockDomain.setTitle(item.parentFragment.getString(relationship!=null && relationship.domainBlocking ? R.string.unblock_domain : R.string.block_domain, account.getDomain())); +// }else{ blockDomain.setVisible(false); - } +// } follow.setTitle(item.parentFragment.getString(relationship!=null && relationship.following ? R.string.unfollow_user : R.string.follow_user, account.getDisplayUsername())); } } From 98707dde76dfd1d5697a9741da5d6f899812de74 Mon Sep 17 00:00:00 2001 From: Choukajohn Date: Fri, 23 Dec 2022 20:28:41 +0000 Subject: [PATCH 042/133] Translated using Weblate (French) Currently translated at 100.0% (89 of 89 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/ --- mastodon/src/main/res/values-fr-rFR/strings_sk.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mastodon/src/main/res/values-fr-rFR/strings_sk.xml b/mastodon/src/main/res/values-fr-rFR/strings_sk.xml index 4df910701..302ec33c9 100644 --- a/mastodon/src/main/res/values-fr-rFR/strings_sk.xml +++ b/mastodon/src/main/res/values-fr-rFR/strings_sk.xml @@ -85,4 +85,7 @@ Rebloguer avec visibilité Annuler le reblogage Poster à ce sujet + Hashtags que vous suivez + Ouvrir dans un autre compte + Copier le lien du post \ No newline at end of file From df73c5ad8dc66d2092911abb864e3513690db072 Mon Sep 17 00:00:00 2001 From: Linerly Date: Fri, 23 Dec 2022 19:24:13 +0000 Subject: [PATCH 043/133] Translated using Weblate (Indonesian) Currently translated at 100.0% (89 of 89 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/ --- mastodon/src/main/res/values-in-rID/strings_sk.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mastodon/src/main/res/values-in-rID/strings_sk.xml b/mastodon/src/main/res/values-in-rID/strings_sk.xml index 1b5795501..5beaf1fb9 100644 --- a/mastodon/src/main/res/values-in-rID/strings_sk.xml +++ b/mastodon/src/main/res/values-in-rID/strings_sk.xml @@ -85,4 +85,7 @@ Urungkan pembagian Kirim tentang ini Bagikan dengan keterlihatan + Salin tautan ke kiriman + Buka di akun lain + Tagar yang Anda ikuti \ No newline at end of file From 9e88e28a59f45a25fb60c4ada6d2bddb8e0f3136 Mon Sep 17 00:00:00 2001 From: Choukajohn Date: Fri, 23 Dec 2022 20:32:33 +0000 Subject: [PATCH 044/133] Translated using Weblate (French) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/ --- metadata/fr-FR/changelogs/63.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 metadata/fr-FR/changelogs/63.txt diff --git a/metadata/fr-FR/changelogs/63.txt b/metadata/fr-FR/changelogs/63.txt new file mode 100644 index 000000000..fff803b6a --- /dev/null +++ b/metadata/fr-FR/changelogs/63.txt @@ -0,0 +1,3 @@ +- Rebloguer avec une visibilité spécifique sur clic long +- Liste des hashtags suivis +- Cliquez longuement sur les liens pour les copier From 8a72c5b9cafdc66e5648434bf686e3075308da7d Mon Sep 17 00:00:00 2001 From: Linerly Date: Fri, 23 Dec 2022 19:25:40 +0000 Subject: [PATCH 045/133] Translated using Weblate (Indonesian) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/ --- metadata/id/changelogs/63.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 metadata/id/changelogs/63.txt diff --git a/metadata/id/changelogs/63.txt b/metadata/id/changelogs/63.txt new file mode 100644 index 000000000..5237cea43 --- /dev/null +++ b/metadata/id/changelogs/63.txt @@ -0,0 +1,3 @@ +- Bagikan dengan keterlihatan khusu pada klik lama +- Daftar tagar yang diikuti +- Klik lama pada tautan untuk menyalinnya From 411e39a0964b777bea57377bf0a4a30246323d0e Mon Sep 17 00:00:00 2001 From: sk Date: Fri, 23 Dec 2022 23:39:51 +0100 Subject: [PATCH 046/133] fix default reblog visibility --- .../ui/displayitems/FooterStatusDisplayItem.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java index 62a4615ff..da92f4499 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java @@ -216,6 +216,16 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ Drawable followersDrawable = ctx.getDrawable(R.drawable.ic_fluent_people_checkmark_24_regular); StatusPrivacy defaultVisibility = session.preferences.postingDefaultVisibility; + // e.g. post visibility is unlisted, but default is public + // in this case, we want to display the check mark on the most visible visibility + if (item.status.visibility.isLessVisibleThan(defaultVisibility)) { + for (StatusPrivacy vis : StatusPrivacy.values()) { + if (vis.equals(item.status.visibility)) { + defaultVisibility = vis; + break; + } + } + } itemPublic.setCompoundDrawablesWithIntrinsicBounds(publicDrawable, null, StatusPrivacy.PUBLIC.equals(defaultVisibility) ? checkMark : null, null); itemUnlisted.setCompoundDrawablesWithIntrinsicBounds(unlistedDrawable, null, StatusPrivacy.UNLISTED.equals(defaultVisibility) ? checkMark : null, null); itemFollowers.setCompoundDrawablesWithIntrinsicBounds(followersDrawable, null, StatusPrivacy.PRIVATE.equals(defaultVisibility) ? checkMark : null, null); From 14786f796bbcef570c9c1000e8cb1107b4d7fd39 Mon Sep 17 00:00:00 2001 From: sk22 Date: Fri, 23 Dec 2022 19:25:55 -0300 Subject: [PATCH 047/133] Translated using Weblate (German) Currently translated at 100.0% (91 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/ --- mastodon/src/main/res/values-de-rDE/strings_sk.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/res/values-de-rDE/strings_sk.xml b/mastodon/src/main/res/values-de-rDE/strings_sk.xml index 92e7b2ee9..4944ff434 100644 --- a/mastodon/src/main/res/values-de-rDE/strings_sk.xml +++ b/mastodon/src/main/res/values-de-rDE/strings_sk.xml @@ -81,5 +81,13 @@ Wirklich alle Benachrichtigungen löschen\? %s unterstützt Übersetzung! %s scheint keine Übersetzung zu unterstützen. - Suche im Fediverse… + Suche im Fediverse + Reblog rückgängig machen + Rebloggen mit Sichtbarkeit + Drüberkommentieren + Hashtags, denen du folgst + Link zum Beitrag kopieren + Mit anderem Konto öffnen + Ressource nicht gefunden + Suche auf %s \ No newline at end of file From 027f19e710bf35db7264fd788b416cb736c26801 Mon Sep 17 00:00:00 2001 From: ling0412 Date: Fri, 23 Dec 2022 22:28:16 +0000 Subject: [PATCH 048/133] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (91 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/ --- mastodon/src/main/res/values-zh-rCN/strings_sk.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/res/values-zh-rCN/strings_sk.xml b/mastodon/src/main/res/values-zh-rCN/strings_sk.xml index c6a8ba180..16e7e1ea9 100644 --- a/mastodon/src/main/res/values-zh-rCN/strings_sk.xml +++ b/mastodon/src/main/res/values-zh-rCN/strings_sk.xml @@ -81,8 +81,13 @@ 清除所有通知 删除所有 您确定要清除所有通知吗? - 在 Fediverse 上查找它…… + 在 Fediverse 上查找它 撤销转发 转发可见性 关于这个嘟文 + 复制链接到嘟文 + 您关注的标签 + 在 %s 上查找 + 找不到资源 + 用另一个帐户打开 \ No newline at end of file From 9f729e9ef07d261e3de64f3b6195c405009f258d Mon Sep 17 00:00:00 2001 From: Pointifurry Date: Sat, 24 Dec 2022 00:40:25 +0000 Subject: [PATCH 049/133] Translated using Weblate (Spanish) Currently translated at 100.0% (91 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/ --- mastodon/src/main/res/values-es-rES/strings_sk.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/res/values-es-rES/strings_sk.xml b/mastodon/src/main/res/values-es-rES/strings_sk.xml index 82d28a5c6..ade655bf0 100644 --- a/mastodon/src/main/res/values-es-rES/strings_sk.xml +++ b/mastodon/src/main/res/values-es-rES/strings_sk.xml @@ -81,8 +81,13 @@ ¿Estás seguro de que quieres borrar todas las notificaciones\? ¡%s admite traducción! %s no parece soportar la traducción. - Buscándolo en Fediverse… + Buscándolo en el Fediverso Publicar sobre esto Deshacer reblogueo Rebloguea con visibilidad + Hashtags que sigues + Copiar enlace a la publicación + Abrir con otra cuenta + El recurso no se pudo encontrar + Buscándolo en %s \ No newline at end of file From 852f666b78fc92e02423f8618d2329973275a27b Mon Sep 17 00:00:00 2001 From: Choukajohn Date: Sat, 24 Dec 2022 00:36:18 +0000 Subject: [PATCH 050/133] Translated using Weblate (French) Currently translated at 100.0% (91 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/ --- mastodon/src/main/res/values-fr-rFR/strings_sk.xml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mastodon/src/main/res/values-fr-rFR/strings_sk.xml b/mastodon/src/main/res/values-fr-rFR/strings_sk.xml index 302ec33c9..f93057f30 100644 --- a/mastodon/src/main/res/values-fr-rFR/strings_sk.xml +++ b/mastodon/src/main/res/values-fr-rFR/strings_sk.xml @@ -81,11 +81,14 @@ %s prend en charge la traduction ! %s ne semble pas prendre en charge la traduction. Voulez-vous vraiment supprimer toutes les notifications \? - Le rechercher sur le Fediverse… - Rebloguer avec visibilité - Annuler le reblogage + Rechercher sur le Fediverse + Reposter avec la visibilité + Annuler le repost Poster à ce sujet Hashtags que vous suivez Ouvrir dans un autre compte - Copier le lien du post + Copier le lien du message + Rechercher sur %s + Ouvrir avec un autre compte + La ressource est introuvable \ No newline at end of file From d031acabf5ec0b76e7e4ab5794d4f2a942f4fd6a Mon Sep 17 00:00:00 2001 From: Linerly Date: Fri, 23 Dec 2022 22:41:14 +0000 Subject: [PATCH 051/133] Translated using Weblate (Indonesian) Currently translated at 100.0% (91 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/ --- mastodon/src/main/res/values-in-rID/strings_sk.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/res/values-in-rID/strings_sk.xml b/mastodon/src/main/res/values-in-rID/strings_sk.xml index 5beaf1fb9..9d343aa42 100644 --- a/mastodon/src/main/res/values-in-rID/strings_sk.xml +++ b/mastodon/src/main/res/values-in-rID/strings_sk.xml @@ -71,7 +71,7 @@ %s mendukung penerjemahan! %s sepertinya tidak mendukung penerjemahan. Apakah Anda yakin ingin menghapus semua notifikasi\? - Mencari di Fedimesta… + Mencari di Fedimesta Aturan Tentang aplikasi Donasi @@ -88,4 +88,7 @@ Salin tautan ke kiriman Buka di akun lain Tagar yang Anda ikuti + Buka dengan akun lain + Mencari di %s + Sumber daya tidak dapat ditemukan \ No newline at end of file From 6653dd97a647af30eaace1328c5be612cc2bbd3b Mon Sep 17 00:00:00 2001 From: goliv Date: Sun, 25 Dec 2022 06:08:25 -0300 Subject: [PATCH 052/133] Translated using Weblate (Portuguese (Brazil)) Currently translated at 74.7% (68 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/ --- .../src/main/res/values-pt-rBR/strings_sk.xml | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/mastodon/src/main/res/values-pt-rBR/strings_sk.xml b/mastodon/src/main/res/values-pt-rBR/strings_sk.xml index 525ac2d61..7d294b71f 100644 --- a/mastodon/src/main/res/values-pt-rBR/strings_sk.xml +++ b/mastodon/src/main/res/values-pt-rBR/strings_sk.xml @@ -7,7 +7,7 @@ Fixar postagem no perfil Você deseja fixar esta postagem em seu perfil\? Fixando postagem… - Moshidon + Megalodon Fixado Desafixar do perfil Desafixar postagem do perfil @@ -18,13 +18,13 @@ Mostrar boosts Carregar novas postagens automaticamente Marcar mídia como sensível - Moshidon v%1$s (%2$d) + Megalodon v%1$s (%2$d) Listas com %s Ativar as notificações de postagem para %s Federação Estas são as postagens mais recentes das pessoas em sua federação. - Moshidon %s está pronto para baixar. - Moshidon %s foi baixado e está pronto para instalar. + Megalodon %s está pronto para baixar. + Megalodon %s foi baixado e está pronto para instalar. Verificar se há atualizações Nenhuma atualização disponível Listas @@ -34,18 +34,18 @@ Recusar solicitação para seguir Sempre revelar avisos de conteúdo Desative o texto de rolagem nas barras de título - Contribua para o Moshidon + Contribua para o Megalodon Mostre a linha do tempo federada Não-listado Mostrar contagens de interação - Roxo - Verde - Azul - Marrom - Amarelo - Rosa + Roxo + Verde + Azul + Marrom + Amarelo + Rosa Postagens - Cor do tema + Cor do tema Traduzir Mostrar original Traduzido usando %s @@ -59,6 +59,32 @@ O tubarão te cumprimenta! Para começar, por favor, digite abaixo o nome de domínio de sua instância de origem. exemplo.social Bem vindo! - Sistema - Vermelho + Sistema + Vermelho + Doe + Regras + Desativar deslizamento entre as abas + Criar um perfil + Preferências de postagem + Configurar filtros + Tem certeza que quer deletar esta notificação\? + Deletar notificação + Deletar notificação + Habilitar deletar notificações + Customizar o texto do botão de publicar + Esconder botão de tradução na linha do tempo + %s possui tradução! + %s parece que não possui tradução + Limpar todas as notificações + Deletar todas + Procurando no Fediverso + Desfazer reblog + Reblog com visibilidade + Hashtags que você segue + Copiar link para postagem + Procurando no %s + Abrir com outra conta + Recurso não pode ser encontrado + Sobre o app + Configurações de segurança \ No newline at end of file From 74efc5c3327786149bc39cc0307114d305a83c69 Mon Sep 17 00:00:00 2001 From: itslameni Date: Sat, 24 Dec 2022 05:39:28 -0300 Subject: [PATCH 053/133] Translated using Weblate (Russian) Currently translated at 96.7% (88 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/ --- .../src/main/res/values-ru-rRU/strings_sk.xml | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/mastodon/src/main/res/values-ru-rRU/strings_sk.xml b/mastodon/src/main/res/values-ru-rRU/strings_sk.xml index 8848723e3..743093780 100644 --- a/mastodon/src/main/res/values-ru-rRU/strings_sk.xml +++ b/mastodon/src/main/res/values-ru-rRU/strings_sk.xml @@ -1,6 +1,6 @@ - Moshidon + Megalodon Закрепленные Удалить и исправить Удалить и исправить пост @@ -14,14 +14,14 @@ Описание изображения Скрытый Отметить медиафайл как деликатный - Moshidon v%1$s (%2$d) + Megalodon v%1$s (%2$d) Публикации Отправляет публикацию - Цветовая схема - Розовый - Фиолетовый - Коричневый - Жёлтый + Цветовая схема + Розовый + Фиолетовый + Коричневый + Жёлтый Показать оригинальную публикацию Переведено через %s Доступные языки @@ -31,8 +31,8 @@ Автоматически загружать новые публикации Показывать ответы на публикации Федерация - Moshidon %s готов к скачиванию. - Moshidon %s скачан и готов к установке новой версии. + Megalodon %s готов к скачиванию. + Megalodon %s скачан и готов к установке новой версии. Проверить обновления Запросы на подписку Списки с %s @@ -44,10 +44,10 @@ Принять запрос на подписку Отклонить заявку на подписку Всегда раскрывать предупреждения о непристойном контенте - Внести свой код в Moshidon + Внести свой код в Megalodon Показывать федеративную временную шкалу - Зелёный - Синий + Зелёный + Синий Перевести Язык: %s Очистить недавно использованные языки @@ -56,9 +56,35 @@ Разрешить несколько вариантов ответа Уведомления о постах %s включены Уведомления о новых постах %s отключены - Система + Система Показать репосты Показывать количество взаимодействий Отключить прокручиваемый текст в заголовках - Красный + Красный + Отключить жесты переключения между вкладками + Настроить профиль + Настройки публикации + Настройки фильтров + Настройки безопасности + Правила инстанса + О приложении + Задонатить + Удаление уведомления + Удалить уведомление + Вы точно хотите удалить это уведомление\? + Включить удаление уведомлений + Текст кнопки публикации + Настройка текста кнопки публикации + Спрятать кнопку перевода во временной шкале + %s поддерживает функцию перевода! + %s не имеет поддержки функции перевода. + Очистить все уведомления + Удалить все + Вы точно хотите удалить все уведомления\? + Отменить продвижение поста + Продвижение с видимостью + Создать публикацию об этом + Скопировать ссылку на публикацию + Открыть с другого аккаунта + Ресурс не был найден \ No newline at end of file From b277eb49903c847b9f5f463be38816388adfb51c Mon Sep 17 00:00:00 2001 From: nitrogenez Date: Sun, 25 Dec 2022 01:58:50 +0000 Subject: [PATCH 054/133] Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/ --- mastodon/src/main/res/values-uk-rUA/strings_sk.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/res/values-uk-rUA/strings_sk.xml b/mastodon/src/main/res/values-uk-rUA/strings_sk.xml index 3b4796303..5b103c062 100644 --- a/mastodon/src/main/res/values-uk-rUA/strings_sk.xml +++ b/mastodon/src/main/res/values-uk-rUA/strings_sk.xml @@ -78,11 +78,16 @@ %s не підтримує переклад. Очистити всі сповіщення Ви впевнені, що хочете очистити всі сповіщення\? - Переглядаємо Федісвіт… + Переглядаємо Федісвіт Скасувати репост Репост з видимістю Цитувати пост Вимкнути перегортання вкладок Налаштування безпеці Видалити все + Скопіювати посилання на пост + Відстежувані хештеги + Переглядаємо %s + Відкрити через інший акаунт + Ресурс не знайдено \ No newline at end of file From 6a4936853bb66b128e0ca2da563fd42f84591b5e Mon Sep 17 00:00:00 2001 From: Choukajohn Date: Sat, 24 Dec 2022 10:18:15 +0000 Subject: [PATCH 055/133] Translated using Weblate (French) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/ --- metadata/fr-FR/changelogs/63.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/metadata/fr-FR/changelogs/63.txt b/metadata/fr-FR/changelogs/63.txt index fff803b6a..3629944a7 100644 --- a/metadata/fr-FR/changelogs/63.txt +++ b/metadata/fr-FR/changelogs/63.txt @@ -1,3 +1,6 @@ -- Rebloguer avec une visibilité spécifique sur clic long -- Liste des hashtags suivis -- Cliquez longuement sur les liens pour les copier +- Possibilité de reposter avec une visibilité spécifique sur clic long +- Afficher la visibilité de ses propres reposts +- Ajout d'une liste de hashtags suivis +- Cliquer longuement pour copier les liens +- Possibilité d'ouvrir des messages avec un autre compte +- Corrections de bugs et ajustements mineurs From 1eb08e40be754ad498fb374dca4fc77803c32d3d Mon Sep 17 00:00:00 2001 From: ling0412 Date: Sat, 24 Dec 2022 02:13:38 +0000 Subject: [PATCH 056/133] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/zh_Hans/ --- metadata/zh-Hans/changelogs/63.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 metadata/zh-Hans/changelogs/63.txt diff --git a/metadata/zh-Hans/changelogs/63.txt b/metadata/zh-Hans/changelogs/63.txt new file mode 100644 index 000000000..2da7725e8 --- /dev/null +++ b/metadata/zh-Hans/changelogs/63.txt @@ -0,0 +1,6 @@ +- 长按时具有可见性的转发选项 +- 显示自己转发嘟文的可见性 +- 添加关注标签列表 +- 长按复制链接 +- 可以选择用其他账户打开帖子 +- 错误修复和小调整 From fedaaa6fc82476993a80ce1b83f18c30e216646b Mon Sep 17 00:00:00 2001 From: Linerly Date: Sat, 24 Dec 2022 03:28:31 +0000 Subject: [PATCH 057/133] Translated using Weblate (Indonesian) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/ --- metadata/id/changelogs/63.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/metadata/id/changelogs/63.txt b/metadata/id/changelogs/63.txt index 5237cea43..91823391a 100644 --- a/metadata/id/changelogs/63.txt +++ b/metadata/id/changelogs/63.txt @@ -1,3 +1,6 @@ -- Bagikan dengan keterlihatan khusu pada klik lama -- Daftar tagar yang diikuti +- Opsi untuk membagikan dengan keterlihatan khusus pada klik lama +- Tampilkan keterlihatan pembagian sendiri +- Ditambahkan daftar tagar yang diikuti - Klik lama pada tautan untuk menyalinnya +- Opsi untuk membuka kiriman dengan akun lain +- Perbaikan kutu dan perubahan kecil From 45952ef143e67190511af35e046a8a5964c0571c Mon Sep 17 00:00:00 2001 From: Pointifurry Date: Sun, 25 Dec 2022 00:46:09 +0000 Subject: [PATCH 058/133] Translated using Weblate (Spanish) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/ --- metadata/es/changelogs/63.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 metadata/es/changelogs/63.txt diff --git a/metadata/es/changelogs/63.txt b/metadata/es/changelogs/63.txt new file mode 100644 index 000000000..f73f665ae --- /dev/null +++ b/metadata/es/changelogs/63.txt @@ -0,0 +1,6 @@ +- Opción de rebloguear con visibilidad específica via clic-largo +- Mostrar visibilidad de reblogueos propios +- Añadir lista de hashtags seguidos +- Clic-largo para copiar enlaces +- Opción de abrir publicaciones con otra cuenta +- Corrección de errores y ajustes menores From 21f99081f2263da118da69c2c230bc9ecfb86d78 Mon Sep 17 00:00:00 2001 From: sk Date: Tue, 27 Dec 2022 17:02:05 -0300 Subject: [PATCH 059/133] long-click to compose from other account --- .../fragments/HashtagTimelineFragment.java | 2 + .../fragments/HomeTimelineFragment.java | 2 + .../fragments/ListTimelineFragment.java | 2 + .../android/fragments/ProfileFragment.java | 8 +- .../android/ui/utils/UiUtils.java | 148 ++++++++++++++++-- 5 files changed, 145 insertions(+), 17 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java index 6408a968d..74c3185ed 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java @@ -16,6 +16,7 @@ import org.joinmastodon.android.api.requests.tags.SetHashtagFollowed; import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline; import org.joinmastodon.android.model.Hashtag; import org.joinmastodon.android.model.Status; +import org.joinmastodon.android.ui.utils.UiUtils; import java.util.List; @@ -117,6 +118,7 @@ public class HashtagTimelineFragment extends StatusListFragment{ super.onViewCreated(view, savedInstanceState); fab=view.findViewById(R.id.fab); fab.setOnClickListener(this::onFabClick); + fab.setOnLongClickListener(v -> UiUtils.pickAccountForCompose(getActivity(), accountID, '#'+hashtag+' ')); } private void onFabClick(View v){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 0d01c041e..19c13e1c9 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -106,6 +106,8 @@ public class HomeTimelineFragment extends StatusListFragment{ super.onViewCreated(view, savedInstanceState); fab=view.findViewById(R.id.fab); fab.setOnClickListener(this::onFabClick); + fab.setOnLongClickListener(v->UiUtils.pickAccountForCompose(getActivity(), accountID, null)); + updateToolbarLogo(); list.addOnScrollListener(new RecyclerView.OnScrollListener(){ @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java index b81d98afb..9c88366ed 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java @@ -12,6 +12,7 @@ import android.widget.ImageButton; import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.timelines.GetListTimeline; import org.joinmastodon.android.model.Status; +import org.joinmastodon.android.ui.utils.UiUtils; import java.util.List; @@ -69,6 +70,7 @@ public class ListTimelineFragment extends StatusListFragment { super.onViewCreated(view, savedInstanceState); fab=view.findViewById(R.id.fab); fab.setOnClickListener(this::onFabClick); + fab.setOnLongClickListener(v -> UiUtils.pickAccountForCompose(getActivity(), accountID, null)); } private void onFabClick(View v){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java index 53dc5c636..f585494cd 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java @@ -138,6 +138,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList private WindowInsets childInsets; private PhotoViewer currentPhotoViewer; private boolean editModeLoading; + private String prefilledText; public ProfileFragment(){ super(R.layout.loader_fragment_overlay_toolbar); @@ -162,6 +163,8 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList if(!getArguments().getBoolean("noAutoLoad", false)) loadData(); } + + prefilledText = AccountSessionManager.getInstance().isSelf(accountID, account) ? null : '@'+account.acct+' '; } @Override @@ -275,6 +278,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList cover.setOnClickListener(this::onCoverClick); refreshLayout.setOnRefreshListener(this); fab.setOnClickListener(this::onFabClick); + fab.setOnLongClickListener(v->UiUtils.pickAccountForCompose(getActivity(), accountID, prefilledText)); if(loaded){ bindHeaderView(); @@ -939,9 +943,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList private void onFabClick(View v){ Bundle args=new Bundle(); args.putString("account", accountID); - if(!AccountSessionManager.getInstance().isSelf(accountID, account)){ - args.putString("prefilledText", '@'+account.acct+' '); - } + if(prefilledText != null) args.putString("prefilledText", prefilledText); Nav.go(getActivity(), ComposeFragment.class, args); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index a011a845b..907618da3 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -5,6 +5,7 @@ import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.ActivityNotFoundException; import android.content.ClipData; @@ -33,6 +34,7 @@ import android.provider.OpenableColumns; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; +import android.view.HapticFeedbackConstants; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -46,12 +48,14 @@ import org.joinmastodon.android.E; import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.R; +import org.joinmastodon.android.api.StatusInteractionController; import org.joinmastodon.android.api.requests.accounts.SetAccountBlocked; import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed; import org.joinmastodon.android.api.requests.accounts.SetAccountMuted; import org.joinmastodon.android.api.requests.accounts.SetDomainBlocked; import org.joinmastodon.android.api.requests.accounts.AuthorizeFollowRequest; import org.joinmastodon.android.api.requests.accounts.RejectFollowRequest; +import org.joinmastodon.android.api.requests.notifications.DismissNotification; import org.joinmastodon.android.api.requests.search.GetSearchResults; import org.joinmastodon.android.api.requests.statuses.DeleteStatus; import org.joinmastodon.android.api.requests.statuses.GetStatusByID; @@ -64,13 +68,16 @@ import org.joinmastodon.android.events.NotificationDeletedEvent; import org.joinmastodon.android.events.RemoveAccountPostsEvent; import org.joinmastodon.android.events.StatusDeletedEvent; import org.joinmastodon.android.events.StatusUnpinnedEvent; +import org.joinmastodon.android.fragments.ComposeFragment; import org.joinmastodon.android.fragments.HashtagTimelineFragment; import org.joinmastodon.android.fragments.ListTimelineFragment; import org.joinmastodon.android.fragments.ProfileFragment; import org.joinmastodon.android.fragments.ThreadFragment; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Emoji; +import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.ListTimeline; +import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.Relationship; import org.joinmastodon.android.model.SearchResults; import org.joinmastodon.android.model.Status; @@ -93,6 +100,7 @@ import java.util.List; import java.util.Map; import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import androidx.annotation.AttrRes; @@ -472,6 +480,25 @@ public class UiUtils{ ); } + public static void confirmDeleteNotification(Activity activity, String accountID, Notification notification, Runnable callback) { + showConfirmationAlert(activity, + notification == null ? R.string.sk_clear_all_notifications : R.string.sk_delete_notification, + notification == null ? R.string.sk_clear_all_notifications_confirm : R.string.sk_delete_notification_confirm, + notification == null ? R.string.sk_clear_all_notifications_confirm_action : R.string.sk_delete_notification_confirm_action, + ()-> new DismissNotification(notification != null ? notification.id : null).setCallback(new Callback<>() { + @Override + public void onSuccess(Object o) { + callback.run(); + } + + @Override + public void onError(ErrorResponse error) { + error.showToast(activity); + } + }).exec(accountID) + ); + } + public static void setRelationshipToActionButton(Relationship relationship, Button button){ setRelationshipToActionButton(relationship, button, false); } @@ -727,16 +754,93 @@ public class UiUtils{ it.matches("^/o/[a-f0-9]+$"); } - public static void openURL(Context context, String accountID, String url){ - Consumer transformDialogForLookup = dialog -> { - dialog.setTitle(R.string.loading_fediverse_resource_title); - dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel), (d, which) -> d.cancel()); + public static String getInstanceName(String accountID) { + AccountSession session = AccountSessionManager.getInstance().getAccount(accountID); + Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain); + return instance != null && !instance.title.isBlank() ? instance.title : session.domain; + } + + public static void pickAccount(Context context, String exceptFor, @StringRes int titleRes, @DrawableRes int iconRes, Consumer sessionConsumer, Consumer transformDialog) { + List sessions=AccountSessionManager.getInstance().getLoggedInAccounts() + .stream().filter(s->!s.getID().equals(exceptFor)).collect(Collectors.toList()); + + AlertDialog.Builder builder = new M3AlertDialogBuilder(context) + .setItems( + sessions.stream().map(AccountSession::getFullUsername).toArray(String[]::new), + (dialog, which) -> sessionConsumer.accept(sessions.get(which)) + ) + .setTitle(titleRes == 0 ? R.string.choose_account : titleRes) + .setIcon(iconRes); + if (transformDialog != null) transformDialog.accept(builder); + builder.show(); + } + + @FunctionalInterface + public interface InteractionPerformer { + void interact(StatusInteractionController ic, Status status, Consumer resultConsumer); + } + + public static void pickInteractAs(Context context, String accountID, Status sourceStatus, Predicate checkInteracted, InteractionPerformer interactionPerformer, @StringRes int interactAsRes, @StringRes int interactedAsAccountRes, @StringRes int alreadyInteractedRes, @DrawableRes int iconRes) { + pickAccount(context, accountID, interactAsRes, iconRes, session -> { + lookupStatus(context, sourceStatus, session.getID(), accountID, status -> { + if (checkInteracted.test(status)) { + Toast.makeText(context, alreadyInteractedRes, Toast.LENGTH_SHORT).show(); + return; + } + + StatusInteractionController ic = AccountSessionManager.getInstance().getAccount(session.getID()).getRemoteStatusInteractionController(); + interactionPerformer.interact(ic, status, s -> { + if (checkInteracted.test(s)) { + Toast.makeText(context, context.getString(interactedAsAccountRes, session.getFullUsername()), Toast.LENGTH_SHORT).show(); + } + }); + }); + }, null); + } + + public static void lookupStatus(Context context, Status queryStatus, String targetAccountID, @Nullable String sourceAccountID, Consumer statusConsumer) { + if (sourceAccountID != null && targetAccountID.startsWith(sourceAccountID.substring(0, sourceAccountID.indexOf('_')))) { + statusConsumer.accept(queryStatus); + return; + } + + new GetSearchResults(queryStatus.url, GetSearchResults.Type.STATUSES, true).setCallback(new Callback<>() { + @Override + public void onSuccess(SearchResults results) { + if (!results.statuses.isEmpty()) statusConsumer.accept(results.statuses.get(0)); + else Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onError(ErrorResponse error) { + error.showToast(context); + } + }) + .wrapProgress((Activity)context, R.string.loading, true, + d -> transformDialogForLookup(context, targetAccountID, null, d)) + .exec(targetAccountID); + } + + public static void openURL(Context context, String accountID, String url) { + openURL(context, accountID, url, true); + } + + private static void transformDialogForLookup(Context context, String accountID, @Nullable String url, ProgressDialog dialog) { + if (accountID != null) { + dialog.setTitle(context.getString(R.string.sk_loading_resource_on_instance_title, getInstanceName(accountID))); + } else { + dialog.setTitle(R.string.sk_loading_fediverse_resource_title); + } + dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel), (d, which) -> d.cancel()); + if (url != null) { dialog.setButton(DialogInterface.BUTTON_POSITIVE, context.getString(R.string.open_in_browser), (d, which) -> { d.cancel(); launchWebBrowser(context, url); }); - }; + } + } + public static void openURL(Context context, String accountID, String url, boolean launchBrowser){ Uri uri=Uri.parse(url); List path=uri.getPathSegments(); if(accountID!=null && "https".equals(uri.getScheme())){ @@ -754,10 +858,11 @@ public class UiUtils{ @Override public void onError(ErrorResponse error){ error.showToast(context); - launchWebBrowser(context, url); + if (launchBrowser) launchWebBrowser(context, url); } }) - .wrapProgress((Activity)context, R.string.loading, true, transformDialogForLookup) + .wrapProgress((Activity)context, R.string.loading, true, + d -> transformDialogForLookup(context, accountID, url, d)) .exec(accountID); return; } else if (looksLikeMastodonUrl(url)) { @@ -774,17 +879,19 @@ public class UiUtils{ args.putParcelable("profileAccount", Parcels.wrap(results.accounts.get(0))); Nav.go((Activity) context, ProfileFragment.class, args); } else { - launchWebBrowser(context, url); + if (launchBrowser) launchWebBrowser(context, url); + else Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show(); } } @Override public void onError(ErrorResponse error) { error.showToast(context); - launchWebBrowser(context, url); + if (launchBrowser) launchWebBrowser(context, url); } }) - .wrapProgress((Activity)context, R.string.loading, true, transformDialogForLookup) + .wrapProgress((Activity)context, R.string.loading, true, + d -> transformDialogForLookup(context, accountID, url, d)) .exec(accountID); return; } @@ -792,14 +899,13 @@ public class UiUtils{ launchWebBrowser(context, url); } - public static void copyText(Context context, String text) { + public static void copyText(View v, String text) { + Context context = v.getContext(); context.getSystemService(ClipboardManager.class).setPrimaryClip(ClipData.newPlainText(null, text)); if(Build.VERSION.SDK_INT= Build.VERSION_CODES.O) vibrator.vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE)); - else vibrator.vibrate(50); + v.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); } private static String getSystemProperty(String key){ @@ -815,6 +921,20 @@ public class UiUtils{ return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.code")); } + public static boolean pickAccountForCompose(Activity activity, String accountID, String prefilledText){ + if (AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1) { + UiUtils.pickAccount(activity, accountID, 0, 0, session -> { + Bundle args=new Bundle(); + args.putString("account", session.getID()); + if (prefilledText != null) args.putString("prefilledText", prefilledText); + Nav.go(activity, ComposeFragment.class, args); + }, null); + return true; + } else { + return false; + } + } + public static void pickAccount(Context context, BiPredicate pick, @StringRes int title) { List sessions=AccountSessionManager.getInstance().getLoggedInAccounts(); new M3AlertDialogBuilder(context) From a0cbfe9a3691da9e5b6c637852d9364ca8175cc4 Mon Sep 17 00:00:00 2001 From: sk Date: Tue, 27 Dec 2022 17:20:20 -0300 Subject: [PATCH 060/133] fix #200 --- .../android/ui/displayitems/PollOptionStatusDisplayItem.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PollOptionStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PollOptionStatusDisplayItem.java index c00edada3..22633b8ce 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PollOptionStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PollOptionStatusDisplayItem.java @@ -89,10 +89,13 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{ button.setBackground(progressBg); itemView.setSelected(item.isMostVoted); icon.setSelected(item.poll.ownVotes.contains(item.poll.options.indexOf(item.option))); + icon.setVisibility(item.poll.voted && item.poll.ownVotes.isEmpty() ? View.GONE : View.VISIBLE); percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f))); }else{ itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option)); button.setBackgroundResource(R.drawable.bg_poll_option_clickable); + icon.setSelected(itemView.isSelected()); + icon.setVisibility(View.VISIBLE); } } From f007bdb39c9b88468c5de89ab51991fbe6776e4f Mon Sep 17 00:00:00 2001 From: sk Date: Tue, 27 Dec 2022 17:30:35 -0300 Subject: [PATCH 061/133] revert broken color attribute for notif icon closes #190 --- .../java/org/joinmastodon/android/PushNotificationReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java index f37f70a99..d56356ded 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java @@ -142,7 +142,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{ .setShowWhen(true) .setCategory(Notification.CATEGORY_SOCIAL) .setAutoCancel(true) - .setColor(UiUtils.getThemeColor(context, R.attr.colorPrimary700)); + .setColor(context.getColor(R.color.shortcut_icon_background)); if(GlobalUserPreferences.showDifferentiatedPushNoticationIcons){ switch (pn.notificationType) { case FAVORITE -> builder.setSmallIcon(R.drawable.ic_fluent_star_24_filled); From d626d45f5c49a166d0a080468997da6761d34af8 Mon Sep 17 00:00:00 2001 From: ihor_ck Date: Mon, 26 Dec 2022 21:05:06 -0300 Subject: [PATCH 062/133] Translated using Weblate (Ukrainian) Currently translated at 100.0% (91 of 91 strings) Translation: Megalodon/values Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/ --- .../src/main/res/values-uk-rUA/strings_sk.xml | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/mastodon/src/main/res/values-uk-rUA/strings_sk.xml b/mastodon/src/main/res/values-uk-rUA/strings_sk.xml index 5b103c062..69eb52e61 100644 --- a/mastodon/src/main/res/values-uk-rUA/strings_sk.xml +++ b/mastodon/src/main/res/values-uk-rUA/strings_sk.xml @@ -1,93 +1,93 @@ - Сповіщення про пости - Колірна тема - Фіолетовий - Зелений - Синий - Коричневий - Жовтий + Сповіщення про дописи + Колірна палітра + Фіолетова + Зелена + Синя + Коричнева + Жовта Дозволити кілька виборів Перекласти Показати оригінал - Перекладено через %s + Перекладено за допомогою %s Мова: %s Доступні мови %s (%s) Очистити нещодавно використані мови - Завжди відкривати вміст - Пости - Рожевий + Завжди розкривати попередження про вміст + Дописи + Рожева Ви впевнені, що хочете очистити нещодавно використані мови\? - Moshidon + Megalodon Закріплене Видалити та переробити - Видалити та переробити пост - Ви впевнені, що хочете видалити та переробити цей пост\? - Закріпити у профіль - Закріпити пост у профіль - Чи хочете ви закріпити цей пост у ваш профіль\? - Закріпляємо пост… + Видалити та переробити допис + Ви впевнені, що хочете видалити та переробити цей допис\? + Закріпити у профілі + Закріпити допис у профілі + Бажаєте закріпити цей допис у своєму профілі\? + Закріплюємо допис… Відкріпити з профілю - Відкріпити пост з профілю - Ви впевнені, що хочете відкріпити цей пост\? - Відкріпляємо пост… + Відкріпити допис із профілю + Ви впевнені, що хочете відкріпити цей допис\? + Відкріпляємо допис… Опис зображення - Не у списку + Прихований Показувати відповіді - Автоматично завантажувати нові пости + Автоматично завантажувати нові дописи Показати кількість взаємодій - Moshidon v%1$s (%2$d) - Запити на підписку - Прийняти запит на підписку - Відхилити запит на підписку + Megalodon v%1$s (%2$d) + Запити на стеження + Погодити запит на стеження + Відхилити запит на стеження Списки з %s Вимкнути прокручування тексту у рядках заголовка - Допомогти у розробці Moshidon - Помітити медіа як чутливу - Показувати бусти - Увімкнено сповіщення про пости для %s - Вимкнено сповіщення про пости для %s + Допомогти у розробці Megalodon + Позначити медіа делікатним + Показувати поширення + Увімкнено сповіщення про дописи для %s + Вимкнено сповіщення про дописи для %s Федерація - Це найновіші публікації людей у вашій федерації. - Moshidon %s готовий до завантаження. - Moshidon %s завантажений й готовий до встановлення. - Перевірити оновлення + Це найновіші дописи людей у вашій федерації. + Megalodon %s готовий до завантаження. + Megalodon %s завантажений і готовий до встановлення. + Перевірити наявність оновлень Немає доступних оновлень Списки Показувати федеративну стрічку example.social Вітаємо! - Акулка вас вітає! Щоб розпочати, введіть нижче доменне ім’я вашого інстансу. + Акулка вітає вас! Щоб розпочати, введіть нижче доменне ім’я вашого сервера. Налаштувати профіль Налаштувати постинг Налаштувати фільтри Правила Про застосунок - Донат + Підтримати Системна Червона Видалити сповіщення - Видалити + Видалити сповіщення Ви впевнені, що хочете видалити це сповіщення\? Увімкнути видалення сповіщень Текст кнопки \"опублікувати\" Змінити текст кнопки \"опублікувати\" - Сховати кнопку \"перекласти\" у стрічці + Сховати кнопку \"перекласти\" у стрічці %s підтримує переклад! %s не підтримує переклад. Очистити всі сповіщення Ви впевнені, що хочете очистити всі сповіщення\? - Переглядаємо Федісвіт - Скасувати репост - Репост з видимістю - Цитувати пост - Вимкнути перегортання вкладок - Налаштування безпеці + Переглядаємо Федівсесвіт + Скасувати поширення + Поширення з видимістю + Цитувати допис + Вимкнути жест гортання між вкладками + Налаштування безпеки Видалити все - Скопіювати посилання на пост + Скопіювати посилання на допис Відстежувані хештеги - Переглядаємо %s - Відкрити через інший акаунт + Пошук на %s + Відкрити через інший обліковий запис Ресурс не знайдено \ No newline at end of file From be86f1e96fc7c7ac58aa934e14b2e952e5e54b0e Mon Sep 17 00:00:00 2001 From: edxkl Date: Tue, 27 Dec 2022 08:24:45 +0000 Subject: [PATCH 063/133] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/ --- metadata/pt-BR/changelogs/61.txt | 5 +++++ metadata/pt-BR/changelogs/62.txt | 11 +++++++++++ metadata/pt-BR/changelogs/63.txt | 6 ++++++ 3 files changed, 22 insertions(+) create mode 100644 metadata/pt-BR/changelogs/61.txt create mode 100644 metadata/pt-BR/changelogs/62.txt create mode 100644 metadata/pt-BR/changelogs/63.txt diff --git a/metadata/pt-BR/changelogs/61.txt b/metadata/pt-BR/changelogs/61.txt new file mode 100644 index 000000000..4b149f50a --- /dev/null +++ b/metadata/pt-BR/changelogs/61.txt @@ -0,0 +1,5 @@ +- Novos temas de cores: Material You and Vermelho +- Novos tons de cinza escuro para todos os temas +- Ícone de impulsionar mais distinto e preenchido +- Animações para botões de interação +- Correções de bugs (Falha em algumas postagens, "Listas com", idioma de postagem padrão) diff --git a/metadata/pt-BR/changelogs/62.txt b/metadata/pt-BR/changelogs/62.txt new file mode 100644 index 000000000..25a61cc8b --- /dev/null +++ b/metadata/pt-BR/changelogs/62.txt @@ -0,0 +1,11 @@ +- Botão de Publicar personalizável +- Links do Fediverso no abertos no aplicativo +- Clique longo em impulsionar para "citar" uma postagem +- Copie o URL da postagem ao pressionar e segurar o compartilhar +- Exclusão de notificações (desativado por padrão) +- Ícones para diferentes tipos de notificação +- Novas cores de cinza +- Opção de desativar o deslizamento entre abas +- Links para as configurações da conta +- Opção para mostrar/ocultar o botão traduzir na timeline +- Correções de bugs e ajustes diff --git a/metadata/pt-BR/changelogs/63.txt b/metadata/pt-BR/changelogs/63.txt new file mode 100644 index 000000000..9d2e71130 --- /dev/null +++ b/metadata/pt-BR/changelogs/63.txt @@ -0,0 +1,6 @@ +- Opção para reblogar com visibilidade específica em clique longo +- Mostrar visibilidade dos próprios reblogs +- Adicionada lista de hashtags seguidas +- Clique longo para copiar links +- Opção para abrir postagens com outra conta +- Correções de bugs e pequenos ajustes From ea3dc32e98b1571341d94c6dbb830ffc68cb4c95 Mon Sep 17 00:00:00 2001 From: ihor_ck Date: Mon, 26 Dec 2022 21:36:49 -0300 Subject: [PATCH 064/133] Translated using Weblate (Ukrainian) Currently translated at 100.0% (11 of 11 strings) Translation: Megalodon/metadata Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/ --- metadata/uk/changelogs/61.txt | 4 ++-- metadata/uk/changelogs/62.txt | 11 +++++++++++ metadata/uk/changelogs/63.txt | 6 ++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 metadata/uk/changelogs/62.txt create mode 100644 metadata/uk/changelogs/63.txt diff --git a/metadata/uk/changelogs/61.txt b/metadata/uk/changelogs/61.txt index 27fe306f6..bdecba860 100644 --- a/metadata/uk/changelogs/61.txt +++ b/metadata/uk/changelogs/61.txt @@ -1,5 +1,5 @@ - Нові колірні теми: Material You й Червона - Нові темно-сірі тони для всіх тем -- Більш виразний заповнений значок репоста +- Виразніша заповнена піктограма поширення - Анімації для кнопок взаємодій -- Виправлення багів (виліт на деякіх постах, тощо) +- Виправлення помилок (збій на деяких дописах, "Списки з", усталена мова дописів тощо) diff --git a/metadata/uk/changelogs/62.txt b/metadata/uk/changelogs/62.txt new file mode 100644 index 000000000..0033889a2 --- /dev/null +++ b/metadata/uk/changelogs/62.txt @@ -0,0 +1,11 @@ +- Налаштовувана кнопка публікування +- Відкриття посилань Федівсесвіту в застосунку +- Цитування допису затисканням кнопки поширення +- Копіювання URL допису затисканням кнопки поділитися +- Реалізація видалення сповіщень (усталено вимкнено) +- Окремі піктограми для різних типів сповіщень +- Нові сірі кольори +- Можливість вимкнення гортання між вкладками +- Додавання різних посилань до налаштувань облікового запису +- Перемикач показу/приховування кнопки перекладу у стрічці +- Виправлення й удосконалення diff --git a/metadata/uk/changelogs/63.txt b/metadata/uk/changelogs/63.txt new file mode 100644 index 000000000..95b1b7e77 --- /dev/null +++ b/metadata/uk/changelogs/63.txt @@ -0,0 +1,6 @@ +- Опція цитування з певною видимістю затисканням +- Показ видимості власних поширень +- Додавання списку відстежуваних хештегів +- Копіювання посилань затисканням +- Можливість відкривати дописи з іншого облікового запису +- Виправлення помилок та незначні коригування From d2be917bd459417c23467e21e94651d0247d9abf Mon Sep 17 00:00:00 2001 From: sk Date: Tue, 27 Dec 2022 22:00:19 +0100 Subject: [PATCH 065/133] fix akkoma crash on edit --- .../org/joinmastodon/android/fragments/ComposeFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java index 2ab46e523..704756cf2 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java @@ -681,7 +681,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr } private void updateLanguage(String lang) { - updateLanguage(languageResolver.from(lang)); + updateLanguage(lang == null ? languageResolver.getDefault() : languageResolver.from(lang)); } private void updateLanguage(MastodonLanguage loc) { From 71c80dd381fd0eadfb7efa7e834e9795905184b8 Mon Sep 17 00:00:00 2001 From: sk Date: Tue, 27 Dec 2022 20:53:06 -0300 Subject: [PATCH 066/133] I want to fucking die --- .../fragments/NotificationsFragment.java | 21 +++- .../android/fragments/ProfileFragment.java | 12 +- .../displayitems/FooterStatusDisplayItem.java | 93 ++++++++++++-- .../displayitems/HeaderStatusDisplayItem.java | 10 +- .../android/ui/utils/UiUtils.java | 118 ++++++++++++------ .../ic_fluent_arrow_clockwise_24_regular.xml | 3 + .../ic_fluent_arrow_clockwise_28_regular.xml | 3 + .../ic_fluent_arrow_reply_28_regular.xml | 3 + .../ic_fluent_bookmark_28_regular.xml | 3 + .../drawable/ic_fluent_globe_24_regular.xml | 3 + ...c_fluent_mail_inbox_dismiss_28_regular.xml | 3 + .../drawable/ic_fluent_person_28_regular.xml | 3 + .../ic_fluent_person_delete_24_regular.xml | 3 + ...ic_fluent_person_prohibited_24_regular.xml | 3 + ...ic_fluent_person_prohibited_28_regular.xml | 3 + .../res/drawable/ic_fluent_pin_24_regular.xml | 3 + .../res/drawable/ic_fluent_pin_28_regular.xml | 3 + .../drawable/ic_fluent_pin_off_24_regular.xml | 3 + .../drawable/ic_fluent_pin_off_28_regular.xml | 3 + .../drawable/ic_fluent_shield_28_regular.xml | 3 + ...ic_fluent_shield_prohibited_24_regular.xml | 3 + .../ic_fluent_speaker_2_24_regular.xml | 3 + .../ic_fluent_speaker_2_28_regular.xml | 3 + .../ic_fluent_speaker_mute_24_regular.xml | 3 + .../ic_fluent_speaker_mute_28_regular.xml | 3 + .../drawable/ic_fluent_star_28_regular.xml | 3 + .../drawable/ic_fluent_warning_24_regular.xml | 3 + .../main/res/drawable/ic_follow_selector.xml | 8 ++ mastodon/src/main/res/menu/post.xml | 29 +++-- mastodon/src/main/res/menu/profile.xml | 16 +-- 30 files changed, 291 insertions(+), 82 deletions(-) create mode 100644 mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_arrow_reply_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_bookmark_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_globe_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_person_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_person_delete_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_person_prohibited_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_person_prohibited_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_pin_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_pin_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_pin_off_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_pin_off_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_shield_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_shield_prohibited_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_speaker_2_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_speaker_2_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_speaker_mute_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_speaker_mute_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_star_28_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_warning_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_follow_selector.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsFragment.java index 0bfc93cad..264a27622 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsFragment.java @@ -74,15 +74,26 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ inflater.inflate(R.menu.notifications, menu); + menu.findItem(R.id.clear_notifications).setVisible(GlobalUserPreferences.enableDeleteNotifications); + UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.follow_requests); } @Override public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() != R.id.follow_requests) return false; - Bundle args=new Bundle(); - args.putString("account", accountID); - Nav.go(getActivity(), FollowRequestsListFragment.class, args); - return true; + if (item.getItemId() == R.id.follow_requests) { + Bundle args=new Bundle(); + args.putString("account", accountID); + Nav.go(getActivity(), FollowRequestsListFragment.class, args); + return true; + } else if (item.getItemId() == R.id.clear_notifications) { + UiUtils.confirmDeleteNotification(getActivity(), accountID, null, ()->{ + for (int i = 0; i < tabViews.length; i++) { + getFragmentForPage(i).reload(); + } + }); + return true; + } + return false; } @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java index f585494cd..713140adb 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java @@ -553,16 +553,24 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList if(relationship==null && !isOwnProfile) return; inflater.inflate(isOwnProfile ? R.menu.profile_own : R.menu.profile, menu); + UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags); menu.findItem(R.id.share).setTitle(getString(R.string.share_user, account.getDisplayUsername())); if(isOwnProfile) return; - menu.findItem(R.id.mute).setTitle(getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername())); + MenuItem mute = menu.findItem(R.id.mute); + mute.setTitle(getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername())); + mute.setIcon(relationship.muting ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_mute_24_regular); + UiUtils.insetPopupMenuIcon(getContext(), mute); + menu.findItem(R.id.block).setTitle(getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername())); menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getDisplayUsername())); MenuItem manageUserLists=menu.findItem(R.id.manage_user_lists); if(relationship.following) { - menu.findItem(R.id.hide_boosts).setTitle(getString(relationship.showingReblogs ? R.string.hide_boosts_from_user : R.string.show_boosts_from_user, account.getDisplayUsername())); + MenuItem hideBoosts = menu.findItem(R.id.hide_boosts); + hideBoosts.setTitle(getString(relationship.showingReblogs ? R.string.hide_boosts_from_user : R.string.show_boosts_from_user, account.getDisplayUsername())); + hideBoosts.setIcon(relationship.showingReblogs ? R.drawable.ic_fluent_arrow_repeat_all_off_24_regular : R.drawable.ic_fluent_arrow_repeat_all_24_regular); + UiUtils.insetPopupMenuIcon(getContext(), hideBoosts); manageUserLists.setTitle(getString(R.string.sk_lists_with_user, account.getDisplayUsername())); manageUserLists.setVisible(true); }else { diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java index da92f4499..f9ab6364e 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java @@ -60,7 +60,14 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ private static final Animation opacityOut, opacityIn; private View touchingView = null; - private final Runnable longClickRunnable = () -> { if (touchingView != null) touchingView.performLongClick(); }; + private boolean longClickPerformed = false; + private final Runnable longClickRunnable = () -> { + longClickPerformed = touchingView != null && touchingView.performLongClick(); + if (longClickPerformed && touchingView != null) { + touchingView.startAnimation(opacityIn); + touchingView.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start(); + } + }; private final View.AccessibilityDelegate buttonAccessibilityDelegate=new View.AccessibilityDelegate(){ @Override @@ -72,12 +79,12 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ }; static { - opacityOut = new AlphaAnimation(1, 0.7f); - opacityOut.setDuration(200); + opacityOut = new AlphaAnimation(1, 0.55f); + opacityOut.setDuration(300); opacityOut.setInterpolator(CubicBezierInterpolator.DEFAULT); opacityOut.setFillAfter(true); - opacityIn = new AlphaAnimation(0.7f, 1); - opacityIn.setDuration(300); + opacityIn = new AlphaAnimation(0.55f, 1); + opacityIn.setDuration(500); opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT); } @@ -101,6 +108,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ View bookmark=findViewById(R.id.bookmark_btn); reply.setOnTouchListener(this::onButtonTouch); reply.setOnClickListener(this::onReplyClick); + reply.setOnLongClickListener(this::onReplyLongClick); reply.setAccessibilityDelegate(buttonAccessibilityDelegate); boost.setOnTouchListener(this::onButtonTouch); boost.setOnClickListener(this::onBoostClick); @@ -108,9 +116,11 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ boost.setAccessibilityDelegate(buttonAccessibilityDelegate); favorite.setOnTouchListener(this::onButtonTouch); favorite.setOnClickListener(this::onFavoriteClick); + favorite.setOnLongClickListener(this::onFavoriteLongClick); favorite.setAccessibilityDelegate(buttonAccessibilityDelegate); bookmark.setOnTouchListener(this::onButtonTouch); bookmark.setOnClickListener(this::onBookmarkClick); + bookmark.setOnLongClickListener(this::onBookmarkLongClick); bookmark.setAccessibilityDelegate(buttonAccessibilityDelegate); share.setOnTouchListener(this::onButtonTouch); share.setOnClickListener(this::onShareClick); @@ -144,15 +154,15 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ boolean disabled = !v.isEnabled() || (v instanceof FrameLayout parentFrame && parentFrame.getChildCount() > 0 && !parentFrame.getChildAt(0).isEnabled()); int action = event.getAction(); - long eventDuration = event.getEventTime() - event.getDownTime(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { touchingView = null; v.removeCallbacks(longClickRunnable); - v.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start(); + if (!longClickPerformed) v.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start(); if (disabled) return true; - if (action == MotionEvent.ACTION_UP && eventDuration <= ViewConfiguration.getLongPressTimeout()) v.performClick(); - else v.startAnimation(opacityIn); + if (action == MotionEvent.ACTION_UP && !longClickPerformed) v.performClick(); + else if (!longClickPerformed) v.startAnimation(opacityIn); } else if (action == MotionEvent.ACTION_DOWN) { + longClickPerformed = false; touchingView = v; // 20dp to center in middle of icon, because: (icon width = 24dp) / 2 + (paddingStart = 8dp) v.setPivotX(V.dp(20)); @@ -172,6 +182,20 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); } + private boolean onReplyLongClick(View v) { + if (AccountSessionManager.getInstance().getLoggedInAccounts().size() < 2) return false; + UiUtils.pickAccount(v.getContext(), item.accountID, R.string.sk_reply_as, R.drawable.ic_fluent_arrow_reply_28_regular, session -> { + Bundle args=new Bundle(); + String accountID = session.getID(); + args.putString("account", accountID); + UiUtils.lookupStatus(v.getContext(), item.status, accountID, item.accountID, status -> { + args.putParcelable("replyTo", Parcels.wrap(status)); + Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); + }); + }, null); + return true; + } + private void onBoostClick(View v){ boost.setSelected(!item.status.reblogged); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r)); @@ -198,6 +222,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ View separator = menu.findViewById(R.id.separator); TextView reblogHeader = menu.findViewById(R.id.reblog_header); TextView undoReblog = menu.findViewById(R.id.delete_reblog); + TextView reblogAs = menu.findViewById(R.id.reblog_as); TextView itemPublic = menu.findViewById(R.id.vis_public); TextView itemUnlisted = menu.findViewById(R.id.vis_unlisted); TextView itemFollowers = menu.findViewById(R.id.vis_followers); @@ -205,6 +230,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ undoReblog.setVisibility(item.status.reblogged ? View.VISIBLE : View.GONE); separator.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE); reblogHeader.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE); + reblogAs.setVisibility(AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1 ? View.VISIBLE : View.GONE); itemPublic.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.PUBLIC) ? View.GONE : View.VISIBLE); itemUnlisted.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) ? View.GONE : View.VISIBLE); @@ -215,10 +241,10 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ Drawable unlistedDrawable = ctx.getDrawable(R.drawable.ic_fluent_people_community_24_regular); Drawable followersDrawable = ctx.getDrawable(R.drawable.ic_fluent_people_checkmark_24_regular); - StatusPrivacy defaultVisibility = session.preferences.postingDefaultVisibility; + StatusPrivacy defaultVisibility = session.preferences != null ? session.preferences.postingDefaultVisibility : null; // e.g. post visibility is unlisted, but default is public // in this case, we want to display the check mark on the most visible visibility - if (item.status.visibility.isLessVisibleThan(defaultVisibility)) { + if (defaultVisibility != null && item.status.visibility.isLessVisibleThan(defaultVisibility)) { for (StatusPrivacy vis : StatusPrivacy.values()) { if (vis.equals(item.status.visibility)) { defaultVisibility = vis; @@ -234,6 +260,19 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ itemPublic.setOnClickListener(c->doReblog.accept(StatusPrivacy.PUBLIC)); itemUnlisted.setOnClickListener(c->doReblog.accept(StatusPrivacy.UNLISTED)); itemFollowers.setOnClickListener(c->doReblog.accept(StatusPrivacy.PRIVATE)); + reblogAs.setOnClickListener(c->{ + dialog.dismiss(); + UiUtils.pickInteractAs(v.getContext(), + item.accountID, item.status, + s -> s.reblogged, + (ic, status, consumer) -> ic.setReblogged(status, true, null, consumer), + R.string.sk_reblog_as, + R.string.sk_reblogged_as, + R.string.sk_already_reblogged, + // TODO: replace once available: https://raw.githubusercontent.com/microsoft/fluentui-system-icons/main/android/library/src/main/res/drawable/ic_fluent_arrow_repeat_all_28_regular.xml + R.drawable.ic_fluent_arrow_repeat_all_24_regular + ); + }); menu.findViewById(R.id.quote).setOnClickListener(c->{ dialog.dismiss(); @@ -257,13 +296,41 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ }); } + private boolean onFavoriteLongClick(View v) { + if (AccountSessionManager.getInstance().getLoggedInAccounts().size() < 2) return false; + UiUtils.pickInteractAs(v.getContext(), + item.accountID, item.status, + s -> s.favourited, + (ic, status, consumer) -> ic.setFavorited(status, true, consumer), + R.string.sk_favorite_as, + R.string.sk_favorited_as, + R.string.sk_already_favorited, + R.drawable.ic_fluent_star_28_regular + ); + return true; + } + private void onBookmarkClick(View v){ - bookmark.setSelected(item.status.bookmarked); + bookmark.setSelected(!item.status.bookmarked); AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{ v.startAnimation(opacityIn); }); } + private boolean onBookmarkLongClick(View v) { + if (AccountSessionManager.getInstance().getLoggedInAccounts().size() < 2) return false; + UiUtils.pickInteractAs(v.getContext(), + item.accountID, item.status, + s -> s.bookmarked, + (ic, status, consumer) -> ic.setBookmarked(status, true, consumer), + R.string.sk_bookmark_as, + R.string.sk_bookmarked_as, + R.string.sk_already_bookmarked, + R.drawable.ic_fluent_bookmark_28_regular + ); + return true; + } + private void onShareClick(View v){ v.startAnimation(opacityIn); Intent intent=new Intent(Intent.ACTION_SEND); @@ -273,7 +340,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ } private boolean onShareLongClick(View v){ - UiUtils.copyText(v.getContext(), item.status.url); + UiUtils.copyText(v, item.status.url); return true; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java index 4a9645fd0..66c421a1f 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java @@ -222,6 +222,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ } return true; }); + UiUtils.enablePopupMenuIcons(activity, optionsMenu); } private void openWithAccount() { @@ -323,6 +324,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ menu.findItem(R.id.open_in_browser).setVisible(item.status!=null); MenuItem blockDomain=menu.findItem(R.id.block_domain); MenuItem mute=menu.findItem(R.id.mute); + MenuItem hideBoosts=menu.findItem(R.id.hide_boosts); MenuItem block=menu.findItem(R.id.block); MenuItem report=menu.findItem(R.id.report); MenuItem follow=menu.findItem(R.id.follow); @@ -338,6 +340,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ */ if(isOwnPost){ mute.setVisible(false); + hideBoosts.setVisible(false); block.setVisible(false); report.setVisible(false); follow.setVisible(false); @@ -348,6 +351,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ report.setVisible(true); follow.setVisible(relationship==null || relationship.following || (!relationship.blocking && !relationship.blockedBy && !relationship.domainBlocking && !relationship.muting)); mute.setTitle(item.parentFragment.getString(relationship!=null && relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername())); + mute.setIcon(relationship!=null && relationship.muting ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_mute_24_regular); + UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), mute); block.setTitle(item.parentFragment.getString(relationship!=null && relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername())); report.setTitle(item.parentFragment.getString(R.string.report_user, account.getDisplayUsername())); // disabled in megalodon. domain blocks from a post clutters the context menu and looks out of place @@ -357,7 +362,10 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ // }else{ blockDomain.setVisible(false); // } - follow.setTitle(item.parentFragment.getString(relationship!=null && relationship.following ? R.string.unfollow_user : R.string.follow_user, account.getDisplayUsername())); + boolean following = relationship!=null && relationship.following; + follow.setTitle(item.parentFragment.getString(following ? R.string.unfollow_user : R.string.follow_user, account.getDisplayUsername())); + follow.setIcon(following ? R.drawable.ic_fluent_person_delete_24_regular : R.drawable.ic_fluent_person_add_24_regular); + UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), follow); } } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index 907618da3..fe28da756 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -105,6 +105,7 @@ import java.util.stream.Collectors; import androidx.annotation.AttrRes; import androidx.annotation.DrawableRes; +import androidx.annotation.IdRes; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.browser.customtabs.CustomTabsIntent; @@ -348,22 +349,29 @@ public class UiUtils{ } public static void showConfirmationAlert(Context context, @StringRes int title, @StringRes int message, @StringRes int confirmButton, Runnable onConfirmed){ - showConfirmationAlert(context, context.getString(title), context.getString(message), context.getString(confirmButton), onConfirmed); + showConfirmationAlert(context, title, message, confirmButton, 0, onConfirmed); } - public static void showConfirmationAlert(Context context, CharSequence title, CharSequence message, CharSequence confirmButton, Runnable onConfirmed){ + public static void showConfirmationAlert(Context context, @StringRes int title, @StringRes int message, @StringRes int confirmButton, @DrawableRes int icon, Runnable onConfirmed){ + showConfirmationAlert(context, context.getString(title), context.getString(message), context.getString(confirmButton), icon, onConfirmed); + } + + public static void showConfirmationAlert(Context context, CharSequence title, CharSequence message, CharSequence confirmButton, int icon, Runnable onConfirmed){ new M3AlertDialogBuilder(context) .setTitle(title) .setMessage(message) .setPositiveButton(confirmButton, (dlg, i)->onConfirmed.run()) .setNegativeButton(R.string.cancel, null) + .setIcon(icon) .show(); } public static void confirmToggleBlockUser(Activity activity, String accountID, Account account, boolean currentlyBlocked, Consumer resultCallback){ showConfirmationAlert(activity, activity.getString(currentlyBlocked ? R.string.confirm_unblock_title : R.string.confirm_block_title), activity.getString(currentlyBlocked ? R.string.confirm_unblock : R.string.confirm_block, account.displayName), - activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block), ()->{ + activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block), + currentlyBlocked ? R.drawable.ic_fluent_person_28_regular : R.drawable.ic_fluent_person_prohibited_28_regular, + ()->{ new SetAccountBlocked(account.id, !currentlyBlocked) .setCallback(new Callback<>(){ @Override @@ -387,7 +395,9 @@ public class UiUtils{ public static void confirmToggleBlockDomain(Activity activity, String accountID, String domain, boolean currentlyBlocked, Runnable resultCallback){ showConfirmationAlert(activity, activity.getString(currentlyBlocked ? R.string.confirm_unblock_domain_title : R.string.confirm_block_domain_title), activity.getString(currentlyBlocked ? R.string.confirm_unblock : R.string.confirm_block, domain), - activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block), ()->{ + activity.getString(currentlyBlocked ? R.string.do_unblock : R.string.do_block), + R.drawable.ic_fluent_shield_28_regular, + ()->{ new SetDomainBlocked(domain, !currentlyBlocked) .setCallback(new Callback<>(){ @Override @@ -408,7 +418,9 @@ public class UiUtils{ public static void confirmToggleMuteUser(Activity activity, String accountID, Account account, boolean currentlyMuted, Consumer resultCallback){ showConfirmationAlert(activity, activity.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title), activity.getString(currentlyMuted ? R.string.confirm_unmute : R.string.confirm_mute, account.displayName), - activity.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), ()->{ + activity.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), + currentlyMuted ? R.drawable.ic_fluent_speaker_2_28_regular : R.drawable.ic_fluent_speaker_mute_28_regular, + ()->{ new SetAccountMuted(account.id, !currentlyMuted) .setCallback(new Callback<>(){ @Override @@ -433,24 +445,28 @@ public class UiUtils{ } public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer resultCallback, boolean forRedraft){ - showConfirmationAlert(activity, forRedraft ? R.string.sk_confirm_delete_and_redraft_title : R.string.confirm_delete_title, forRedraft ? R.string.sk_confirm_delete_and_redraft : R.string.confirm_delete, forRedraft ? R.string.sk_delete_and_redraft : R.string.delete, ()->{ - new DeleteStatus(status.id) - .setCallback(new Callback<>(){ - @Override - public void onSuccess(Status result){ - resultCallback.accept(result); - AccountSessionManager.getInstance().getAccount(accountID).getCacheController().deleteStatus(status.id); - E.post(new StatusDeletedEvent(status.id, accountID)); - } + showConfirmationAlert(activity, + forRedraft ? R.string.sk_confirm_delete_and_redraft_title : R.string.confirm_delete_title, + forRedraft ? R.string.sk_confirm_delete_and_redraft : R.string.confirm_delete, + forRedraft ? R.string.sk_delete_and_redraft : R.string.delete, + forRedraft ? R.drawable.ic_fluent_arrow_clockwise_28_regular : R.drawable.ic_fluent_delete_28_regular, + () -> new DeleteStatus(status.id) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(Status result){ + resultCallback.accept(result); + AccountSessionManager.getInstance().getAccount(accountID).getCacheController().deleteStatus(status.id); + E.post(new StatusDeletedEvent(status.id, accountID)); + } - @Override - public void onError(ErrorResponse error){ - error.showToast(activity); - } - }) - .wrapProgress(activity, R.string.deleting, false) - .exec(accountID); - }); + @Override + public void onError(ErrorResponse error){ + error.showToast(activity); + } + }) + .wrapProgress(activity, R.string.deleting, false) + .exec(accountID) + ); } public static void confirmPinPost(Activity activity, String accountID, Status status, boolean pinned, Consumer resultCallback){ @@ -458,6 +474,7 @@ public class UiUtils{ pinned ? R.string.sk_confirm_pin_post_title : R.string.sk_confirm_unpin_post_title, pinned ? R.string.sk_confirm_pin_post : R.string.sk_confirm_unpin_post, pinned ? R.string.sk_pin_post : R.string.sk_unpin_post, + pinned ? R.drawable.ic_fluent_pin_off_28_regular : R.drawable.ic_fluent_pin_28_regular, ()->{ new SetStatusPinned(status.id, pinned) .setCallback(new Callback<>() { @@ -485,7 +502,8 @@ public class UiUtils{ notification == null ? R.string.sk_clear_all_notifications : R.string.sk_delete_notification, notification == null ? R.string.sk_clear_all_notifications_confirm : R.string.sk_delete_notification_confirm, notification == null ? R.string.sk_clear_all_notifications_confirm_action : R.string.sk_delete_notification_confirm_action, - ()-> new DismissNotification(notification != null ? notification.id : null).setCallback(new Callback<>() { + notification == null ? R.drawable.ic_fluent_mail_inbox_dismiss_28_regular : R.drawable.ic_fluent_delete_28_regular, + () -> new DismissNotification(notification != null ? notification.id : null).setCallback(new Callback<>() { @Override public void onSuccess(Object o) { callback.run(); @@ -666,6 +684,42 @@ public class UiUtils{ return bitmap; } + public static void insetPopupMenuIcon(Context context, MenuItem item) { + ColorStateList iconTint=ColorStateList.valueOf(UiUtils.getThemeColor(context, android.R.attr.textColorSecondary)); + insetPopupMenuIcon(item, iconTint); + } + public static void insetPopupMenuIcon(MenuItem item, ColorStateList iconTint) { + Drawable icon=item.getIcon().mutate(); + if(Build.VERSION.SDK_INT>=26) item.setIconTintList(iconTint); + else icon.setTintList(iconTint); + icon=new InsetDrawable(icon, V.dp(8), 0, V.dp(8), 0); + item.setIcon(icon); + SpannableStringBuilder ssb=new SpannableStringBuilder(item.getTitle()); + item.setTitle(ssb); + } + + public static void enableOptionsMenuIcons(Context context, Menu menu, @IdRes int... asAction) { + if(menu.getClass().getSimpleName().equals("MenuBuilder")){ + try { + Method m = menu.getClass().getDeclaredMethod( + "setOptionalIconsVisible", Boolean.TYPE); + m.setAccessible(true); + m.invoke(menu, true); + enableMenuIcons(context, menu, asAction); + } + catch(Exception ignored){} + } + } + + public static void enableMenuIcons(Context context, Menu m, @IdRes int... exclude) { + ColorStateList iconTint=ColorStateList.valueOf(UiUtils.getThemeColor(context, android.R.attr.textColorSecondary)); + for(int i=0;i id == item.getItemId())) continue; + insetPopupMenuIcon(item, iconTint); + } + } + public static void enablePopupMenuIcons(Context context, PopupMenu menu){ Menu m=menu.getMenu(); if(Build.VERSION.SDK_INT>=29){ @@ -677,23 +731,7 @@ public class UiUtils{ setOptionalIconsVisible.invoke(m, true); }catch(Exception ignore){} } - ColorStateList iconTint=ColorStateList.valueOf(UiUtils.getThemeColor(context, android.R.attr.textColorSecondary)); - for(int i=0;i=26){ - item.setIconTintList(iconTint); - }else{ - icon.setTintList(iconTint); - } - icon=new InsetDrawable(icon, V.dp(8), 0, 0, 0); - item.setIcon(icon); - SpannableStringBuilder ssb=new SpannableStringBuilder(item.getTitle()); - ssb.insert(0, " "); - ssb.setSpan(new SpacerSpan(V.dp(24), 1), 0, 1, 0); - ssb.append(" ", new SpacerSpan(V.dp(8), 1), 0); - item.setTitle(ssb); - } + enableMenuIcons(context, m); } public static void setUserPreferredTheme(Context context){ diff --git a/mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_24_regular.xml new file mode 100644 index 000000000..d130d2b90 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_28_regular.xml new file mode 100644 index 000000000..c693e299d --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_arrow_clockwise_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_arrow_reply_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_arrow_reply_28_regular.xml new file mode 100644 index 000000000..7e17362da --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_arrow_reply_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_bookmark_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_bookmark_28_regular.xml new file mode 100644 index 000000000..964afe7b1 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_bookmark_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_globe_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_globe_24_regular.xml new file mode 100644 index 000000000..580825c79 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_globe_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml new file mode 100644 index 000000000..2ea945f3d --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_person_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_person_28_regular.xml new file mode 100644 index 000000000..ab35ad3fd --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_person_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_person_delete_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_person_delete_24_regular.xml new file mode 100644 index 000000000..106276c58 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_person_delete_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_person_prohibited_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_person_prohibited_24_regular.xml new file mode 100644 index 000000000..dece645aa --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_person_prohibited_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_person_prohibited_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_person_prohibited_28_regular.xml new file mode 100644 index 000000000..7de6abefc --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_person_prohibited_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_pin_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_pin_24_regular.xml new file mode 100644 index 000000000..0dff766bc --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_pin_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_pin_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_pin_28_regular.xml new file mode 100644 index 000000000..cc5a4f204 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_pin_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_pin_off_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_pin_off_24_regular.xml new file mode 100644 index 000000000..cb69ef23b --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_pin_off_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_pin_off_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_pin_off_28_regular.xml new file mode 100644 index 000000000..523fa6031 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_pin_off_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_shield_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_shield_28_regular.xml new file mode 100644 index 000000000..30bf53796 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_shield_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_shield_prohibited_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_shield_prohibited_24_regular.xml new file mode 100644 index 000000000..a6d013610 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_shield_prohibited_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_speaker_2_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_speaker_2_24_regular.xml new file mode 100644 index 000000000..8ba6f262d --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_speaker_2_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_speaker_2_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_speaker_2_28_regular.xml new file mode 100644 index 000000000..486228e0e --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_speaker_2_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_speaker_mute_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_speaker_mute_24_regular.xml new file mode 100644 index 000000000..8cd5f52dc --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_speaker_mute_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_speaker_mute_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_speaker_mute_28_regular.xml new file mode 100644 index 000000000..b45d213d3 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_speaker_mute_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_star_28_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_star_28_regular.xml new file mode 100644 index 000000000..27e31d2bf --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_star_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_warning_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_warning_24_regular.xml new file mode 100644 index 000000000..fbb3813ca --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_warning_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_follow_selector.xml b/mastodon/src/main/res/drawable/ic_follow_selector.xml new file mode 100644 index 000000000..8cd4d4e92 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_follow_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mastodon/src/main/res/menu/post.xml b/mastodon/src/main/res/menu/post.xml index 9b876f64c..b0de637d0 100644 --- a/mastodon/src/main/res/menu/post.xml +++ b/mastodon/src/main/res/menu/post.xml @@ -1,16 +1,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/menu/profile.xml b/mastodon/src/main/res/menu/profile.xml index 097d1b40a..1f2a99a2d 100644 --- a/mastodon/src/main/res/menu/profile.xml +++ b/mastodon/src/main/res/menu/profile.xml @@ -1,11 +1,11 @@ - - - - - - - - + + + + + + + + \ No newline at end of file From db88de206b6f5355efab954dd0fccd9351dcc8e7 Mon Sep 17 00:00:00 2001 From: sk Date: Thu, 29 Dec 2022 17:14:38 +0100 Subject: [PATCH 067/133] add mention with quasi-quoting --- .../android/ui/displayitems/FooterStatusDisplayItem.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java index f9ab6364e..d517f1fd6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java @@ -279,7 +279,11 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ v.startAnimation(opacityIn); Bundle args=new Bundle(); args.putString("account", item.accountID); - args.putString("prefilledText", "\n\n" + item.status.url); + StringBuilder prefilledText = new StringBuilder().append("\n\n"); + String ownID = AccountSessionManager.getInstance().getAccount(item.accountID).self.id; + if (!item.status.account.id.equals(ownID)) prefilledText.append('@').append(item.status.account.acct).append(' '); + prefilledText.append(item.status.url); + args.putString("prefilledText", prefilledText.toString()); args.putInt("selectionStart", 0); Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); }); From 16c0866f7ff9c9395e155e5e3159a66d09c6ef44 Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Fri, 30 Dec 2022 14:12:10 -0300 Subject: [PATCH 068/133] It fucking compiles. Still a whole lot of stuff to be done --- ...c_fluent_mail_inbox_dismiss_24_regular.xml | 3 +++ ...c_fluent_mail_inbox_dismiss_28_regular.xml | 3 +++ .../drawable/ic_fluent_open_24_regular.xml | 3 +++ .../ic_fluent_sign_out_24_regular.xml | 3 +++ .../android/GlobalUserPreferences.java | 3 +++ .../api/StatusInteractionController.java | 26 ++++++++++++------- .../notifications/DismissNotification.java | 17 ++++++++++++ .../android/api/session/AccountSession.java | 12 ++++++++- .../android/fragments/ProfileFragment.java | 8 +++--- .../ui/text/ClickableLinksDelegate.java | 3 ++- .../android/ui/text/LinkSpan.java | 6 +++-- .../android/ui/utils/UiUtils.java | 1 + .../ic_fluent_person_swap_24_regular.xml | 3 +++ .../src/main/res/layout/item_boost_menu.xml | 14 ++++++++++ mastodon/src/main/res/menu/notifications.xml | 6 +++++ mastodon/src/main/res/values/strings_sk.xml | 13 ++++++++++ 16 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_24_regular.xml create mode 100644 mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml create mode 100644 mastodon/src/github/res/drawable/ic_fluent_open_24_regular.xml create mode 100644 mastodon/src/github/res/drawable/ic_fluent_sign_out_24_regular.xml create mode 100644 mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/DismissNotification.java create mode 100644 mastodon/src/main/res/drawable/ic_fluent_person_swap_24_regular.xml diff --git a/mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_24_regular.xml b/mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_24_regular.xml new file mode 100644 index 000000000..e32e4fab5 --- /dev/null +++ b/mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml b/mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml new file mode 100644 index 000000000..2ea945f3d --- /dev/null +++ b/mastodon/src/github/res/drawable/ic_fluent_mail_inbox_dismiss_28_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/github/res/drawable/ic_fluent_open_24_regular.xml b/mastodon/src/github/res/drawable/ic_fluent_open_24_regular.xml new file mode 100644 index 000000000..e18fe0aed --- /dev/null +++ b/mastodon/src/github/res/drawable/ic_fluent_open_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/github/res/drawable/ic_fluent_sign_out_24_regular.xml b/mastodon/src/github/res/drawable/ic_fluent_sign_out_24_regular.xml new file mode 100644 index 000000000..d20ea1330 --- /dev/null +++ b/mastodon/src/github/res/drawable/ic_fluent_sign_out_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java index ac3124565..19fd6cce8 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java +++ b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java @@ -30,6 +30,7 @@ public class GlobalUserPreferences{ public static boolean voteButtonForSingleChoice; public static boolean showDifferentiatedPushNoticationIcons; public static boolean relocatePublishButton; + public static boolean enableDeleteNotifications; public static ThemePreference theme; public static ColorPreference color; @@ -62,6 +63,7 @@ public class GlobalUserPreferences{ disableDividers=prefs.getBoolean("disableDividers", true); relocatePublishButton=prefs.getBoolean("relocatePublishButton", true); voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true); + enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", true); theme=ThemePreference.values()[prefs.getInt("theme", 0)]; recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>()); @@ -93,6 +95,7 @@ public class GlobalUserPreferences{ .putBoolean("disableDividers", disableDividers) .putBoolean("relocatePublishButton", relocatePublishButton) .putBoolean("showDifferentiatedPushNoticationIcons", showDifferentiatedPushNoticationIcons) + .putBoolean("enableDeleteNotifications", enableDeleteNotifications) .putInt("theme", theme.ordinal()) .putString("color", color.name()) .putString("recentLanguages", gson.toJson(recentLanguages)) diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/StatusInteractionController.java b/mastodon/src/main/java/org/joinmastodon/android/api/StatusInteractionController.java index 33df962bf..ec45b6d90 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/StatusInteractionController.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/StatusInteractionController.java @@ -19,12 +19,18 @@ import me.grishka.appkit.api.ErrorResponse; public class StatusInteractionController{ private final String accountID; + private final boolean updateCounters; private final HashMap runningFavoriteRequests=new HashMap<>(); private final HashMap runningReblogRequests=new HashMap<>(); private final HashMap runningBookmarkRequests=new HashMap<>(); - public StatusInteractionController(String accountID){ + public StatusInteractionController(String accountID, boolean updateCounters) { this.accountID=accountID; + this.updateCounters=updateCounters; + } + + public StatusInteractionController(String accountID){ + this(accountID, true); } public void setFavorited(Status status, boolean favorited, Consumer cb){ @@ -42,7 +48,7 @@ public class StatusInteractionController{ runningFavoriteRequests.remove(status.id); result.favouritesCount = Math.max(0, status.favouritesCount) + (favorited ? 1 : -1); cb.accept(result); - E.post(new StatusCountersUpdatedEvent(result)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(result)); } @Override @@ -51,13 +57,13 @@ public class StatusInteractionController{ error.showToast(MastodonApp.context); status.favourited=!favorited; cb.accept(status); - E.post(new StatusCountersUpdatedEvent(status)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(status)); } }) .exec(accountID); runningFavoriteRequests.put(status.id, req); status.favourited=favorited; - E.post(new StatusCountersUpdatedEvent(status)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(status)); } public void setReblogged(Status status, boolean reblogged, StatusPrivacy visibility, Consumer cb){ @@ -76,7 +82,7 @@ public class StatusInteractionController{ runningReblogRequests.remove(status.id); result.reblogsCount = Math.max(0, status.reblogsCount) + (reblogged ? 1 : -1); cb.accept(result); - E.post(new StatusCountersUpdatedEvent(result)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(result)); } @Override @@ -85,13 +91,13 @@ public class StatusInteractionController{ error.showToast(MastodonApp.context); status.reblogged=!reblogged; cb.accept(status); - E.post(new StatusCountersUpdatedEvent(status)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(status)); } }) .exec(accountID); runningReblogRequests.put(status.id, req); status.reblogged=reblogged; - E.post(new StatusCountersUpdatedEvent(status)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(status)); } public void setBookmarked(Status status, boolean bookmarked){ @@ -112,7 +118,7 @@ public class StatusInteractionController{ public void onSuccess(Status result){ runningBookmarkRequests.remove(status.id); cb.accept(result); - E.post(new StatusCountersUpdatedEvent(result)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(result)); } @Override @@ -121,12 +127,12 @@ public class StatusInteractionController{ error.showToast(MastodonApp.context); status.bookmarked=!bookmarked; cb.accept(status); - E.post(new StatusCountersUpdatedEvent(status)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(status)); } }) .exec(accountID); runningBookmarkRequests.put(status.id, req); status.bookmarked=bookmarked; - E.post(new StatusCountersUpdatedEvent(status)); + if (updateCounters) E.post(new StatusCountersUpdatedEvent(status)); } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/DismissNotification.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/DismissNotification.java new file mode 100644 index 000000000..5c2399774 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/DismissNotification.java @@ -0,0 +1,17 @@ +package org.joinmastodon.android.api.requests.notifications; + +import com.google.gson.reflect.TypeToken; + +import org.joinmastodon.android.api.ApiUtils; +import org.joinmastodon.android.api.MastodonAPIRequest; +import org.joinmastodon.android.model.Notification; + +import java.util.EnumSet; +import java.util.List; + +public class DismissNotification extends MastodonAPIRequest{ + public DismissNotification(String id){ + super(HttpMethod.POST, "/notifications/" + (id != null ? id + "/dismiss" : "clear"), Object.class); + setRequestBody(new Object()); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java index 735b19aca..e7fa19d9e 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java @@ -32,7 +32,7 @@ public class AccountSession{ public Preferences preferences; public AccountActivationInfo activationInfo; private transient MastodonAPIController apiController; - private transient StatusInteractionController statusInteractionController; + private transient StatusInteractionController statusInteractionController, remoteStatusInteractionController; private transient CacheController cacheController; private transient PushSubscriptionManager pushSubscriptionManager; @@ -52,6 +52,10 @@ public class AccountSession{ return domain+"_"+self.id; } + public String getFullUsername() { + return "@"+self.username+"@"+domain; + } + public MastodonAPIController getApiController(){ if(apiController==null) apiController=new MastodonAPIController(this); @@ -64,6 +68,12 @@ public class AccountSession{ return statusInteractionController; } + public StatusInteractionController getRemoteStatusInteractionController(){ + if(remoteStatusInteractionController==null) + remoteStatusInteractionController=new StatusInteractionController(getID(), false); + return remoteStatusInteractionController; + } + public CacheController getCacheController(){ if(cacheController==null) cacheController=new CacheController(getID()); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java index 713140adb..4599f1049 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java @@ -292,11 +292,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList followingBtn.setOnClickListener(this::onFollowersOrFollowingClick); username.setOnLongClickListener(v->{ - String username=account.acct; - if(!username.contains("@")){ - username+="@"+AccountSessionManager.getInstance().getAccount(accountID).domain; + String usernameString=account.acct; + if(!usernameString.contains("@")){ + usernameString+="@"+AccountSessionManager.getInstance().getAccount(accountID).domain; } - UiUtils.copyText(getActivity(), '@'+username); + UiUtils.copyText(username, '@'+usernameString); return true; }); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/text/ClickableLinksDelegate.java b/mastodon/src/main/java/org/joinmastodon/android/ui/text/ClickableLinksDelegate.java index e3a1bfc61..15ba797b0 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/text/ClickableLinksDelegate.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/text/ClickableLinksDelegate.java @@ -24,9 +24,10 @@ public class ClickableLinksDelegate { private TextView view; private final Runnable longClickRunnable = () -> { - if (selectedSpan != null) selectedSpan.onLongClick(view.getContext()); + if (selectedSpan != null) selectedSpan.onLongClick(view); }; + public ClickableLinksDelegate(TextView view) { this.view=view; hlPaint=new Paint(); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java b/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java index 9cc570efe..8379a6922 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java @@ -3,6 +3,7 @@ package org.joinmastodon.android.ui.text; import android.content.Context; import android.text.TextPaint; import android.text.style.CharacterStyle; +import android.view.View; import org.joinmastodon.android.ui.utils.UiUtils; @@ -40,10 +41,11 @@ public class LinkSpan extends CharacterStyle { } } - public void onLongClick(Context context) { - UiUtils.copyText(context, getType() == Type.URL ? link : text); + public void onLongClick(View view) { + UiUtils.copyText(view, getType() == Type.URL ? link : text); } + public String getLink(){ return link; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index fe28da756..376b47987 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -55,6 +55,7 @@ import org.joinmastodon.android.api.requests.accounts.SetAccountMuted; import org.joinmastodon.android.api.requests.accounts.SetDomainBlocked; import org.joinmastodon.android.api.requests.accounts.AuthorizeFollowRequest; import org.joinmastodon.android.api.requests.accounts.RejectFollowRequest; +//import org.joinmastodon.android.api.requests.notification.DismissNotification; import org.joinmastodon.android.api.requests.notifications.DismissNotification; import org.joinmastodon.android.api.requests.search.GetSearchResults; import org.joinmastodon.android.api.requests.statuses.DeleteStatus; diff --git a/mastodon/src/main/res/drawable/ic_fluent_person_swap_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_person_swap_24_regular.xml new file mode 100644 index 000000000..8b7c650c8 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_person_swap_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/layout/item_boost_menu.xml b/mastodon/src/main/res/layout/item_boost_menu.xml index fa19a8f6c..91069afcb 100644 --- a/mastodon/src/main/res/layout/item_boost_menu.xml +++ b/mastodon/src/main/res/layout/item_boost_menu.xml @@ -78,6 +78,20 @@ android:layout_width="match_parent" android:layout_marginVertical="8dp" android:background="?colorPollVoted" /> + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/strings_sk.xml b/mastodon/src/main/res/values/strings_sk.xml index be97d90e6..a25e7bb3a 100644 --- a/mastodon/src/main/res/values/strings_sk.xml +++ b/mastodon/src/main/res/values/strings_sk.xml @@ -94,4 +94,17 @@ Hashtags you follow Copy link to post Open in other account + Open with other account + Bookmark in other account + Bookmarked as %s + Already bookmarked + Favorite from other account + Favorited as %s + Already favorited + Reblog from other account + Reblogged as %s + Already reblogged + Reply with other account + Resource could not be found + Looking it up on %s \ No newline at end of file From dccd9dcb97ff34da42abf932c51edc46e39e4c6a Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Fri, 30 Dec 2022 19:42:16 -0300 Subject: [PATCH 069/133] Editing the InstanceRulesFragment for allowing a more coherent color scheme --- .../fragments/onboarding/InstanceRulesFragment.java | 7 ++++--- mastodon/src/main/res/layout/fragment_onboarding_rules.xml | 1 + mastodon/src/main/res/layout/item_list_header_simple.xml | 1 - mastodon/src/main/res/layout/item_server_rule.xml | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/onboarding/InstanceRulesFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/onboarding/InstanceRulesFragment.java index c3ab13586..4c0bf0135 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/onboarding/InstanceRulesFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/onboarding/InstanceRulesFragment.java @@ -2,6 +2,7 @@ package org.joinmastodon.android.fragments.onboarding; import android.annotation.SuppressLint; import android.app.Activity; +import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; @@ -65,7 +66,7 @@ public class InstanceRulesFragment extends ToolbarFragment{ adapter.addAdapter(new SingleViewRecyclerAdapter(headerView)); adapter.addAdapter(new ItemsAdapter()); list.setAdapter(adapter); - list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorM3SurfaceVariant, 1, 56, 0, DividerItemDecoration.NOT_FIRST)); + list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1, 56, 0, DividerItemDecoration.NOT_FIRST)); btn=view.findViewById(R.id.btn_next); btn.setOnClickListener(v->onButtonClick()); @@ -77,8 +78,8 @@ public class InstanceRulesFragment extends ToolbarFragment{ @Override public void onViewCreated(View view, Bundle savedInstanceState){ super.onViewCreated(view, savedInstanceState); - setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background)); - view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background)); +// setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background)); +// view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background)); } // @Override diff --git a/mastodon/src/main/res/layout/fragment_onboarding_rules.xml b/mastodon/src/main/res/layout/fragment_onboarding_rules.xml index 1ccbf4afd..b531e4c79 100644 --- a/mastodon/src/main/res/layout/fragment_onboarding_rules.xml +++ b/mastodon/src/main/res/layout/fragment_onboarding_rules.xml @@ -26,6 +26,7 @@ android:layout_marginBottom="16dp" android:minWidth="145dp" style="@style/Widget.Mastodon.M3.Button.Filled" + android:visibility="gone" android:text="@string/i_agree" /> diff --git a/mastodon/src/main/res/layout/item_list_header_simple.xml b/mastodon/src/main/res/layout/item_list_header_simple.xml index 0caf3ec73..6b8b358bd 100644 --- a/mastodon/src/main/res/layout/item_list_header_simple.xml +++ b/mastodon/src/main/res/layout/item_list_header_simple.xml @@ -4,7 +4,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="@style/m3_body_large" - android:textColor="?colorM3OnSurface" android:paddingStart="56dp" android:paddingTop="12dp" android:paddingEnd="24dp" diff --git a/mastodon/src/main/res/layout/item_server_rule.xml b/mastodon/src/main/res/layout/item_server_rule.xml index ad25fbc1d..9930af222 100644 --- a/mastodon/src/main/res/layout/item_server_rule.xml +++ b/mastodon/src/main/res/layout/item_server_rule.xml @@ -15,7 +15,7 @@ android:layout_width="24dp" android:layout_height="24dp" android:layout_marginEnd="16dp" - android:textColor="?colorM3Primary" + android:textColor="?android:colorAccent" android:fontFamily="sans-serif-condensed" android:textStyle="bold" android:textSize="22dp" From 1554c6d422e1d199f67c979c820238818841ba2e Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Fri, 30 Dec 2022 19:43:07 -0300 Subject: [PATCH 070/133] Editing settings page --- .../android/fragments/SettingsFragment.java | 24 ++++++++++++------- .../ic_fluent_task_list_ltr_24_regular.xml | 3 +++ 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 mastodon/src/main/res/drawable-xxxhdpi/ic_fluent_task_list_ltr_24_regular.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java index 003ea8331..c39a28fb3 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java @@ -47,6 +47,7 @@ import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.SelfUpdateStateChangedEvent; +import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment; import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.PushNotification; import org.joinmastodon.android.model.PushSubscription; @@ -54,6 +55,7 @@ import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.OutlineProviders; import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.updater.GithubSelfUpdater; +import org.parceler.Parcels; import java.util.ArrayList; import java.util.function.Consumer; @@ -63,6 +65,8 @@ import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + +import me.grishka.appkit.Nav; import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.imageloader.ImageCache; @@ -205,7 +209,11 @@ public class SettingsFragment extends MastodonToolbarFragment{ items.add(new TextItem(R.string.settings_privacy_policy, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms"))); items.add(new HeaderItem(instance != null ? instance.title : session.domain)); - items.add(new TextItem(R.string.sk_settings_rules, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/about"), R.drawable.ic_fluent_open_24_regular)); + items.add(new TextItem(R.string.sk_settings_rules, ()->{ + Bundle args=new Bundle(); + args.putParcelable("instance", Parcels.wrap(instance)); + Nav.go(getActivity(), InstanceRulesFragment.class, args); + }, R.drawable.ic_fluent_task_list_ltr_24_regular)); items.add(new TextItem(R.string.settings_tos, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms"), R.drawable.ic_fluent_open_24_regular)); items.add(new TextItem(R.string.settings_privacy_policy, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/terms"), R.drawable.ic_fluent_open_24_regular)); items.add(new TextItem(R.string.log_out, this::confirmLogOut, R.drawable.ic_fluent_sign_out_24_regular)); @@ -216,13 +224,13 @@ public class SettingsFragment extends MastodonToolbarFragment{ items.add(new HeaderItem(R.string.sk_settings_about)); - items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon"), R.drawable.ic_fluent_open_24_regular)); - items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://ko-fi.com/xsk22"), R.drawable.ic_fluent_heart_24_regular)); - if (GithubSelfUpdater.needSelfUpdating()) { - checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates); - items.add(checkForUpdateItem); - } - items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon"))); +// items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon"), R.drawable.ic_fluent_open_24_regular)); +// items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://ko-fi.com/xsk22"), R.drawable.ic_fluent_heart_24_regular)); +// if (GithubSelfUpdater.needSelfUpdating()) { +// checkForUpdateItem = new TextItem(R.string.sk_check_for_update, GithubSelfUpdater.getInstance()::checkForUpdates); +// items.add(checkForUpdateItem); +// } + items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/LucasGGamerM/moshidon"), R.drawable.ic_fluent_open_24_regular)); items.add(new TextItem(R.string.sk_settings_donate, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sponsors/LucasGGamerM"), R.drawable.ic_fluent_heart_24_regular)); items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache)); items.add(new TextItem(R.string.sk_clear_recent_languages, ()->UiUtils.showConfirmationAlert(getActivity(), R.string.sk_clear_recent_languages, R.string.sk_confirm_clear_recent_languages, R.string.clear, ()->{ diff --git a/mastodon/src/main/res/drawable-xxxhdpi/ic_fluent_task_list_ltr_24_regular.xml b/mastodon/src/main/res/drawable-xxxhdpi/ic_fluent_task_list_ltr_24_regular.xml new file mode 100644 index 000000000..d000a4700 --- /dev/null +++ b/mastodon/src/main/res/drawable-xxxhdpi/ic_fluent_task_list_ltr_24_regular.xml @@ -0,0 +1,3 @@ + + + From 54106c497b305d480e21dc4a747fd637bdaa466a Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Fri, 30 Dec 2022 20:00:11 -0300 Subject: [PATCH 071/133] Unfucking your own profile icons. They now look how they should --- .../org/joinmastodon/android/fragments/ProfileFragment.java | 2 +- mastodon/src/main/res/menu/profile_own.xml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java index 4599f1049..a3a4cbf51 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java @@ -553,7 +553,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList if(relationship==null && !isOwnProfile) return; inflater.inflate(isOwnProfile ? R.menu.profile_own : R.menu.profile, menu); - UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags); +// UiUtils.enableOptionsMenuIcons(getActivity(), menu, R.id.bookmarks, R.id.followed_hashtags); menu.findItem(R.id.share).setTitle(getString(R.string.share_user, account.getDisplayUsername())); if(isOwnProfile) return; diff --git a/mastodon/src/main/res/menu/profile_own.xml b/mastodon/src/main/res/menu/profile_own.xml index 4d5de8519..2e7539b05 100644 --- a/mastodon/src/main/res/menu/profile_own.xml +++ b/mastodon/src/main/res/menu/profile_own.xml @@ -1,7 +1,8 @@ - - + + + \ No newline at end of file From a881f23253adc1bcb2ec3ae44c2ce4454e1163f4 Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Fri, 30 Dec 2022 20:23:13 -0300 Subject: [PATCH 072/133] Fixing the PublishButton background and also fixing the Fab icon background on trueblack theme. Its a relevant thing, i beliebe you shall merge this @sk22 --- mastodon/src/main/res/values/styles.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mastodon/src/main/res/values/styles.xml b/mastodon/src/main/res/values/styles.xml index 23ada039d..22c862d53 100644 --- a/mastodon/src/main/res/values/styles.xml +++ b/mastodon/src/main/res/values/styles.xml @@ -19,7 +19,7 @@ ?colorGray800 ?colorGray500 ?colorGray50 - #E9EDF2 + ?colorGray200 ?colorGray50 ?colorGray25 ?colorBackgroundLightest @@ -116,7 +116,7 @@ ?colorGray50 ?colorGray400 ?colorGray800 - #E9EDF2 + ?colorGray200 ?colorGray700 ?colorGray900 ?colorBackgroundLightest @@ -207,7 +207,7 @@ ?colorGray900 @color/black ?android:colorAccent - ?colorGray900 + ?colorGray100 #000 From 99e365893850a08a882267885660a72cd18e7a5f Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Sat, 31 Dec 2022 12:49:16 -0300 Subject: [PATCH 073/133] Making fab feel better on light themes. Merging this might be good for you too, @sk22 --- mastodon/src/main/res/values/styles.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mastodon/src/main/res/values/styles.xml b/mastodon/src/main/res/values/styles.xml index 22c862d53..77ad35a75 100644 --- a/mastodon/src/main/res/values/styles.xml +++ b/mastodon/src/main/res/values/styles.xml @@ -38,7 +38,7 @@ ?colorPrimary100 ?colorGray500 ?colorGray50 - ?colorBackgroundPopup + ?colorGray50 ?android:textColorPrimary @style/Widget.Mastodon.Button.Compose From 3a962c7c0547a002ab15c075dae617f5fef91bb0 Mon Sep 17 00:00:00 2001 From: LucasGGamerM Date: Sat, 31 Dec 2022 13:47:55 -0300 Subject: [PATCH 074/133] Refactoring the uniform notification icon setting --- .../joinmastodon/android/GlobalUserPreferences.java | 6 +++--- .../joinmastodon/android/PushNotificationReceiver.java | 4 +--- .../android/fragments/SettingsFragment.java | 10 ++++------ mastodon/src/main/res/values/strings_sk.xml | 1 + 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java index 19fd6cce8..cebb4ab61 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java +++ b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java @@ -28,7 +28,7 @@ public class GlobalUserPreferences{ public static boolean disableSwipe; public static boolean disableDividers; public static boolean voteButtonForSingleChoice; - public static boolean showDifferentiatedPushNoticationIcons; + public static boolean showUniformPushNoticationIcons; public static boolean relocatePublishButton; public static boolean enableDeleteNotifications; public static ThemePreference theme; @@ -54,7 +54,7 @@ public class GlobalUserPreferences{ showReplies=prefs.getBoolean("showReplies", true); showBoosts=prefs.getBoolean("showBoosts", true); loadNewPosts=prefs.getBoolean("loadNewPosts", true); - showDifferentiatedPushNoticationIcons=prefs.getBoolean("showDifferentiatedPushNoticationIcons", false); + showUniformPushNoticationIcons=prefs.getBoolean("showUniformPushNotificationIcons", true); showFederatedTimeline=prefs.getBoolean("showFederatedTimeline", !BuildConfig.BUILD_TYPE.equals("playRelease")); showInteractionCounts=prefs.getBoolean("showInteractionCounts", false); alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false); @@ -94,7 +94,7 @@ public class GlobalUserPreferences{ .putBoolean("disableSwipe", disableSwipe) .putBoolean("disableDividers", disableDividers) .putBoolean("relocatePublishButton", relocatePublishButton) - .putBoolean("showDifferentiatedPushNoticationIcons", showDifferentiatedPushNoticationIcons) + .putBoolean("showUniformPushNotificationIcons", showUniformPushNoticationIcons) .putBoolean("enableDeleteNotifications", enableDeleteNotifications) .putInt("theme", theme.ordinal()) .putString("color", color.name()) diff --git a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java index d56356ded..3a8f01861 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java @@ -8,9 +8,7 @@ import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; @@ -143,7 +141,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{ .setCategory(Notification.CATEGORY_SOCIAL) .setAutoCancel(true) .setColor(context.getColor(R.color.shortcut_icon_background)); - if(GlobalUserPreferences.showDifferentiatedPushNoticationIcons){ + if(!GlobalUserPreferences.showUniformPushNoticationIcons){ switch (pn.notificationType) { case FAVORITE -> builder.setSmallIcon(R.drawable.ic_fluent_star_24_filled); case REBLOG -> builder.setSmallIcon(R.drawable.ic_fluent_arrow_repeat_all_24_filled); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java index c39a28fb3..cedc401b8 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java @@ -10,7 +10,6 @@ import android.graphics.Rect; import android.os.Build; import android.os.Bundle; import android.util.TypedValue; - import android.provider.Settings; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; @@ -20,8 +19,6 @@ import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.LinearInterpolator; import android.widget.Button; -import android.widget.EditText; -import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; @@ -131,6 +128,7 @@ public class SettingsFragment extends MastodonToolbarFragment{ case NORD -> R.string.sk_color_palette_nord; }); })); + items.add(new SwitchItem(R.string.sk_settings_uniform_icon_for_notifications, R.drawable.ic_ntf_logo, GlobalUserPreferences.showUniformPushNoticationIcons, this::onNotificationStyleChanged)); items.add(new HeaderItem(R.string.settings_behavior)); items.add(new SwitchItem(R.string.sk_settings_show_federated_timeline, R.drawable.ic_fluent_earth_24_regular, GlobalUserPreferences.showFederatedTimeline, i->{ @@ -159,7 +157,7 @@ public class SettingsFragment extends MastodonToolbarFragment{ GlobalUserPreferences.save(); needAppRestart=true; })); - items.add(new SwitchItem(R.string.sk_settings_show_differentiated_notification_icons, R.drawable.ic_fluent_earth_24_regular, GlobalUserPreferences.showDifferentiatedPushNoticationIcons, this::onNotificationStyleChanged)); +// items.add(new SwitchItem(R.string.sk_settings_show_differentiated_notification_icons, R.drawable.ic_ntf_logo, GlobalUserPreferences.showUniformPushNoticationIcons, this::onNotificationStyleChanged)); items.add(new SwitchItem(R.string.sk_disable_dividers, R.drawable.ic_fluent_timeline_24_regular, GlobalUserPreferences.disableDividers, i->{ GlobalUserPreferences.disableDividers=i.checked; GlobalUserPreferences.save(); @@ -237,7 +235,7 @@ public class SettingsFragment extends MastodonToolbarFragment{ GlobalUserPreferences.recentLanguages.remove(accountID); GlobalUserPreferences.save(); }))); - items.add(new TextItem(R.string.log_out, this::confirmLogOut)); +// items.add(new TextItem(R.string.log_out, this::confirmLogOut)); items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE))); } @@ -402,7 +400,7 @@ public class SettingsFragment extends MastodonToolbarFragment{ } private void onNotificationStyleChanged(SwitchItem item){ - GlobalUserPreferences.showDifferentiatedPushNoticationIcons=item.checked; + GlobalUserPreferences.showUniformPushNoticationIcons=item.checked; GlobalUserPreferences.save(); } diff --git a/mastodon/src/main/res/values/strings_sk.xml b/mastodon/src/main/res/values/strings_sk.xml index a25e7bb3a..fece608f0 100644 --- a/mastodon/src/main/res/values/strings_sk.xml +++ b/mastodon/src/main/res/values/strings_sk.xml @@ -107,4 +107,5 @@ Reply with other account Resource could not be found Looking it up on %s + Uniform icon for all notifications \ No newline at end of file From 98b96c78d713c6ff2b5d23f853d1b27cb386374a Mon Sep 17 00:00:00 2001 From: Thiago 'Jedi' Abreu Date: Thu, 29 Dec 2022 09:32:22 -0300 Subject: [PATCH 075/133] Better handling of filter expiration date (#212) * Better handling of filter expiration date * Simplify Thread and Home Timeline filtering --- .../fragments/HomeTimelineFragment.java | 19 +++++++------------ .../android/fragments/ThreadFragment.java | 16 +++++----------- .../joinmastodon/android/model/Filter.java | 10 ++++++++++ .../android/utils/StatusFilterPredicate.java | 11 +++++++++++ 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 19c13e1c9..c659bc3ff 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -19,9 +19,11 @@ import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; -import android.widget.TextView; import android.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + import com.squareup.otto.Subscribe; import org.joinmastodon.android.E; @@ -43,12 +45,9 @@ import org.joinmastodon.android.utils.StatusFilterPredicate; import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; import me.grishka.appkit.Nav; import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.ErrorResponse; @@ -266,18 +265,14 @@ public class HomeTimelineFragment extends StatusListFragment{ List targetList=displayItems.subList(gapPos, gapPos+1); targetList.clear(); List insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1); - List filters=AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream().filter(f->f.context.contains(Filter.FilterContext.HOME)).collect(Collectors.toList()); - outer: + StatusFilterPredicate filterPredicate=new StatusFilterPredicate(accountID, Filter.FilterContext.HOME); for(Status s:result){ if(idsBelowGap.contains(s.id)) break; - for(Filter filter:filters){ - if(filter.matches(s)){ - continue outer; - } + if(filterPredicate.test(s)){ + targetList.addAll(buildDisplayItems(s)); + insertedPosts.add(s); } - targetList.addAll(buildDisplayItems(s)); - insertedPosts.add(s); } if(targetList.isEmpty()){ // oops. We didn't add new posts, but at least we know there are none. diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java index 4578617c4..b4de4d184 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java @@ -5,7 +5,6 @@ import android.view.View; import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.statuses.GetStatusContext; -import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.events.StatusCreatedEvent; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Filter; @@ -17,6 +16,7 @@ import org.joinmastodon.android.ui.displayitems.StatusDisplayItem; import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem; import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.utils.UiUtils; +import org.joinmastodon.android.utils.StatusFilterPredicate; import org.parceler.Parcels; import java.util.Collections; @@ -92,16 +92,10 @@ public class ThreadFragment extends StatusListFragment{ } private List filterStatuses(List statuses){ - List filters=AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream().filter(f->f.context.contains(Filter.FilterContext.THREAD)).collect(Collectors.toList()); - if(filters.isEmpty()) - return statuses; - return statuses.stream().filter(status->{ - for(Filter filter:filters){ - if(filter.matches(status)) - return false; - } - return true; - }).collect(Collectors.toList()); + StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,Filter.FilterContext.THREAD); + return statuses.stream() + .filter(statusFilterPredicate) + .collect(Collectors.toList()); } @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/Filter.java b/mastodon/src/main/java/org/joinmastodon/android/model/Filter.java index 8a629a290..f7b394765 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/Filter.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/Filter.java @@ -6,12 +6,14 @@ import com.google.gson.annotations.SerializedName; import org.joinmastodon.android.api.ObjectValidationException; import org.joinmastodon.android.api.RequiredField; +import org.parceler.Parcel; import java.time.Instant; import java.util.EnumSet; import java.util.List; import java.util.regex.Pattern; +@Parcel public class Filter extends BaseModel{ @RequiredField public String id; @@ -21,6 +23,7 @@ public class Filter extends BaseModel{ public Instant expiresAt; public boolean irreversible; public boolean wholeWord; + public FilterAction filterAction; @SerializedName("context") private List _context; @@ -76,4 +79,11 @@ public class Filter extends BaseModel{ @SerializedName("thread") THREAD } + + public enum FilterAction{ + @SerializedName("hide") + HIDE, + @SerializedName("warn") + WARN + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/utils/StatusFilterPredicate.java b/mastodon/src/main/java/org/joinmastodon/android/utils/StatusFilterPredicate.java index cf9e0829f..4555cdfdb 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/utils/StatusFilterPredicate.java +++ b/mastodon/src/main/java/org/joinmastodon/android/utils/StatusFilterPredicate.java @@ -4,6 +4,7 @@ import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Filter; import org.joinmastodon.android.model.Status; +import java.time.Instant; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -21,6 +22,16 @@ public class StatusFilterPredicate implements Predicate{ @Override public boolean test(Status status){ + if(status.filtered!=null){ + if (status.filtered.isEmpty()){ + return true; + } + boolean matches=status.filtered.stream() + .map(filterResult->filterResult.filter) + .filter(filter->filter.expiresAt==null||filter.expiresAt.isAfter(Instant.now())) + .anyMatch(filter->filter.filterAction==Filter.FilterAction.HIDE); + return !matches; + } for(Filter filter:filters){ if(filter.matches(status)) return false; From 074efb0813587259dd935c696ba9e31560eff2c5 Mon Sep 17 00:00:00 2001 From: sk22 Date: Thu, 29 Dec 2022 12:53:18 -0300 Subject: [PATCH 076/133] Drafts and scheduled posts (#217) closes #100 closes #59 * enable saving as draft (scheduled) * add scheduled posts list * fix NoSuchMethodError * editable drafts/scheduled posts * ui for drafts * use instants between 9999-01-01 and 9999-12-31 * use save and draft strings * map scheduled status params to status * implement scheduling posts * improve save/discard draft dialog * persist scheduled date in state * add unsent posts button to toolbar * clean up imports --- .../api/requests/statuses/CreateStatus.java | 18 ++ .../api/requests/statuses/DeleteStatus.java | 6 + .../statuses/GetScheduledStatuses.java | 16 + .../events/ScheduledStatusCreatedEvent.java | 13 + .../events/ScheduledStatusDeletedEvent.java | 13 + .../android/fragments/ComposeFragment.java | 274 +++++++++++++++--- .../fragments/NotificationsListFragment.java | 9 +- .../android/fragments/ProfileFragment.java | 4 + .../ScheduledStatusListFragment.java | 143 +++++++++ .../org/joinmastodon/android/model/Poll.java | 5 + .../android/model/ScheduledStatus.java | 79 +++++ .../displayitems/HeaderStatusDisplayItem.java | 116 ++++++-- .../ui/displayitems/StatusDisplayItem.java | 8 +- .../android/ui/utils/UiUtils.java | 29 +- .../drawable/ic_fluent_clock_20_regular.xml | 3 + .../drawable/ic_fluent_clock_24_filled.xml | 3 + .../drawable/ic_fluent_clock_24_regular.xml | 3 + .../drawable/ic_fluent_clock_24_selector.xml | 8 + .../drawable/ic_fluent_drafts_20_regular.xml | 3 + .../drawable/ic_fluent_drafts_24_regular.xml | 3 + .../src/main/res/layout/fragment_compose.xml | 220 +++++++++----- mastodon/src/main/res/menu/profile_own.xml | 2 +- mastodon/src/main/res/menu/schedule_draft.xml | 5 + mastodon/src/main/res/values/strings_sk.xml | 26 +- mastodon/src/main/res/values/styles.xml | 15 + 25 files changed, 854 insertions(+), 170 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/GetScheduledStatuses.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusCreatedEvent.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusDeletedEvent.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/fragments/ScheduledStatusListFragment.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/model/ScheduledStatus.java create mode 100644 mastodon/src/main/res/drawable/ic_fluent_clock_20_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_clock_24_filled.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_clock_24_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_clock_24_selector.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_drafts_20_regular.xml create mode 100644 mastodon/src/main/res/drawable/ic_fluent_drafts_24_regular.xml create mode 100644 mastodon/src/main/res/menu/schedule_draft.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/CreateStatus.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/CreateStatus.java index bdb9dd14d..6a9c0cea1 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/CreateStatus.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/CreateStatus.java @@ -1,6 +1,7 @@ package org.joinmastodon.android.api.requests.statuses; import org.joinmastodon.android.api.MastodonAPIRequest; +import org.joinmastodon.android.model.ScheduledStatus; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.StatusPrivacy; @@ -9,12 +10,29 @@ import java.util.ArrayList; import java.util.List; public class CreateStatus extends MastodonAPIRequest{ + public static final Instant DRAFTS_AFTER_INSTANT = Instant.ofEpochMilli(253370764799999L) /* end of 9998 */; + private static final float draftFactor = 31536000000f /* one year */ / 253370764799999f /* end of 9998 */; + + public static Instant getDraftInstant() { + // returns an instant between 9999-01-01 00:00:00 and 9999-12-31 23:59:59 + // yes, this is a weird implementation for something that hardly matters + return DRAFTS_AFTER_INSTANT.plusMillis(1 + (long) (System.currentTimeMillis() * draftFactor)); + } + public CreateStatus(CreateStatus.Request req, String uuid){ super(HttpMethod.POST, "/statuses", Status.class); setRequestBody(req); addHeader("Idempotency-Key", uuid); } + public static class Scheduled extends MastodonAPIRequest{ + public Scheduled(CreateStatus.Request req, String uuid){ + super(HttpMethod.POST, "/statuses", ScheduledStatus.class); + setRequestBody(req); + addHeader("Idempotency-Key", uuid); + } + } + public static class Request{ public String status; public List mediaIds; diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java index edc8a70bc..3730a64f6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java @@ -7,4 +7,10 @@ public class DeleteStatus extends MastodonAPIRequest{ public DeleteStatus(String id){ super(HttpMethod.DELETE, "/statuses/"+id, Status.class); } + + public static class Scheduled extends MastodonAPIRequest { + public Scheduled(String id) { + super(HttpMethod.DELETE, "/scheduled_statuses/"+id, Object.class); + } + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/GetScheduledStatuses.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/GetScheduledStatuses.java new file mode 100644 index 000000000..fec163f2f --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/GetScheduledStatuses.java @@ -0,0 +1,16 @@ +package org.joinmastodon.android.api.requests.statuses; + +import com.google.gson.reflect.TypeToken; + +import org.joinmastodon.android.api.requests.HeaderPaginationRequest; +import org.joinmastodon.android.model.ScheduledStatus; + +public class GetScheduledStatuses extends HeaderPaginationRequest{ + public GetScheduledStatuses(String maxID, int limit){ + super(HttpMethod.GET, "/scheduled_statuses", new TypeToken<>(){}); + if(maxID!=null) + addQueryParameter("max_id", maxID); + if(limit>0) + addQueryParameter("limit", limit+""); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusCreatedEvent.java b/mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusCreatedEvent.java new file mode 100644 index 000000000..b11fb2375 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusCreatedEvent.java @@ -0,0 +1,13 @@ +package org.joinmastodon.android.events; + +import org.joinmastodon.android.model.ScheduledStatus; + +public class ScheduledStatusCreatedEvent { + public final ScheduledStatus scheduledStatus; + public final String accountID; + + public ScheduledStatusCreatedEvent(ScheduledStatus scheduledStatus, String accountID){ + this.scheduledStatus = scheduledStatus; + this.accountID=accountID; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusDeletedEvent.java b/mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusDeletedEvent.java new file mode 100644 index 000000000..96aaeac26 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/events/ScheduledStatusDeletedEvent.java @@ -0,0 +1,13 @@ +package org.joinmastodon.android.events; + +import org.joinmastodon.android.model.ScheduledStatus; + +public class ScheduledStatusDeletedEvent{ + public final String id; + public final String accountID; + + public ScheduledStatusDeletedEvent(String id, String accountID){ + this.id=id; + this.accountID=accountID; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java index 704756cf2..22f4ca314 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java @@ -1,12 +1,16 @@ package org.joinmastodon.android.fragments; import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages; +import static org.joinmastodon.android.api.requests.statuses.CreateStatus.DRAFTS_AFTER_INSTANT; +import static org.joinmastodon.android.api.requests.statuses.CreateStatus.getDraftInstant; import static org.joinmastodon.android.utils.MastodonLanguage.allLanguages; import static org.joinmastodon.android.utils.MastodonLanguage.defaultRecentLanguages; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.DatePickerDialog; +import android.app.TimePickerDialog; import android.content.ClipData; import android.content.Context; import android.content.Intent; @@ -32,8 +36,8 @@ import android.text.Layout; import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.format.DateFormat; import android.util.Log; -import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; @@ -67,13 +71,15 @@ import org.joinmastodon.android.R; import org.joinmastodon.android.api.MastodonAPIController; import org.joinmastodon.android.api.MastodonErrorResponse; import org.joinmastodon.android.api.ProgressListener; -import org.joinmastodon.android.api.requests.accounts.GetPreferences; import org.joinmastodon.android.api.requests.statuses.CreateStatus; +import org.joinmastodon.android.api.requests.statuses.DeleteStatus; import org.joinmastodon.android.api.requests.statuses.EditStatus; import org.joinmastodon.android.api.requests.statuses.GetAttachmentByID; import org.joinmastodon.android.api.requests.statuses.UploadAttachment; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; +import org.joinmastodon.android.events.ScheduledStatusCreatedEvent; +import org.joinmastodon.android.events.ScheduledStatusDeletedEvent; import org.joinmastodon.android.events.StatusCountersUpdatedEvent; import org.joinmastodon.android.events.StatusCreatedEvent; import org.joinmastodon.android.events.StatusUpdatedEvent; @@ -85,6 +91,7 @@ import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.Mention; import org.joinmastodon.android.model.Poll; import org.joinmastodon.android.model.Preferences; +import org.joinmastodon.android.model.ScheduledStatus; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.StatusPrivacy; import org.joinmastodon.android.ui.ComposeAutocompleteViewController; @@ -109,6 +116,12 @@ import org.parceler.Parcels; import java.io.InterruptedIOException; import java.net.SocketException; import java.net.UnknownHostException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; @@ -154,9 +167,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr private String accountID; private int charCount, charLimit, trimmedCharCount; - private Button publishButton, languageButton; - private PopupMenu languagePopup, visibilityPopup; - private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn; + private Button publishButton, languageButton, scheduleTimeBtn; + private PopupMenu languagePopup, visibilityPopup, scheduleDraftPopup; + private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn, scheduleBtn, scheduleDraftDismiss; private ImageView sensitiveIcon; private ComposeMediaLayout attachmentsView; private TextView replyText; @@ -165,6 +178,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr private View addPollOptionBtn; private View sensitiveItem; private View pollAllowMultipleItem; + private View scheduleDraftView; + private TextView scheduleDraftText; private CheckBox pollAllowMultipleCheckbox; private TextView pollDurationView; @@ -182,6 +197,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr private EditText spoilerEdit; private boolean hasSpoiler; private boolean sensitive; + private Instant scheduledAt = null; private ProgressBar sendProgress; private ImageView sendError; private View sendingOverlay; @@ -194,6 +210,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr private boolean attachmentsErrorShowing; private Status editingStatus; + private ScheduledStatus scheduledStatus; private boolean redraftStatus; private boolean pollChanged; private boolean creatingView; @@ -219,9 +236,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr customEmojis=AccountSessionManager.getInstance().getCustomEmojis(instanceDomain); instance=AccountSessionManager.getInstance().getInstanceInfo(instanceDomain); languageResolver=new MastodonLanguage.LanguageResolver(instance); + redraftStatus=getArguments().getBoolean("redraftStatus", false); if(getArguments().containsKey("editStatus")){ editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus")); - redraftStatus=getArguments().getBoolean("redraftStatus"); } if(instance==null){ Nav.finish(this); @@ -231,6 +248,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr AccountSessionManager.getInstance().updateInstanceInfo(instanceDomain); } + // sorry about all this ugly code, but i can't find any consistency in ComposeFragment.java + Bundle bundle = savedInstanceState != null ? savedInstanceState : getArguments(); + if (bundle.containsKey("scheduledStatus")) scheduledStatus=Parcels.unwrap(bundle.getParcelable("scheduledStatus")); + if (bundle.containsKey("scheduledAt")) scheduledAt=(Instant) bundle.getSerializable("scheduledAt"); + if(instance.maxTootChars>0) charLimit=instance.maxTootChars; else if(instance.configuration!=null && instance.configuration.statuses!=null && instance.configuration.statuses.maxCharacters>0) @@ -295,6 +317,11 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr emojiBtn=view.findViewById(R.id.btn_emoji); spoilerBtn=view.findViewById(R.id.btn_spoiler); visibilityBtn=view.findViewById(R.id.btn_visibility); + scheduleBtn=view.findViewById(R.id.btn_schedule); + scheduleDraftView=view.findViewById(R.id.schedule_draft_view); + scheduleDraftText=view.findViewById(R.id.schedule_draft_text); + scheduleDraftDismiss=view.findViewById(R.id.schedule_draft_dismiss); + scheduleTimeBtn=view.findViewById(R.id.scheduled_time_btn); sensitiveIcon=view.findViewById(R.id.sensitive_icon); sensitiveItem=view.findViewById(R.id.sensitive_item); replyText=view.findViewById(R.id.reply_text); @@ -315,6 +342,23 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr buildVisibilityPopup(visibilityBtn); visibilityBtn.setOnClickListener(v->visibilityPopup.show()); visibilityBtn.setOnTouchListener(visibilityPopup.getDragToOpenListener()); + + scheduleDraftPopup=new PopupMenu(getContext(), scheduleBtn); + scheduleDraftPopup.inflate(R.menu.schedule_draft); + scheduleDraftPopup.setOnMenuItemClickListener(item->{ + if (item.getItemId() == R.id.draft) updateScheduledAt(getDraftInstant()); + else pickScheduledDateTime(); + return true; + }); + UiUtils.enablePopupMenuIcons(getContext(), scheduleDraftPopup); + scheduleBtn.setOnClickListener(v->{ + if (scheduledAt != null) updateScheduledAt(null); + else scheduleDraftPopup.show(); + }); + scheduleBtn.setOnTouchListener(scheduleDraftPopup.getDragToOpenListener()); + scheduleDraftDismiss.setOnClickListener(v->updateScheduledAt(null)); + scheduleTimeBtn.setOnClickListener(v->pickScheduledDateTime()); + sensitiveItem.setOnClickListener(v->toggleSensitive()); emojiKeyboard.setOnIconChangedListener(new PopupKeyboard.OnIconChangeListener(){ @Override @@ -364,8 +408,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr DraftPollOption opt=createDraftPollOption(); opt.edit.setText(eopt.title); } - pollDuration=(int)editingStatus.poll.expiresAt.minus(System.currentTimeMillis(), ChronoUnit.MILLIS).getEpochSecond(); - pollDurationStr=UiUtils.formatTimeLeft(getActivity(), editingStatus.poll.expiresAt); + pollDuration=scheduledStatus == null + ? (int)editingStatus.poll.expiresAt.minus(System.currentTimeMillis(), ChronoUnit.MILLIS).getEpochSecond() + : Integer.parseInt(scheduledStatus.params.poll.expiresIn); + pollDurationStr=UiUtils.formatTimeLeft(getActivity(), scheduledStatus == null + ? editingStatus.poll.expiresAt + : Instant.now().plus(pollDuration, ChronoUnit.SECONDS)); updatePollOptionHints(); pollDurationView.setText(getString(R.string.compose_poll_duration, pollDurationStr)); }else{ @@ -404,9 +452,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr if(editingStatus!=null && editingStatus.visibility!=null) { statusVisibility=editingStatus.visibility; + } else { + loadDefaultStatusVisibility(savedInstanceState); } - loadDefaultStatusVisibility(savedInstanceState); updateVisibilityIcon(); visibilityPopup.getMenu().findItem(switch(statusVisibility){ case PUBLIC -> R.id.vis_public; @@ -450,6 +499,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr outState.putParcelableArrayList("attachments", serializedAttachments); } outState.putSerializable("visibility", statusVisibility); + if (scheduledAt != null) outState.putSerializable("scheduledAt", scheduledAt); + if (scheduledStatus != null) outState.putParcelable("scheduledStatus", Parcels.wrap(scheduledStatus)); } @Override @@ -544,7 +595,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr case PUBLIC -> R.drawable.ic_fluent_earth_20_regular; case UNLISTED -> R.drawable.ic_fluent_people_community_20_regular; case PRIVATE -> R.drawable.ic_fluent_people_checkmark_20_regular; - case DIRECT -> R.drawable.ic_fluent_mention_24_regular; + case DIRECT -> R.drawable.ic_fluent_mention_20_regular; }); visibilityIcon.setBounds(0, 0, V.dp(20), V.dp(20)); Drawable replyArrow = getActivity().getDrawable(R.drawable.ic_fluent_arrow_reply_20_filled); @@ -632,6 +683,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr } updateSensitive(); + updateScheduledAt(scheduledAt != null ? scheduledAt : scheduledStatus != null ? scheduledStatus.scheduledAt : null); if(editingStatus!=null){ updateCharCounter(); @@ -643,7 +695,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ if(!GlobalUserPreferences.relocatePublishButton){ publishButton=new Button(getActivity()); - publishButton.setText(editingStatus==null || redraftStatus ? R.string.publish : R.string.save); + resetPublishButtonText(); + publishButton.setSingleLine(); + publishButton.setEllipsize(TextUtils.TruncateAt.END); publishButton.setOnClickListener(this::onPublishClick); } LinearLayout wrap=new LinearLayout(getActivity()); @@ -692,11 +746,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr @SuppressLint("ClickableViewAccessibility") private Button buildLanguageSelector() { - TypedValue typedValue = new TypedValue(); - getActivity().getTheme().resolveAttribute(android.R.attr.textColorSecondary, typedValue, true); - languageButton=new Button(getActivity()); - languageButton.setTextColor(typedValue.data); + languageButton.setTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorSecondary)); languageButton.setBackground(getActivity().getDrawable(R.drawable.bg_text_button)); languageButton.setPadding(V.dp(8), 0, V.dp(8), 0); languageButton.setCompoundDrawablesRelativeWithIntrinsicBounds(getActivity().getDrawable(R.drawable.ic_fluent_local_language_16_regular), null, null, null); @@ -767,6 +818,15 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr updatePublishButtonState(); } + private void resetPublishButtonText() { + int publishText = editingStatus==null || redraftStatus ? R.string.publish : R.string.save; + if (publishText == R.string.publish && !GlobalUserPreferences.publishButtonText.isEmpty()) { + publishButton.setText(GlobalUserPreferences.publishButtonText); + } else { + publishButton.setText(publishText); + } + } + private void updatePublishButtonState(){ uuid=null; int nonEmptyPollOptionsCount=0; @@ -782,6 +842,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr nonDoneAttachmentCount++; } publishButton.setEnabled((trimmedCharCount>0 || !attachments.isEmpty()) && charCount<=charLimit && nonDoneAttachmentCount==0 && (pollOptions.isEmpty() || nonEmptyPollOptionsCount>1)); + sendError.setVisibility(View.GONE); } private void onCustomEmojiClick(Emoji emoji){ @@ -793,6 +854,24 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr @Override protected void updateToolbar(){ super.updateToolbar(); + if (replyTo != null || hasDraft()) return; + Button draftsBtn=new Button(getActivity()); + draftsBtn.setTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorSecondary)); + draftsBtn.setBackground(getActivity().getDrawable(R.drawable.bg_text_button)); + draftsBtn.setPadding(V.dp(8), 0, V.dp(8), 0); + draftsBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(getActivity().getDrawable(R.drawable.ic_fluent_drafts_20_regular), null, null, null); + draftsBtn.setCompoundDrawableTintList(draftsBtn.getTextColors()); + draftsBtn.setContentDescription(getString(R.string.sk_unsent_posts)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) draftsBtn.setTooltipText(getString(R.string.sk_unsent_posts)); + draftsBtn.setOnClickListener(v->{ + Bundle args=new Bundle(); + args.putString("account", accountID); + InputMethodManager imm=getActivity().getSystemService(InputMethodManager.class); + imm.hideSoftInputFromWindow(draftsBtn.getWindowToken(), 0); + Nav.go(getActivity(), ScheduledStatusListFragment.class, args); + if (!hasDraft()) Nav.finish(this); + }); + getToolbar().addView(draftsBtn); getToolbar().setNavigationIcon(R.drawable.ic_fluent_dismiss_24_regular); } @@ -800,6 +879,43 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr publish(); } + private void publishErrorCallback(ErrorResponse error) { + wm.removeView(sendingOverlay); + sendingOverlay=null; + sendProgress.setVisibility(View.GONE); + sendError.setVisibility(View.VISIBLE); + publishButton.setEnabled(true); + if (error != null) error.showToast(getActivity()); + } + + private void createScheduledStatusFinish(ScheduledStatus result) { + wm.removeView(sendingOverlay); + sendingOverlay=null; + Toast.makeText(getContext(), scheduledAt.isAfter(DRAFTS_AFTER_INSTANT) ? + R.string.sk_draft_saved : R.string.sk_post_scheduled, Toast.LENGTH_SHORT).show(); + Nav.finish(ComposeFragment.this); + E.post(new ScheduledStatusCreatedEvent(result, accountID)); + } + + private void maybeDeleteScheduledPost(Runnable callback) { + if (scheduledStatus != null) { + new DeleteStatus.Scheduled(scheduledStatus.id).setCallback(new Callback<>() { + @Override + public void onSuccess(Object o) { + E.post(new ScheduledStatusDeletedEvent(scheduledStatus.id, accountID)); + callback.run(); + } + + @Override + public void onError(ErrorResponse error) { + publishErrorCallback(error); + } + }).exec(accountID); + } else { + callback.run(); + } + } + private void publish(){ String text=mainEditText.getText().toString(); CreateStatus.Request req=new CreateStatus.Request(); @@ -807,6 +923,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr req.visibility=statusVisibility; req.sensitive=sensitive; req.language=language; + req.scheduledAt = scheduledAt; if(!attachments.isEmpty()){ req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList()); } @@ -843,35 +960,32 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr Callback resCallback=new Callback<>(){ @Override public void onSuccess(Status result){ - wm.removeView(sendingOverlay); - sendingOverlay=null; - if(editingStatus==null){ - E.post(new StatusCreatedEvent(result, accountID)); - if(replyTo!=null){ - replyTo.repliesCount++; - E.post(new StatusCountersUpdatedEvent(replyTo)); + maybeDeleteScheduledPost(() -> { + wm.removeView(sendingOverlay); + sendingOverlay=null; + if(editingStatus==null){ + E.post(new StatusCreatedEvent(result, accountID)); + if(replyTo!=null){ + replyTo.repliesCount++; + E.post(new StatusCountersUpdatedEvent(replyTo)); + } + }else{ + E.post(new StatusUpdatedEvent(result)); } - }else{ - E.post(new StatusUpdatedEvent(result)); - } - Nav.finish(ComposeFragment.this); - if (getArguments().getBoolean("navigateToStatus", false)) { - Bundle args=new Bundle(); - args.putString("account", accountID); - args.putParcelable("status", Parcels.wrap(result)); - if(replyTo!=null) args.putParcelable("inReplyToAccount", Parcels.wrap(replyTo)); - Nav.go(getActivity(), ThreadFragment.class, args); - } + Nav.finish(ComposeFragment.this); + if (getArguments().getBoolean("navigateToStatus", false)) { + Bundle args=new Bundle(); + args.putString("account", accountID); + args.putParcelable("status", Parcels.wrap(result)); + if(replyTo!=null) args.putParcelable("inReplyToAccount", Parcels.wrap(replyTo)); + Nav.go(getActivity(), ThreadFragment.class, args); + } + }); } @Override public void onError(ErrorResponse error){ - wm.removeView(sendingOverlay); - sendingOverlay=null; - sendProgress.setVisibility(View.GONE); - sendError.setVisibility(View.VISIBLE); - publishButton.setEnabled(true); - error.showToast(getActivity()); + publishErrorCallback(error); } }; @@ -879,10 +993,37 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr new EditStatus(req, editingStatus.id) .setCallback(resCallback) .exec(accountID); - }else{ + }else if(req.scheduledAt == null){ new CreateStatus(req, uuid) .setCallback(resCallback) .exec(accountID); + }else if(req.scheduledAt.isAfter(Instant.now().plus(10, ChronoUnit.MINUTES))){ + // checking for 10 instead of 5 minutes (as per mastodon) because i really don't want + // bugs to occur because the client's clock is wrong by a minute or two - the api + // returns a status instead of a scheduled status if scheduled time is less than 5 + // minutes into the future and this is 1. unexpected for the user and 2. hard to handle + new CreateStatus.Scheduled(req, uuid) + .setCallback(new Callback<>() { + @Override + public void onSuccess(ScheduledStatus result) { + maybeDeleteScheduledPost(() -> { + createScheduledStatusFinish(result); + }); + } + + @Override + public void onError(ErrorResponse error) { + publishErrorCallback(error); + } + }).exec(accountID); + }else{ + new M3AlertDialogBuilder(getActivity()) + .setTitle(R.string.sk_scheduled_too_soon_title) + .setMessage(R.string.sk_scheduled_too_soon) + .setPositiveButton(R.string.ok, (a, b)->{}) + .show(); + publishErrorCallback(null); + publishButton.setEnabled(false); } if (replyTo == null) { @@ -902,6 +1043,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr List existingMediaIDs=editingStatus.mediaAttachments.stream().map(a->a.id).collect(Collectors.toList()); if(!existingMediaIDs.equals(attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList()))) return true; + if(!statusVisibility.equals(editingStatus.visibility)) return true; return pollChanged; } boolean pollFieldsHaveContent=false; @@ -951,9 +1093,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr private void confirmDiscardDraftAndFinish(){ new M3AlertDialogBuilder(getActivity()) - .setTitle(editingStatus==null ? R.string.discard_draft : R.string.discard_changes) - .setPositiveButton(R.string.discard, (dialog, which)->Nav.finish(this)) - .setNegativeButton(R.string.cancel, null) + .setTitle(editingStatus != null ? R.string.sk_save_changes : R.string.sk_save_draft) + .setPositiveButton(R.string.save, (d, w) -> { + updateScheduledAt(getDraftInstant()); + publish(); + }) + .setNegativeButton(R.string.discard, (d, w) -> Nav.finish(this)) .show(); } @@ -1132,7 +1277,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr @Override public void onProgress(long transferred, long total){ if(updateUploadEtaRunnable==null){ - UiUtils.runOnUiThread(updateUploadEtaRunnable=ComposeFragment.this::updateUploadETAs, 100); + // getting a NoSuchMethodError: No static method -$$Nest$mupdateUploadETAs(ComposeFragment;)V in class ComposeFragment + // when using method reference out of nowhere after changing code elsewhere. no idea. programming is awful, actually + // noinspection Convert2MethodRef + UiUtils.runOnUiThread(updateUploadEtaRunnable=()->ComposeFragment.this.updateUploadETAs(), 50); } int progress=Math.round(transferred/(float)total*attachment.progressBar.getMax()); if(Build.VERSION.SDK_INT>=24) @@ -1295,7 +1443,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr att.uploadStateText.setText(getString(R.string.file_upload_time_remaining, time)); } } - UiUtils.runOnUiThread(updateUploadEtaRunnable, 100); + UiUtils.runOnUiThread(updateUploadEtaRunnable, 50); } private void onEditMediaDescriptionClick(View v){ @@ -1427,6 +1575,42 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr if (attachments.isEmpty()) sensitive = false; } + private void pickScheduledDateTime() { + LocalDateTime soon = LocalDateTime.now() + .plus(15, ChronoUnit.MINUTES) // so 14:59 doesn't get rounded up to… + .plus(1, ChronoUnit.HOURS) // …15:00, but rather 16:00 + .withMinute(0); + new DatePickerDialog(getActivity(), (datePicker, year, arrayMonth, dayOfMonth) -> { + new TimePickerDialog(getActivity(), (timePicker, hour, minute) -> { + updateScheduledAt(LocalDateTime.of(year, arrayMonth + 1, dayOfMonth, hour, minute) + .toInstant(OffsetDateTime.now().getOffset())); + }, soon.getHour(), soon.getMinute(), DateFormat.is24HourFormat(getActivity())).show(); + }, soon.getYear(), soon.getMonthValue() - 1, soon.getDayOfMonth()).show(); + } + + private void updateScheduledAt(Instant scheduledAt) { + this.scheduledAt = scheduledAt; + scheduleDraftView.setVisibility(scheduledAt == null ? View.GONE : View.VISIBLE); + scheduleBtn.setSelected(scheduledAt != null); + updatePublishButtonState(); + if (scheduledAt != null) { + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault()); + if (scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)) { + scheduleTimeBtn.setVisibility(View.GONE); + scheduleDraftText.setText(R.string.sk_compose_draft); + publishButton.setText(scheduledStatus != null ? R.string.save : R.string.sk_draft); + } else { + String at = scheduledAt.atZone(ZoneId.systemDefault()).format(formatter); + scheduleTimeBtn.setVisibility(View.VISIBLE); + scheduleTimeBtn.setText(at); + scheduleDraftText.setText(R.string.sk_compose_scheduled); + publishButton.setText(scheduledStatus != null ? R.string.save : R.string.sk_schedule); + } + } else { + resetPublishButtonText(); + } + } + private int getMediaAttachmentsCount(){ return attachments.size(); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java index c63848b45..97ec6f770 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java @@ -2,6 +2,8 @@ package org.joinmastodon.android.fragments; import android.app.Activity; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; import android.view.View; import com.squareup.otto.Subscribe; @@ -10,7 +12,6 @@ import org.joinmastodon.android.E; import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.markers.SaveMarkers; import org.joinmastodon.android.api.session.AccountSessionManager; -import org.joinmastodon.android.events.NotificationDeletedEvent; import org.joinmastodon.android.events.PollUpdatedEvent; import org.joinmastodon.android.events.RemoveAccountPostsEvent; import org.joinmastodon.android.model.Notification; @@ -78,9 +79,9 @@ public class NotificationsListFragment extends BaseStatusListFragment getString(R.string.user_favorited); case POLL -> getString(R.string.poll_ended); }; - HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, null, extraText) : null; + HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, null, extraText, n, null) : null; if(n.status!=null){ - ArrayList items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null); + ArrayList items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n); if(titleItem!=null){ for(StatusDisplayItem item:items){ if(item instanceof ImageStatusDisplayItem imgItem){ @@ -210,7 +211,7 @@ public class NotificationsListFragment extends BaseStatusListFragment { + private String nextMaxID; + + @Override + public void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + E.register(this); + } + + @Override + public void onDestroy(){ + super.onDestroy(); + E.unregister(this); + } + + + @Override + public void onAttach(Activity activity){ + super.onAttach(activity); + setTitle(R.string.sk_unsent_posts); + loadData(); + } + + @Override + protected List buildDisplayItems(ScheduledStatus s) { + return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, null); + } + + @Override + protected void addAccountToKnown(ScheduledStatus s) {} + + @Override + public void onItemClick(String id) { + final Bundle args=new Bundle(); + args.putString("account", accountID); + ScheduledStatus scheduledStatus = getStatusByID(id); + Status status = scheduledStatus.toStatus(); + args.putParcelable("scheduledStatus", Parcels.wrap(scheduledStatus)); + args.putParcelable("editStatus", Parcels.wrap(status)); + args.putString("sourceText", status.text); + args.putString("sourceSpoiler", status.spoilerText); + args.putBoolean("redraftStatus", true); + Nav.go(getActivity(), ComposeFragment.class, args); + } + + @Override + protected void doLoadData(int offset, int count){ + currentRequest=new GetScheduledStatuses(offset==0 ? null : nextMaxID, count) + .setCallback(new SimpleCallback<>(this){ + @Override + public void onSuccess(HeaderPaginationList result){ + if(result.nextPageUri!=null) + nextMaxID=result.nextPageUri.getQueryParameter("max_id"); + else + nextMaxID=null; + onDataLoaded(result, nextMaxID!=null); + } + }) + .exec(accountID); + } + + // copied from StatusListFragment.java + @Subscribe + public void onScheduledStatusDeleted(ScheduledStatusDeletedEvent ev){ + if(!ev.accountID.equals(accountID)) return; + ScheduledStatus status=getStatusByID(ev.id); + if(status==null) return; + removeStatus(status); + } + + // copied from StatusListFragment.java + @Subscribe + public void onScheduledStatusCreated(ScheduledStatusCreatedEvent ev){ + if(!ev.accountID.equals(accountID)) return; + prependItems(Collections.singletonList(ev.scheduledStatus), true); + scrollToTop(); + } + + // copied from StatusListFragment.java + protected void removeStatus(ScheduledStatus status){ + data.remove(status); + preloadedData.remove(status); + int index=-1; + for(int i=0;i mediaAttachments; + + @Override + public String getID() { + return id; + } + + @Parcel + public static class Params { + @RequiredField + public String text; + public String spoilerText; + @RequiredField + public StatusPrivacy visibility; + public long inReplyToId; + public ScheduledPoll poll; + public boolean sensitive; + public boolean withRateLimit; + public String language; + public String idempotency; + public String applicationId; + public List mediaIds; + } + + @Parcel + public static class ScheduledPoll { + @RequiredField + public String expiresIn; + @RequiredField + public List options; + public boolean multiple; + public boolean hideTotals; + + public Poll toPoll() { + Poll p = new Poll(); + p.voted = true; + p.emojis = List.of(); + p.ownVotes = List.of(); + p.multiple = multiple; + p.options = options.stream().map(Option::new).collect(Collectors.toList()); + return p; + } + } + + public Status toStatus() { + Status s = new Status(); + s.id = id; + s.mediaAttachments = mediaAttachments; + s.createdAt = scheduledAt; + s.content = s.text = params.text; + s.spoilerText = params.spoilerText; + s.visibility = params.visibility; + s.language = params.language; + s.mentions = List.of(); + s.tags = List.of(); + s.emojis = List.of(); + if (params.poll != null) s.poll = params.poll.toPoll(); + return s; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java index 66c421a1f..f3e6bf02c 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java @@ -11,6 +11,7 @@ import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; +import android.view.SubMenu; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; @@ -22,28 +23,34 @@ import android.widget.Toast; import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships; +import org.joinmastodon.android.api.requests.statuses.CreateStatus; import org.joinmastodon.android.api.requests.statuses.GetStatusSourceText; +import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.ComposeFragment; +import org.joinmastodon.android.fragments.NotificationsListFragment; import org.joinmastodon.android.fragments.ProfileFragment; import org.joinmastodon.android.fragments.ThreadFragment; import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Attachment; -import org.joinmastodon.android.model.Preferences; +import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.Relationship; +import org.joinmastodon.android.model.ScheduledStatus; import org.joinmastodon.android.model.Status; -import org.joinmastodon.android.model.StatusPrivacy; import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.utils.CustomEmojiHelper; import org.joinmastodon.android.ui.utils.UiUtils; import org.parceler.Parcels; import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.util.Collections; import java.util.List; -import java.util.Objects; +import java.util.Locale; import me.grishka.appkit.Nav; import me.grishka.appkit.api.APIRequest; @@ -65,15 +72,20 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ private boolean hasVisibilityToggle; boolean needBottomPadding; private String extraText; + private Notification notification; + private ScheduledStatus scheduledStatus; - public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, String extraText){ + public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, String extraText, Notification notification, ScheduledStatus scheduledStatus){ super(parentID, parentFragment); + user=scheduledStatus != null ? AccountSessionManager.getInstance().getAccount(accountID).self : user; this.user=user; this.createdAt=createdAt; avaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? user.avatar : user.avatarStatic, V.dp(50), V.dp(50)); this.accountID=accountID; parsedName=new SpannableStringBuilder(user.displayName); this.status=status; + this.notification=notification; + this.scheduledStatus=scheduledStatus; HtmlParser.parseCustomEmoji(parsedName, user.emojis); emojiHelper.setText(parsedName); if(status!=null){ @@ -110,7 +122,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ public static class Holder extends StatusDisplayItem.Holder implements ImageLoaderViewHolder{ private final TextView name, username, timestamp, extraText; - private final ImageView avatar, more, visibility; + private final ImageView avatar, more, visibility, deleteNotification; private final PopupMenu optionsMenu; private Relationship relationship; private APIRequest currentRelationshipRequest; @@ -130,19 +142,25 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ avatar=findViewById(R.id.avatar); more=findViewById(R.id.more); visibility=findViewById(R.id.visibility); + deleteNotification=findViewById(R.id.delete_notification); extraText=findViewById(R.id.extra_text); avatar.setOnClickListener(this::onAvaClick); avatar.setOutlineProvider(roundCornersOutline); avatar.setClipToOutline(true); more.setOnClickListener(this::onMoreClick); - more.setOnLongClickListener((v) -> { openWithAccount(); return true; }); visibility.setOnClickListener(v->item.parentFragment.onVisibilityIconClick(this)); + deleteNotification.setOnClickListener(v->UiUtils.confirmDeleteNotification(activity, item.parentFragment.getAccountID(), item.notification, ()->{ + if (item.parentFragment instanceof NotificationsListFragment fragment) { + fragment.removeNotification(item.notification); + } + })); optionsMenu=new PopupMenu(activity, more); optionsMenu.inflate(R.menu.post); optionsMenu.setOnMenuItemClickListener(menuItem->{ Account account=item.user; int id=menuItem.getItemId(); + if(id==R.id.edit || id==R.id.delete_and_redraft) { final Bundle args=new Bundle(); args.putString("account", item.parentFragment.getAccountID()); @@ -157,6 +175,12 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ } if(TextUtils.isEmpty(item.status.content) && TextUtils.isEmpty(item.status.spoilerText)){ Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); + }else if(item.scheduledStatus!=null){ + args.putString("sourceText", item.status.text); + args.putString("sourceSpoiler", item.status.spoilerText); + args.putBoolean("redraftStatus", true); + args.putParcelable("scheduledStatus", Parcels.wrap(item.scheduledStatus)); + Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); }else{ new GetStatusSourceText(item.status.id) .setCallback(new Callback<>(){ @@ -182,12 +206,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ .exec(item.parentFragment.getAccountID()); } }else if(id==R.id.delete){ - UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{}); + if (item.scheduledStatus != null) { + UiUtils.confirmDeleteScheduledPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.scheduledStatus, ()->{}); + } else { + UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{}); + } }else if(id==R.id.pin || id==R.id.unpin) { - UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s -> { - }); - }else if(id==R.id.open_with_account) { - openWithAccount(); + UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s->{}); }else if(id==R.id.mute){ UiUtils.confirmToggleMuteUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, relationship!=null && relationship.muting, r->{}); }else if(id==R.id.block){ @@ -198,8 +223,10 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ args.putParcelable("status", Parcels.wrap(item.status)); args.putParcelable("reportAccount", Parcels.wrap(item.status.account)); Nav.go(item.parentFragment.getActivity(), ReportReasonChoiceFragment.class, args); - }else if(id==R.id.open_in_browser){ + }else if(id==R.id.open_in_browser) { UiUtils.launchWebBrowser(activity, item.status.url); + }else if(id==R.id.copy_link){ + UiUtils.copyText(parent, item.status.url); }else if(id==R.id.follow){ if(relationship==null) return true; @@ -213,7 +240,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ progress.dismiss(); }, rel->{ relationship=rel; - Toast.makeText(activity, activity.getString(rel.following ? R.string.followed_user : R.string.unfollowed_user, account.getDisplayUsername()), Toast.LENGTH_SHORT).show(); + Toast.makeText(activity, activity.getString(rel.following ? R.string.followed_user : R.string.unfollowed_user, account.getShortUsername()), Toast.LENGTH_SHORT).show(); }); }else if(id==R.id.block_domain){ UiUtils.confirmToggleBlockDomain(activity, item.parentFragment.getAccountID(), account.getDomain(), relationship!=null && relationship.domainBlocking, ()->{}); @@ -225,22 +252,34 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ UiUtils.enablePopupMenuIcons(activity, optionsMenu); } - private void openWithAccount() { - UiUtils.pickAccount(item.parentFragment.getActivity(), (session, dialog) -> { - UiUtils.openURL(item.parentFragment.getActivity(), session.getID(), item.status.url); - return true; - }, R.string.sk_open_in_account); + private void populateAccountsMenu(Menu menu) { + List sessions=AccountSessionManager.getInstance().getLoggedInAccounts(); + sessions.stream().filter(s -> !s.getID().equals(item.accountID)).forEach(s -> { + String username = "@"+s.self.username+"@"+s.domain; + menu.add(username).setOnMenuItemClickListener(c->{ + UiUtils.openURL(item.parentFragment.getActivity(), s.getID(), item.status.url, false); + return true; + }); + }); } @Override public void onBind(HeaderStatusDisplayItem item){ name.setText(item.parsedName); username.setText('@'+item.user.acct); - if(item.status==null || item.status.editedAt==null) + if (item.scheduledStatus!=null) + if (item.scheduledStatus.scheduledAt.isAfter(CreateStatus.DRAFTS_AFTER_INSTANT)) { + timestamp.setText(R.string.sk_draft); + } else { + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault()); + timestamp.setText(item.scheduledStatus.scheduledAt.atZone(ZoneId.systemDefault()).format(formatter)); + } + else if(item.status==null || item.status.editedAt==null) timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt)); else timestamp.setText(item.parentFragment.getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(itemView.getContext(), item.status.editedAt))); visibility.setVisibility(item.hasVisibilityToggle && !item.inset ? View.VISIBLE : View.GONE); + deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE); if(item.hasVisibilityToggle){ visibility.setImageResource(item.status.spoilerRevealed ? R.drawable.ic_visibility_off : R.drawable.ic_visibility); visibility.setContentDescription(item.parentFragment.getString(item.status.spoilerRevealed ? R.string.hide_content : R.string.reveal_content)); @@ -313,18 +352,32 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ } private void updateOptionsMenu(){ - Account account=item.user; + boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1; Menu menu=optionsMenu.getMenu(); + + MenuItem openWithAccounts = menu.findItem(R.id.open_with_account); + SubMenu accountsMenu = openWithAccounts != null ? openWithAccounts.getSubMenu() : null; + if (hasMultipleAccounts && accountsMenu != null) { + openWithAccounts.setVisible(true); + accountsMenu.clear(); + populateAccountsMenu(accountsMenu); + } else if (openWithAccounts != null) { + openWithAccounts.setVisible(false); + } + + Account account=item.user; boolean isOwnPost=AccountSessionManager.getInstance().isSelf(item.parentFragment.getAccountID(), account); + boolean isPostScheduled=item.scheduledStatus!=null; + menu.findItem(R.id.open_with_account).setVisible(!isPostScheduled && hasMultipleAccounts); menu.findItem(R.id.edit).setVisible(item.status!=null && isOwnPost); menu.findItem(R.id.delete).setVisible(item.status!=null && isOwnPost); - menu.findItem(R.id.delete_and_redraft).setVisible(item.status!=null && isOwnPost); - menu.findItem(R.id.pin).setVisible(item.status!=null && isOwnPost && !item.status.pinned); - menu.findItem(R.id.unpin).setVisible(item.status!=null && isOwnPost && item.status.pinned); - menu.findItem(R.id.open_in_browser).setVisible(item.status!=null); + menu.findItem(R.id.delete_and_redraft).setVisible(!isPostScheduled && item.status!=null && isOwnPost); + menu.findItem(R.id.pin).setVisible(!isPostScheduled && item.status!=null && isOwnPost && !item.status.pinned); + menu.findItem(R.id.unpin).setVisible(!isPostScheduled && item.status!=null && isOwnPost && item.status.pinned); + menu.findItem(R.id.open_in_browser).setVisible(!isPostScheduled && item.status!=null); + menu.findItem(R.id.copy_link).setVisible(!isPostScheduled && item.status!=null); MenuItem blockDomain=menu.findItem(R.id.block_domain); MenuItem mute=menu.findItem(R.id.mute); - MenuItem hideBoosts=menu.findItem(R.id.hide_boosts); MenuItem block=menu.findItem(R.id.block); MenuItem report=menu.findItem(R.id.report); MenuItem follow=menu.findItem(R.id.follow); @@ -338,9 +391,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ bookmark.setVisible(false); } */ - if(isOwnPost){ + if(isPostScheduled || isOwnPost){ mute.setVisible(false); - hideBoosts.setVisible(false); block.setVisible(false); report.setVisible(false); follow.setVisible(false); @@ -350,11 +402,11 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ block.setVisible(true); report.setVisible(true); follow.setVisible(relationship==null || relationship.following || (!relationship.blocking && !relationship.blockedBy && !relationship.domainBlocking && !relationship.muting)); - mute.setTitle(item.parentFragment.getString(relationship!=null && relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername())); - mute.setIcon(relationship!=null && relationship.muting ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_mute_24_regular); + mute.setTitle(item.parentFragment.getString(relationship!=null && relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getShortUsername())); + mute.setIcon(relationship!=null && relationship.muting ? R.drawable.ic_fluent_speaker_0_24_regular : R.drawable.ic_fluent_speaker_off_24_regular); UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), mute); - block.setTitle(item.parentFragment.getString(relationship!=null && relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername())); - report.setTitle(item.parentFragment.getString(R.string.report_user, account.getDisplayUsername())); + block.setTitle(item.parentFragment.getString(relationship!=null && relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getShortUsername())); + report.setTitle(item.parentFragment.getString(R.string.report_user, account.getShortUsername())); // disabled in megalodon. domain blocks from a post clutters the context menu and looks out of place // if(!account.isLocal()){ // blockDomain.setVisible(true); @@ -363,7 +415,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{ blockDomain.setVisible(false); // } boolean following = relationship!=null && relationship.following; - follow.setTitle(item.parentFragment.getString(following ? R.string.unfollow_user : R.string.follow_user, account.getDisplayUsername())); + follow.setTitle(item.parentFragment.getString(following ? R.string.unfollow_user : R.string.follow_user, account.getShortUsername())); follow.setIcon(following ? R.drawable.ic_fluent_person_delete_24_regular : R.drawable.ic_fluent_person_add_24_regular); UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), follow); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index 4a9d3c8a7..36e907616 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -15,7 +15,9 @@ import org.joinmastodon.android.fragments.ThreadFragment; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Attachment; import org.joinmastodon.android.model.DisplayItemsParent; +import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.Poll; +import org.joinmastodon.android.model.ScheduledStatus; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.ui.PhotoLayoutHelper; import org.joinmastodon.android.ui.text.HtmlParser; @@ -74,12 +76,14 @@ public abstract class StatusDisplayItem{ }; } - public static ArrayList buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject, Map knownAccounts, boolean inset, boolean addFooter){ + public static ArrayList buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject, Map knownAccounts, boolean inset, boolean addFooter, Notification notification){ String parentID=parentObject.getID(); ArrayList items=new ArrayList<>(); Status statusForContent=status.getContentStatus(); Bundle args=new Bundle(); args.putString("account", accountID); + ScheduledStatus scheduledStatus = parentObject instanceof ScheduledStatus ? (ScheduledStatus) parentObject : null; + if(status.reblog!=null){ boolean isOwnPost = AccountSessionManager.getInstance().isSelf(fragment.getAccountID(), status.account); items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName), status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20_filled, isOwnPost ? status.visibility : null, i->{ @@ -94,7 +98,7 @@ public abstract class StatusDisplayItem{ })); } HeaderStatusDisplayItem header; - items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null)); + items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, notification, scheduledStatus)); if(!TextUtils.isEmpty(statusForContent.content)) items.add(new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID), fragment, statusForContent)); else diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index 376b47987..4b46a9fa5 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -58,11 +58,13 @@ import org.joinmastodon.android.api.requests.accounts.RejectFollowRequest; //import org.joinmastodon.android.api.requests.notification.DismissNotification; import org.joinmastodon.android.api.requests.notifications.DismissNotification; import org.joinmastodon.android.api.requests.search.GetSearchResults; +import org.joinmastodon.android.api.requests.statuses.CreateStatus; import org.joinmastodon.android.api.requests.statuses.DeleteStatus; import org.joinmastodon.android.api.requests.statuses.GetStatusByID; import org.joinmastodon.android.api.requests.statuses.SetStatusPinned; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; +import org.joinmastodon.android.events.ScheduledStatusDeletedEvent; import org.joinmastodon.android.events.StatusCountersUpdatedEvent; import org.joinmastodon.android.events.FollowRequestHandledEvent; import org.joinmastodon.android.events.NotificationDeletedEvent; @@ -80,11 +82,11 @@ import org.joinmastodon.android.model.Instance; import org.joinmastodon.android.model.ListTimeline; import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.Relationship; +import org.joinmastodon.android.model.ScheduledStatus; import org.joinmastodon.android.model.SearchResults; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.text.CustomEmojiSpan; -import org.joinmastodon.android.ui.text.SpacerSpan; import org.parceler.Parcels; import java.io.File; @@ -470,6 +472,31 @@ public class UiUtils{ ); } + public static void confirmDeleteScheduledPost(Activity activity, String accountID, ScheduledStatus status, Runnable resultCallback){ + boolean isDraft = status.scheduledAt.isAfter(CreateStatus.DRAFTS_AFTER_INSTANT); + showConfirmationAlert(activity, + isDraft ? R.string.sk_confirm_delete_draft_title : R.string.sk_confirm_delete_scheduled_post_title, + isDraft ? R.string.sk_confirm_delete_draft : R.string.sk_confirm_delete_scheduled_post, + R.string.delete, + R.drawable.ic_fluent_delete_28_regular, + () -> new DeleteStatus.Scheduled(status.id) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(Object nothing){ + resultCallback.run(); + E.post(new ScheduledStatusDeletedEvent(status.id, accountID)); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(activity); + } + }) + .wrapProgress(activity, R.string.deleting, false) + .exec(accountID) + ); + } + public static void confirmPinPost(Activity activity, String accountID, Status status, boolean pinned, Consumer resultCallback){ showConfirmationAlert(activity, pinned ? R.string.sk_confirm_pin_post_title : R.string.sk_confirm_unpin_post_title, diff --git a/mastodon/src/main/res/drawable/ic_fluent_clock_20_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_clock_20_regular.xml new file mode 100644 index 000000000..8858954c5 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_clock_20_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_clock_24_filled.xml b/mastodon/src/main/res/drawable/ic_fluent_clock_24_filled.xml new file mode 100644 index 000000000..beec42fea --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_clock_24_filled.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_clock_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_clock_24_regular.xml new file mode 100644 index 000000000..23e62f033 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_clock_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_clock_24_selector.xml b/mastodon/src/main/res/drawable/ic_fluent_clock_24_selector.xml new file mode 100644 index 000000000..53c57862a --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_clock_24_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_drafts_20_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_drafts_20_regular.xml new file mode 100644 index 000000000..f6b22cb5f --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_drafts_20_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_drafts_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_drafts_24_regular.xml new file mode 100644 index 000000000..9343ff2fe --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_drafts_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/layout/fragment_compose.xml b/mastodon/src/main/res/layout/fragment_compose.xml index 438779cda..db35a12f8 100644 --- a/mastodon/src/main/res/layout/fragment_compose.xml +++ b/mastodon/src/main/res/layout/fragment_compose.xml @@ -196,6 +196,7 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="16dp" android:layout_marginTop="8dp" android:gravity="center_vertical" android:layoutDirection="locale" @@ -228,94 +229,153 @@ - - - - - - - - - - - - - - + android:gravity="center_vertical" + android:minHeight="48dp" + android:paddingTop="4dp"> + +