From 1a9c3ccb79b2deb89fe5cf5ffab1e0e9cb128b13 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 30 Aug 2023 08:44:14 -0400 Subject: [PATCH 01/18] Must have a valid ZapRequest to process. --- .../main/java/com/vitorpamplona/amethyst/model/LocalCache.kt | 3 ++- .../main/java/com/vitorpamplona/quartz/events/LnZapEvent.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 290a294b7..165c0d06e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -1492,9 +1492,10 @@ object LocalCache { is LiveActivitiesChatMessageEvent -> consume(event, relay) is LnZapEvent -> { event.zapRequest?.let { + // must have a valid request verifyAndConsume(it, relay) + consume(event) } - consume(event) } is LnZapRequestEvent -> consume(event) is LnZapPaymentRequestEvent -> consume(event) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapEvent.kt index c4502cf69..e1ab6a9ed 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/LnZapEvent.kt @@ -21,7 +21,7 @@ class LnZapEvent( fromJson(it) } as? LnZapRequestEvent } catch (e: Exception) { - Log.e("LnZapEvent", "Failed to Parse Contained Post ${description()}", e) + Log.w("LnZapEvent", "Failed to Parse Contained Post ${description()}", e) null } From d5607faadd083fd6bf30c2fbb1241bc8c5ae46f3 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 30 Aug 2023 08:47:25 -0400 Subject: [PATCH 02/18] Requires 10 sat zaps to trigger notifications --- .../service/notifications/EventNotificationConsumer.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt index 5ca2e3af8..dd8e104a0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/EventNotificationConsumer.kt @@ -20,6 +20,7 @@ import com.vitorpamplona.quartz.events.LnZapRequestEvent import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.SealedGossipEvent import kotlinx.collections.immutable.persistentSetOf +import java.math.BigDecimal class EventNotificationConsumer(private val applicationContext: Context) { @@ -129,15 +130,17 @@ class EventNotificationConsumer(private val applicationContext: Context) { private fun notify(event: LnZapEvent) { val noteZapEvent = LocalCache.notes[event.id] ?: return - val noteZapRequest = event.zapRequest?.id?.let { LocalCache.checkGetOrCreateNote(it) } + val noteZapRequest = event.zapRequest?.id?.let { LocalCache.checkGetOrCreateNote(it) } ?: return val noteZapped = event.zappedPost().firstOrNull()?.let { LocalCache.checkGetOrCreateNote(it) } + if ((event.amount ?: BigDecimal.ZERO) < BigDecimal.TEN) return + LocalPreferences.allSavedAccounts().forEach { val acc = LocalPreferences.loadFromEncryptedStorage(it.npub) if (acc != null && acc.userProfile().pubkeyHex == event.zappedAuthor().firstOrNull()) { val amount = showAmount(event.amount) - val senderInfo = (noteZapRequest?.event as? LnZapRequestEvent)?.let { + val senderInfo = (noteZapRequest.event as? LnZapRequestEvent)?.let { val decryptedContent = acc.decryptZapContentAuthor(noteZapRequest) if (decryptedContent != null) { val author = LocalCache.getOrCreateUser(decryptedContent.pubKey) From 51f997a34a9bd47670f2bd2b98a4fad6a9482dd0 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Wed, 30 Aug 2023 12:48:43 +0000 Subject: [PATCH 03/18] New Crowdin translations by GitHub Action --- app/src/main/res/values-ar/strings.xml | 99 ++++++++++++++++++++++ app/src/main/res/values-zh-rCN/strings.xml | 73 ++++++++++++++++ app/src/main/res/values-zh-rTW/strings.xml | 29 +++++++ 3 files changed, 201 insertions(+) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 80c0e70f5..fc239fb65 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -16,11 +16,14 @@ التمثيل تصرف غير قانوني غير معروف + أيقونة الخادم كاتب غير معروف نسخ النص نسخ المفتاح العام نسخ معرف بث + حذف الطلب + حظر / تبليغ الابلاغ عن البريد العشوائي / الاحتيال الإبلاغ عن التمثيل @@ -31,6 +34,8 @@ تسجيل الدخول باستخدام مفتاح خاص لإبداء الإعجاب بالمنشورات لا يوجد إعداد لمبلغ Zap. اضغط لفترة طويلة للتغيير قم بتسجيل الدخول باستخدام مفتاح خاص لتتمكن من إرسال Zaps + قم بتسجيل الدخول باستخدام مفتاح خاص لتتمكن من متابعة المستخدمين + قم بتسجيل الدخول بمفتاحك الخاص للتتمكن من إلغاء متابعة المستخدمين مشاهدة العد تعزيز معزز @@ -41,6 +46,8 @@ " و " "في القناة " لافتة الملف الشخصي + تم الدفع بنجاح + خطأ أثناء تحليل رسالة الخطأ "المتابعون" "متابِعاً" الملف الشخصي @@ -70,6 +77,7 @@ فشل تحميل الصورة Relay عنوان المنشورات + Bytes الأخطاء المنشورات الرئيسية الرسائل الخاصة @@ -166,4 +174,95 @@ أبلغ عن كلام يحض على الكراهية الإبلاغ عن عُري / إباحي آخرون + ضع علامة على جميع الرسائل/الاشعارات المعروفة كمقروء + ضع علامة على جميع الرسائل/الاشعارات الجديدة كمقروء + ضع علامة على جميع الرسائل/الاشعارات كمقروء + قم بعمل نسخة احتياطية للمفاتيح + ## النصائح الرئيسية للنسخ الاحتياطي والسلامة + \n\n- يتم تأمين حسابك بمفتاح سري. المفتاح السري هو سلسلة عشوائية طويلة تبدأ بـ **nsec1**. أي شخص لديه حق الوصول إلى مفتاحك السري يمكنه نشر المحتوى باستخدام هويتك. + \n\n- لا تقم بوضع مفتاحك السري في أي موقع أو برنامج لا تثق به. + \n- مطوري Amethyst لن يطلبوا منك **أبدا** المفتاح السري الخاص بك. + \n- حافظ على نسخة احتياطية آمنة لمفتاحك السري لاسترداد الحساب. نوصي باستخدام برنامج لادارة كلمات المرور. + + مفتاحك السري (nsec) قد تم نسخه في الحافظة + إنسخ مفتاحي السري + فشلت المصادقة + خطأ + "تم إنشاؤه بواسطة %1$s" + "صورة شارة مكافئة ل %1$s" + لقد حصلت على شارة جائزة جديدة + تم نسخ نص الملاحظة/المنشور إلى الحافظة + تم نسخ عنوان @npub المؤلف إلى الحافظة + تم نسخ رمز الملاحظة/المنشور (note ID) إلى الحافظة + تحديد نص + "<استحالة فك تشفير الرسالة الخاصة> +\n\n أنت الآن في محادثة خاصة/مشفرة بين %1$s و %2$s ." + إضافة حساب جديد + الحسابات + اختر حساب + إضافة حساب جديد + تنشيط الحساب + يحتوي على مفتاح خاص + قراءة فقط، لا يوجد مفتاح خاص + رجوع + اختر + شارك رابط المتصفح + مشاركة + معرف المؤلف (ID) + رمز/معرف الملاحظة (Note ID) + نسخ النص + حذف + الغاء المتابعة + متابعة + طلب الحذف + سيطلب Amethyst حذف ملاحظتك من الخوادم (relays) الذي أنت متصل به حاليا. لا يوجد ضمان لحذف ملاحظتك بشكل دائم من تلك الخوادم أو من الخوادم الأخرى التي ربما حفظت فيها. + حظر + حذف + لا تظهر مرة أخرى + تصرف غير قانوني + حظر المستخدم سوف يخفي محتواه في التطبيق الخاص بك. ملاحظاتك لا تزال قابلة للعرض علناً، بما في ذلك للأشخاص الذين تقوم بحظرهم. يتم إدراج المستخدمين المحظورين على شاشة مرشحات الأمان (Security Filters screen). + + ستكون جميع التقارير المنشورة مرئية للجمهور. + اختياريا تستطيع توفير سياق إضافي حول تقريرك… + سياق إضافي + حدد سببا + تبليغ المنشور (Report) + حظر / تبليغ + حظر + المفضلة + المفضلة الخاصة + المفضلة العامة + إضافة إلى المفضلات الخاصة + إضافة إلى المفضلات العامة + إزالة من المفضلات الخاصة + إزالة من المفضلات العامة + خدمة Wallet Connect + (0–100)% + إغلاق بعد + أيام + تم إغلاق الاستطلاع لأي تصويت جديد + يسمح بصوت واحد فقط لكل مستخدم في هذا النوع من الاستطلاع + "البحث عن الحدث %1$s" + أضف رسالة عامة + أضف رسالة خاصة + أضف رسالة مع الفاتورة + شكرا لك على كل مساهمتك! + إنشاء وإضافة + لا يستطيع مؤلف الاستطلاع التصويت في استطلاعه. + هذا المحتوى هو نفسه منذ النشر + لقد تغير هذا المحتوى. ربما لم يشاهد مؤلفه التغيير أو يوافق عليه بعد. + أضف صورة + اضف فيديو + أضف مستند + أضف إلى الرسالة + وصف المحتوى/المحتويات + A blue boat in a white sandy beach at sunset +(قارب أزرق في شاطئ رملي أبيض عند غروب الشمس) + عام + يستطيع الجميع رؤية المعاملة والرسالة + خاص + يمكن للمرسل والمستقبل رؤية بعضهما البعض وقراءة الرسالة + مجهول الهوية + المستقبل والجمهور لا يعرفان من الذي قام بإرسال الدفع + خادم الملفات diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c2bde1bbf..4d9ec0a96 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -8,6 +8,7 @@ 帖文被标记为不当 频道图片 未找到相关事件 + 无法解密消息 群聊图片 明确内容 垃圾邮件 @@ -31,6 +32,9 @@ 使用私钥登录以便点赞帖子 没有设置Zap金额。长按以更改 使用私钥登录以便发送Zaps + 使用私钥登录以便能够关注 + 使用私钥登录以便能够取消关注 + 打闪 浏览次数 提升 已提升 @@ -41,6 +45,7 @@ " 和 " " 在频道 " 个人档案横幅 + 付款成功 " 关注" " 粉丝" 个人档案 @@ -158,6 +163,7 @@ 先显示 %1$s 在前 总是翻译为 %1$s 不再翻译 %1$s + Nostr 地址 从不 现在 @@ -242,6 +248,73 @@ 使用您的私钥在不离开应用程序的情况下支付 zaps。 任何具有访问 Nostr 私钥的人都可以使用您的钱包余额。要保留您的资金避免损失,如果可能,请使用私人中继器。中继器操作员可以看到您的付款元数据。 钱包绑定公钥 钱包绑定中继 + 显示私钥 + nsec / 十六进制私钥 聪数量 + 可选字段: + 打闪最低金额 + 打闪最高金额 + (0–100)% + + 打闪金额 "“正在查找事件%1$s”" + 添加公开消息 + 添加发票消息 + 创建并添加 + 添加图片 + 添加视频 + 添加文件 + 添加到消息 + 内容描述 + 一艘蓝色船,位于白沙滩的日落点 + 打闪种类 + 公开 + 所有人都能看到交易和消息 + 发送方和接收方能互相看到并读取消息 + 匿名 + 非打闪 + 断开与你的 Orbot/Tor 连接? + + + 全球 + 使用 Orbot + 今天 + 推荐: + 版本 + 软件 + 联络 + 支持的 NIPs + 接纳费 + 付款网址 + 限制 + 国家 + 语言 + 标签 + 消息长度 + 订阅 + 筛选器 + 离线 + 已结束 + 已关注的标签 + 中继器 + 直播 + 社区 + 聊天 + 敏感内容 + 设置 + 始终 + 仅限 Wifi + 从不 + 系统 + 浅色 + 深色 + 语言 + 主题 + 加载图像 + Nostr 地址已验证 + Nostr 地址验证失败 + 正在检查 Nostr 地址 + 默认 + 公开 + 创建于 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 7ed5a5a4f..f1c0d1684 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -32,6 +32,7 @@ 使用私鑰登錄以便點贊貼文 沒有設置Zap金額。長按以更改 使用私鑰登錄以便發送Zaps + 打閃 瀏覽次數 提升 已提升 @@ -42,6 +43,7 @@ " 和 " " 在頻道 " 個人檔案橫幅 + 付款成功 " 關注" " 粉絲" 個人檔案 @@ -158,6 +160,7 @@ 顯示 %1$s 在前 總是翻譯為 %1$s 不再翻譯 %1$s + Nostr 地址 從不 現在 小時 @@ -171,6 +174,7 @@ 將所有已知內容標記為已讀 將所有新內容標記為已讀 將所有內容標記為已讀 + 備份密鑰 ## 備份與安全提示 \n\n您的帳户由一個私人密鑰保護。 密鑰是以**nsec1**開頭的長隨機字符串。任何擁有您的私人密鑰的人都可以使用您的身份發佈內容。 \n\n- **不要**將您的私人密鑰添加到您不信任的任何網站或軟件,亦不要在網上公開。 @@ -189,6 +193,13 @@ 複製作者的 @npub 到剪貼板 複製文章ID (@note1) 到剪貼板 選擇文本 + 添加新帳戶 + 帳戶 + 選擇帳戶 + 添加新帳戶 + 活躍帳戶 + 有私鑰 + 返回 選擇 分享瀏覽網址 分享 @@ -200,4 +211,22 @@ 關注 請求刪貼 Amethyst 將請求您的記錄從當前連接的中繼器中刪除。不能保證您發佈的筆記將被永久從那些中繼器或其他存儲筆記的中繼器中刪除。 + 屏蔽 + 刪除 + 屏蔽 + 舉報 + 刪除 + 原因 + 選擇原因... + 發佈舉報 + 屏蔽並舉報 + 屏蔽 + 書籤 + 私人書籤 + 公開書籤 + 添加到私人書籤 + 添加到公開書籤 + 從私人書籤移除 + 從公開書籤移除 + 創建並添加 From d3de5e0a42f1972b6f6f1273790607b8211b6eb4 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Wed, 30 Aug 2023 12:50:26 +0000 Subject: [PATCH 04/18] New Crowdin translations by GitHub Action --- app/src/main/res/values-zh-rTW/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index f1c0d1684..feff88f6a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -229,4 +229,12 @@ 從私人書籤移除 從公開書籤移除 創建並添加 + 添加圖像 + 添加視頻 + 添加文件 + 添加到消息 + 打閃種類 + 公開 + 匿名 + 非打閃 From 05714de945967cbbcce548bd709f2704d897ce21 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Wed, 30 Aug 2023 21:14:24 +0000 Subject: [PATCH 05/18] New Crowdin translations by GitHub Action --- app/src/main/res/values-ar/strings.xml | 107 +++++++++++++++++++-- app/src/main/res/values-hu/strings.xml | 32 ++++++ app/src/main/res/values-zh-rTW/strings.xml | 25 +++++ 3 files changed, 158 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index fc239fb65..efb8c8673 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1,9 +1,9 @@ - أشر إلى رمز QR + أشر إلى رمز (QR Code) أظهر QR صورة الملف الشخصي - مسح QR + مسح رمز ال QR عرض على أي حال تم وضع علامة على المنشور على أنه غير لائق بواسطة المنشور غير موجود @@ -12,7 +12,7 @@ لا يمكن فك تشفير الرسالة صورة المجموعة محتوى فاضح - رسائل عشوائية + محتوى عشوائي التمثيل تصرف غير قانوني غير معروف @@ -59,7 +59,7 @@ Lightning تبرع ملاحظة للمستقبل شكرا جزيلا! - المبلغ في Sats + المبلغ ب الSats إرسال Sats "خطأ في تحليل المعاينة لـ %1$s : %2$s" "معاينة صورة البطاقة لـ %1$s" @@ -75,7 +75,7 @@ إنشاء إلغاء فشل تحميل الصورة - Relay عنوان + عنوان الخادم (Relay Adress) المنشورات Bytes الأخطاء @@ -98,7 +98,7 @@ فشل حفظ الصورة تحميل الصورة جاري التحميل… - لا يمتلك المستخدم إعداد عنوان lighting لاستقبال sats + لا يمتلك المستخدم عنوان (Lightning Address) لاستقبال sats "الرد هنا.. " نسخ معرف الملاحظة إلى الحافظة للمشاركة انسخ معرف القناة (ملاحظة) إلى الحافظة @@ -217,6 +217,9 @@ طلب الحذف سيطلب Amethyst حذف ملاحظتك من الخوادم (relays) الذي أنت متصل به حاليا. لا يوجد ضمان لحذف ملاحظتك بشكل دائم من تلك الخوادم أو من الخوادم الأخرى التي ربما حفظت فيها. حظر + حذف + حظر + التبليغ حذف لا تظهر مرة أخرى تصرف غير قانوني @@ -225,6 +228,7 @@ ستكون جميع التقارير المنشورة مرئية للجمهور. اختياريا تستطيع توفير سياق إضافي حول تقريرك… سياق إضافي + السبب حدد سببا تبليغ المنشور (Report) حظر / تبليغ @@ -237,6 +241,18 @@ إزالة من المفضلات الخاصة إزالة من المفضلات العامة خدمة Wallet Connect + خادم Wallet Connect + كلمة سر خدمة Wallet Connect + إظهار كلمة السر + المفتاح السري بصيغة nsec أو hex + نشر الاستطلاع + الحقول المطلوبة: + وصف الاستطلاع الأساسي… + الخيار %s + وصف خيار الاستطلاع + حقل اختياري + الحد الأدنى + الحد الاقصى (0–100)% إغلاق بعد أيام @@ -265,4 +281,83 @@ مجهول الهوية المستقبل والجمهور لا يعرفان من الذي قام بإرسال الدفع خادم الملفات + imgur.com - موثوق به + يمكن لـ Imgur تعديل الملف + nostrimg.com - (موثوق به) + يمكن لـ NostrImg تعديل الملف + nostr.build- (موثوق به) + يمكن لـ Nostr.build تعديل الملف + nostrfiles.dev - (موثوق به) + يمكن لـ Nostrfiles.dev تعديل الملف + nostrcheck.me - (موثوق به) + يمكن لـ nostrcheck.me تعديل الملف + تحقق مما إذا قام Imgur بتعديل الملف. +NIP جديد: قد لا يراه العملاء الآخرون + من طرف %1$s + ل %1$s + تنبيه: + الانضمام إلى المحادثة + معرف المستخدم أو المجموعة + npub, nevent أو hex + إنشاء + إنضمام + اليوم + تحذير من المحتوى + إخفاء المحتوى الحساس دائماً + إظهار المحتوى الحساس دائماً + إظهار تحذيرات المحتوى دائمًا + التطبيقات الموصى بها : + تصفية الرسائل المزعجة من الغرباء + تنبيه عندما تكون منشورتك قد تم التبليغ عنها + رمز رد فعل جديد + لم يتم تحديد أي نوع من ردود الفعل. اضغط مطولاً للتغيير + القراءة من الخادم (Relay) + الكتابة للخادم + حدث خطأ أثناء محاولة الحصول على معلومات الخادم من %1$s + المالك + الاصدار + البرنامج + جهة الاتصال + الNIPs المدعومة + رسوم القبول + رابط الدفع + الحدود + الدول + اللغات + الوسوم + سياسات النشر + طول الرسالة + الإشتراكات + الفلاتر + طول معرّف الاشتراك + الحد الأدنى لل prefix + الحد الأقصى لوسوم الحدث + طول المحتوى + الحد الأدنى لل PoW + المصادقة + الدفع + Cashu Token + عرض الموقع كـ + ميزة جديدة + تفعيل + عام + خاص + إلى + الموضوع + موضوع المحادثة + "\@User1, @User2, @User3" + أعضاء هذه المجموعة + التوضيح للأعضاء + تغيير اسم الأهداف الجديدة. + من أجل واجهة التطبيق + مظهر غامق أو فاتح أو اوتوماتيكي + تحميل الصور و الصور المتحركة تلقائياً + تشغيل الفيديوهات و الصور المتحركة تلقائياً + إظهار معاينات الروابط + متى يتم تحميل الصور + نسخ عنوان الرابط إلى الحافظة + انسخ معرف النص (ID) إلى الحافظة + أنشئ في + القواعد + تحديث الحالة diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index f49ebcaf4..0ab767de5 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -12,6 +12,7 @@ Az üzenet dekódolása sikertelen Csoport Kép Szókimondó tartalom + Spam Megszemélyesítés Illegális viselkedés Ismeretlen @@ -22,6 +23,7 @@ A bejegyzés azonosítójának másolása Közvetít Törlés Kérése + Tiltás és Jelentés Spam / Csalás bejelentés Megszemélyesítés bejelentés @@ -32,6 +34,8 @@ Jelentkezzen be privát kulccsal a bejegyzések kedveléséhez Nincs Zap összeg beállítva. Nyomja meg hosszan a változtatáshoz Jelentkezzen be privát kulccsal, hogy Zaps-t küldhessen + Jelentkezz be a privát kulccsal, hogy követni tudd + Jelentkezz be a privát kulccsal, hogy őt kikövesd Zap-ek Megtekintések száma Megosztás @@ -43,6 +47,8 @@ " és " "csatornában " Profil Banner + Sikeres fizetés + Hiba a hibaüzenet elemzésekor " Követek" " Követők" Profil @@ -161,6 +167,7 @@ Először %1$s nyelven Mindig fordítsa le %1$s-ra Soha ne fordíts %1$s-ról + Nostr Cím soha most ó @@ -257,7 +264,10 @@ Szavazás %s megoszlása Szavazás opcióinak leírása Kiegészítő mezők: + Minimum Zap + Maximum Zap Konszenzus + (0–100)% Szavazás lezárása napok A szavazásra nem lehet már új szavazatot leadni @@ -294,10 +304,22 @@ Feltöltés az Imgur-ba. Az Imgur a képet/videót bármikor megváltoztathatja nostrimg.com - kevésbé biztonságos Feltöltés a NostrImg-be. A NostrImg a képet bármikor megváltoztathatja + nostr.build - megbízható + A Nostr.build a fájlt módosíthatja + nostrfiles.dev - megbízható + A Nostrfiles.dev a fájlt módosíthatja + nostrcheck.me - megbízható + a Nostrcheck.me a fájlt módosíthatja Ellenőrizhető Imgur (NIP-94) Megvéd attól, hogy az Imgur a képet/videót a közzététel után megváltoztassa Ellenőrizhető NostrImg (NIP-94) Megvéd attól, hogy az NostrImg a képet a közzététel után megváltoztassa + Ellenőrizhető Nostr.build (NIP-94) + Ellenőrzi, hogy a Nostr.build a fájlt módosította-e. Új NIP: előfordulhat, hogy más kliensek nem jelenítik meg + Ellenőrizhető Nostrfiles.dev (NIP-94) + Ellenőrzi, hogy a Nostrfiles.dev a fájlt módosította-e. Új NIP: előfordulhat, hogy más kliensek nem jelenítik meg + Ellenőrizhető Nostrcheck.me (NIP-94) + Ellenőrzi, hogy a Nostrcheck.me a fájlt módosította-e. Új NIP: előfordulhat, hogy más kliensek nem jelenítik meg Saját csomópontjaid (NIP-95) A fájlokat a csomópontokra töltik fel és ott tárolják. Rögzített URL-től mentesek (harmadik féltől való függőség). Győződj meg róla, hogy legalább egy NIP-95 csomópont a csomópontlistában szerepel Tor/Orbot beállítása @@ -325,6 +347,7 @@ Értesítést küld, amikor privát üzeneted érkezik Zap-et kaptál Értesítést küld, amikor valaki neked Zap-et küldött + %1$s sats %1$s -tól %1$s -ért Értesítés: @@ -350,6 +373,7 @@ A ZapGyűjtés %1$s-nál. %2$s sats kell a célig Olvassás a csomópontból Írás a csomópontra + Hiba történt a közvetítő információinak lekérése közben a %1$s -ról Tulajdonos Verzió Szoftver @@ -372,8 +396,12 @@ Minimális PoW Azonosítás Fizetés + Cashu Token Beváltás + Nincs Lightning Cím beállítva + Token a vágólapra másolva ÉLŐ + NINCS ADÁS VÉGE ÜTEMEZETT Az élő közvetítés offline @@ -392,6 +420,7 @@ Beállítások Mindig Csak WIFI + Soha Rendszer Világos Sötét @@ -442,4 +471,7 @@ Állapotod változtatása Hiba a hibaüzenet elemzésekor A szavazatokat a Zap-ek összegével súlyozzuk. Beállíthatsz egy minimális összeget, hogy a kéretlen leveleket elkerüld, és egy maximális összeget annak elkerülésére, hogy a szavazás feletti irányítást a nagy Zapperek vegyék át. Mindkét mezőben ugyanazt az összeget használd, hogy minden szavazat azonos értéket kapjon. Bármilyen összeg elfogadásához, hagyjd üresen. + Zap küldése nem sikerült + Üzenet a Felhasználónak + Ok diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index feff88f6a..eaa2a1c33 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -237,4 +237,29 @@ 公開 匿名 非打閃 + Tor/Orbot 設置 + 通過你的 Orbot 設置連接 + 斷開與你的 Orbot/Tor 連接? + + + 直播 + 離線 + 已結束 + 直播已結束 + 以關注的標籤 + 中繼器 + 直播 + 社群 + 設置 + 始終 + 永不 + 系統 + 淺色 + 深色 + 語言 + 主題 + 圖像預覽 + 鏈接預覽 + 加載圖像 + 默認 From 5325542c81eed5c869322660ea942b246af07df8 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 30 Aug 2023 19:56:37 -0400 Subject: [PATCH 06/18] update vico --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7e7e64f1c..eb3e2ab7d 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { room_version = "2.4.3" accompanist_version = '0.30.1' coil_version = '2.4.0' - vico_version = '1.11.0' + vico_version = '1.11.1' exoplayer_version = '1.1.1' media3_version = '1.1.1' core_ktx_version = '1.10.1' From f0fcf1ea8ab0afce52b42890a72d4167540887df Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 09:04:09 -0400 Subject: [PATCH 07/18] Fixes the grammar in the nip05 error messages --- .../java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt | 4 ++-- .../amethyst/service/lnurl/LightningAddressResolver.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt index 4dd37d4b6..3da20b268 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt @@ -47,13 +47,13 @@ class Nip05Verifier() { if (it.isSuccessful) { onSuccess(it.body.string()) } else { - onError("Could not resolve $nip05. Error: ${it.code}. Check if the server up and if the address $nip05 is correct") + onError("Could not resolve $nip05. Error: ${it.code}. Check if the server is up and if the address $nip05 is correct") } } } override fun onFailure(call: Call, e: java.io.IOException) { - onError("Could not resolve $url. Check if the server up and if the address $nip05 is correct") + onError("Could not resolve $url. Check if the server is up and if the address $nip05 is correct") e.printStackTrace() } }) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt index 6adb42fd7..6d67e3ddb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt @@ -57,12 +57,12 @@ class LightningAddressResolver() { if (it.isSuccessful) { onSuccess(it.body.string()) } else { - onError("The receiver's lightning service at $url is not available. It was calculated from the lightning address \"${lnaddress}\". Error: ${it.code}. Check if the server up and if the lightning address is correct") + onError("The receiver's lightning service at $url is not available. It was calculated from the lightning address \"${lnaddress}\". Error: ${it.code}. Check if the server is up and if the lightning address is correct") } } } catch (e: Exception) { e.printStackTrace() - onError("Could not resolve $url. Check if the server up and if the lightning address $lnaddress is correct") + onError("Could not resolve $url. Check if the server is up and if the lightning address $lnaddress is correct") } } From 1af3bb7dfc0c8ce81676e13cb0fbf29992e913e9 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 11:48:22 -0400 Subject: [PATCH 08/18] Improve cohesiveness of the pruning system. --- .../amethyst/model/LocalCache.kt | 165 +++++++++--------- 1 file changed, 78 insertions(+), 87 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 165c0d06e..6c08e18f9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -1183,13 +1183,7 @@ object LocalCache { val childrenToBeRemoved = mutableListOf() toBeRemoved.forEach { - notes.remove(it.idHex) - // Doesn't need to clean up the replies and mentions.. Too small to matter. - - // Counts the replies - it.replyTo?.forEach { parent -> - parent.removeReply(it) - } + removeFromCache(it) childrenToBeRemoved.addAll(it.removeAllChildNotes()) } @@ -1208,12 +1202,7 @@ object LocalCache { val childrenToBeRemoved = mutableListOf() toBeRemoved.forEach { - notes.remove(it.idHex) - - // Counts the replies - it.replyTo?.forEach { parent -> - parent.removeReply(it) - } + removeFromCache(it) childrenToBeRemoved.addAll(it.removeAllChildNotes()) } @@ -1240,17 +1229,12 @@ object LocalCache { val childrenToBeRemoved = mutableListOf() toBeRemoved.forEach { - notes.remove(it.idHex) - val newerVersion = addressables[(it.event as? AddressableEvent)?.address()?.toTag()] if (newerVersion != null) { it.moveAllReferencesTo(newerVersion) } - it.replyTo?.forEach { masterNote -> - removeLinkFromParentNote(it) - } - + removeFromCache(it) childrenToBeRemoved.addAll(it.removeAllChildNotes()) } @@ -1279,11 +1263,7 @@ object LocalCache { val childrenToBeRemoved = mutableListOf() toBeRemoved.forEach { - notes.remove(it.idHex) - - removeLinkFromParentNote(it) - removeAuthorLinkTo(it) - + removeFromCache(it) childrenToBeRemoved.addAll(it.removeAllChildNotes()) } @@ -1300,73 +1280,39 @@ object LocalCache { } } - fun removeLinkFromParentNote(it: Note) { - it.replyTo?.forEach { masterNote -> - masterNote.removeReply(it) - masterNote.removeBoost(it) - masterNote.removeReaction(it) - masterNote.removeZap(it) - masterNote.removeReport(it) + private fun removeFromCache(note: Note) { + note.replyTo?.forEach { masterNote -> + masterNote.removeReply(note) + masterNote.removeBoost(note) + masterNote.removeReaction(note) + masterNote.removeZap(note) + masterNote.removeReport(note) masterNote.clearEOSE() // allows reloading of these events if needed } - } - fun pruneExpiredEvents() { - checkNotInMainThread() - - val toBeRemoved = notes.filter { - it.value.event?.isExpired() == true - }.values - - val childrenToBeRemoved = mutableListOf() - - toBeRemoved.forEach { - notes.remove(it.idHex) - - removeLinkFromParentNote(it) - removeAuthorLinkTo(it) - - childrenToBeRemoved.addAll(it.removeAllChildNotes()) - } - - removeChildrenOf(childrenToBeRemoved) - - if (toBeRemoved.size > 1) { - println("PRUNE: ${toBeRemoved.size} thread replies removed.") - } - } - - fun pruneHiddenMessages(account: Account) { - checkNotInMainThread() - - val childrenToBeRemoved = mutableListOf() - - val toBeRemoved = account.hiddenUsers.map { userHex -> - ( - notes.values.filter { - it.event?.pubKey() == userHex - } + addressables.values.filter { - it.event?.pubKey() == userHex - } - ).toSet() - }.flatten() - - toBeRemoved.forEach { - // Counts the replies - it.replyTo?.forEach { masterNote -> - removeLinkFromParentNote(it) + if (note.event is LnZapEvent) { + (note.event as LnZapEvent).zappedAuthor().mapNotNull { + val author = getUserIfExists(it) + author?.removeZap(note) + author?.clearEOSE() + } + } + if (note.event is LnZapRequestEvent) { + (note.event as LnZapRequestEvent).zappedAuthor().mapNotNull { + val author = getUserIfExists(it) + author?.removeZap(note) + author?.clearEOSE() + } + } + if (note.event is ReportEvent) { + (note.event as ReportEvent).reportedAuthor().mapNotNull { + val author = getUserIfExists(it.key) + author?.removeReport(note) + author?.clearEOSE() } - - notes.remove(it.idHex) - - removeAuthorLinkTo(it) - - childrenToBeRemoved.addAll(it.removeAllChildNotes()) } - removeChildrenOf(childrenToBeRemoved) - - println("PRUNE: ${toBeRemoved.size} messages removed because they were Hidden") + notes.remove(note.idHex) } fun removeAuthorLinkTo(note: Note) { @@ -1395,11 +1341,56 @@ object LocalCache { fun removeChildrenOf(nextToBeRemoved: List) { nextToBeRemoved.forEach { note -> - removeAuthorLinkTo(note) - notes.remove(note.idHex) + removeFromCache(note) } } + fun pruneExpiredEvents() { + checkNotInMainThread() + + val toBeRemoved = notes.filter { + it.value.event?.isExpired() == true + }.values + + val childrenToBeRemoved = mutableListOf() + + toBeRemoved.forEach { + removeFromCache(it) + childrenToBeRemoved.addAll(it.removeAllChildNotes()) + } + + removeChildrenOf(childrenToBeRemoved) + + if (toBeRemoved.size > 1) { + println("PRUNE: ${toBeRemoved.size} thread replies removed.") + } + } + + fun pruneHiddenMessages(account: Account) { + checkNotInMainThread() + + val childrenToBeRemoved = mutableListOf() + + val toBeRemoved = account.hiddenUsers.map { userHex -> + ( + notes.values.filter { + it.event?.pubKey() == userHex + } + addressables.values.filter { + it.event?.pubKey() == userHex + } + ).toSet() + }.flatten() + + toBeRemoved.forEach { + removeFromCache(it) + childrenToBeRemoved.addAll(it.removeAllChildNotes()) + } + + removeChildrenOf(childrenToBeRemoved) + + println("PRUNE: ${toBeRemoved.size} messages removed because they were Hidden") + } + fun pruneContactLists(loggedIn: Set) { checkNotInMainThread() From 0ccd41f5e824d7de001020ca867a774490945b7f Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 13:21:08 -0400 Subject: [PATCH 09/18] Fixes wrong EOSE updates. --- .../com/vitorpamplona/amethyst/service/NostrDataSource.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt index 7bf7084f1..55f01d3b4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt @@ -49,7 +49,7 @@ abstract class NostrDataSource(val debugName: String) { // Log.e("ERROR", "Relay ${relay.url}: ${error.message}") } - override fun onRelayStateChange(type: Relay.Type, relay: Relay, channel: String?) { + override fun onRelayStateChange(type: Relay.Type, relay: Relay, subscriptionId: String?) { // Log.d("RELAY", "Relay ${relay.url} ${when (type) { // Relay.Type.CONNECT -> "connected." // Relay.Type.DISCONNECT -> "disconnected." @@ -57,9 +57,9 @@ abstract class NostrDataSource(val debugName: String) { // Relay.Type.EOSE -> "sent all events it had stored." // }}") - if (type == Relay.Type.EOSE && channel != null) { + if (type == Relay.Type.EOSE && subscriptionId != null && subscriptionId in subscriptions.keys) { // updates a per subscripton since date - subscriptions[channel]?.updateEOSE(TimeUtils.now(), relay.url) + subscriptions[subscriptionId]?.updateEOSE(TimeUtils.now(), relay.url) } } From c934a1cdfe199f3ab3b607abde946d54e0df7776 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 13:36:46 -0400 Subject: [PATCH 10/18] Reduce the space between display name and status. --- .../com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index a038e28ce..9d89e4f7a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -220,7 +220,6 @@ fun ProfileContent( maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier - .padding(top = 15.dp) .clickable( onClick = { nav(route) From 669b33a3e1fa3a3779e20fc9c4562ae33e20e4d0 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 13:43:57 -0400 Subject: [PATCH 11/18] Reducing the height of the banner in the drawer --- .../vitorpamplona/amethyst/ui/navigation/DrawerContent.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 9d89e4f7a..0e8f37c8d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -109,7 +109,7 @@ fun DrawerContent( modifier = Modifier .fillMaxWidth() .padding(horizontal = 25.dp) - .padding(top = 100.dp), + .padding(top = 70.dp), scaffoldState, accountViewModel, nav @@ -162,7 +162,7 @@ fun ProfileContent( contentScale = ContentScale.FillWidth, modifier = Modifier .fillMaxWidth() - .height(150.dp) + .height(120.dp) ) } else { Image( @@ -171,7 +171,7 @@ fun ProfileContent( contentScale = ContentScale.FillWidth, modifier = Modifier .fillMaxWidth() - .height(150.dp) + .height(120.dp) ) } From 2771d34951ecd04a6ab5727b72b2b70a3e9542b3 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 14:53:43 -0400 Subject: [PATCH 12/18] Fixes the report card when the author has been blocked by the logged in user but the list loaded before the block user list. --- .../amethyst/ui/note/BlankNote.kt | 86 ++++++++++--------- .../amethyst/ui/note/ChannelCardCompose.kt | 23 ++--- .../ui/note/ChatroomMessageCompose.kt | 15 ++-- .../amethyst/ui/note/NoteCompose.kt | 31 ++----- .../amethyst/ui/screen/ThreadFeedView.kt | 1 + .../ui/screen/loggedIn/AccountViewModel.kt | 26 +++++- .../ui/screen/loggedIn/VideoScreen.kt | 21 ++--- 7 files changed, 96 insertions(+), 107 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt index ef8e4b76d..e987f7daa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt @@ -62,57 +62,63 @@ fun BlankNote(modifier: Modifier = Modifier, showDivider: Boolean = false, idHex @Composable fun HiddenNote( reports: ImmutableSet, + isHiddenAuthor: Boolean, accountViewModel: AccountViewModel, modifier: Modifier = Modifier, isQuote: Boolean = false, nav: (String) -> Unit, onClick: () -> Unit ) { - Column(modifier = modifier) { - Row(modifier = Modifier.padding(horizontal = if (!isQuote) 12.dp else 6.dp)) { - Column(modifier = Modifier.padding(start = if (!isQuote) 10.dp else 5.dp)) { - Row( - modifier = Modifier.padding( - start = 20.dp, - end = 20.dp - ), - verticalAlignment = Alignment.CenterVertically - ) { - Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(30.dp)) { - Text( - text = stringResource(R.string.post_was_flagged_as_inappropriate_by), - color = Color.Gray + Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) { + Row( + modifier = Modifier.padding(start = if (!isQuote) 30.dp else 25.dp, end = 20.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(30.dp) + ) { + Text( + text = stringResource(R.string.post_was_flagged_as_inappropriate_by), + color = Color.Gray + ) + FlowRow(modifier = Modifier.padding(top = 10.dp)) { + if (isHiddenAuthor) { + UserPicture( + user = accountViewModel.userProfile(), + size = Size35dp, + nav = nav, + accountViewModel = accountViewModel + ) + } + reports.forEach { + NoteAuthorPicture( + baseNote = it, + size = Size35dp, + nav = nav, + accountViewModel = accountViewModel ) - FlowRow(modifier = Modifier.padding(top = 10.dp)) { - reports.forEach { - NoteAuthorPicture( - baseNote = it, - nav = nav, - accountViewModel = accountViewModel, - size = Size35dp - ) - } - } - - Button( - modifier = Modifier.padding(top = 10.dp), - onClick = onClick, - shape = ButtonBorder, - colors = ButtonDefaults - .buttonColors( - backgroundColor = MaterialTheme.colors.primary - ), - contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp) - ) { - Text(text = stringResource(R.string.show_anyway), color = Color.White) - } } } - Divider( - thickness = 0.25.dp - ) + Button( + modifier = Modifier.padding(top = 10.dp), + onClick = onClick, + shape = ButtonBorder, + colors = ButtonDefaults + .buttonColors( + backgroundColor = MaterialTheme.colors.primary + ), + contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp) + ) { + Text(text = stringResource(R.string.show_anyway), color = Color.White) + } } } + + Divider( + thickness = 0.25.dp + ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt index 9c45a6a04..00352c989 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChannelCardCompose.kt @@ -76,7 +76,6 @@ import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_LIVE import com.vitorpamplona.quartz.events.LiveActivitiesEvent.Companion.STATUS_PLANNED import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -135,13 +134,9 @@ fun CheckHiddenChannelCardCompose( nav: (String) -> Unit ) { if (showHidden) { - var state by remember { + val state by remember { mutableStateOf( - NoteComposeReportState( - isAcceptable = true, - canPreview = true, - relevantReports = persistentSetOf() - ) + AccountViewModel.NoteComposeReportState() ) } @@ -185,19 +180,14 @@ fun LoadedChannelCardCompose( ) { var state by remember { mutableStateOf( - NoteComposeReportState( - isAcceptable = true, - canPreview = true, - relevantReports = persistentSetOf() - ) + AccountViewModel.NoteComposeReportState() ) } val scope = rememberCoroutineScope() - WatchForReports(note, accountViewModel) { newIsAcceptable, newCanPreview, newRelevantReports -> - if (newIsAcceptable != state.isAcceptable || newCanPreview != state.canPreview) { - val newState = NoteComposeReportState(newIsAcceptable, newCanPreview, newRelevantReports) + WatchForReports(note, accountViewModel) { newState -> + if (state != newState) { scope.launch(Dispatchers.Main) { state = newState } @@ -219,7 +209,7 @@ fun LoadedChannelCardCompose( @Composable fun RenderChannelCardReportState( - state: NoteComposeReportState, + state: AccountViewModel.NoteComposeReportState, note: Note, routeForLastRead: String? = null, modifier: Modifier = Modifier, @@ -233,6 +223,7 @@ fun RenderChannelCardReportState( if (showHiddenNote) { HiddenNote( state.relevantReports, + state.isHiddenAuthor, accountViewModel, modifier, false, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index dceec11dd..c3edb2350 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -69,8 +69,6 @@ import com.vitorpamplona.quartz.events.ChatMessageEvent import com.vitorpamplona.quartz.events.ImmutableListOfLists import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.toImmutableListOfLists -import kotlinx.collections.immutable.persistentSetOf -import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -152,17 +150,13 @@ fun LoadedChatMessageCompose( ) { var state by remember { mutableStateOf( - NoteComposeReportState( - isAcceptable = true, - canPreview = true, - relevantReports = persistentSetOf() - ) + AccountViewModel.NoteComposeReportState() ) } - WatchForReports(baseNote, accountViewModel) { newIsAcceptable, newCanPreview, newRelevantReports -> - if (newIsAcceptable != state.isAcceptable || newCanPreview != state.canPreview) { - state = NoteComposeReportState(newIsAcceptable, newCanPreview, newRelevantReports.toImmutableSet()) + WatchForReports(baseNote, accountViewModel) { newState -> + if (state != newState) { + state = newState } } @@ -178,6 +172,7 @@ fun LoadedChatMessageCompose( if (it) { HiddenNote( state.relevantReports, + state.isHiddenAuthor, accountViewModel, Modifier, innerQuote, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 56128b091..0948f5ced 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -38,7 +38,6 @@ import androidx.compose.material.Text import androidx.compose.material.darkColors import androidx.compose.material.lightColors import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable @@ -196,7 +195,6 @@ import com.vitorpamplona.quartz.events.TextNoteEvent import com.vitorpamplona.quartz.events.UserMetadata import com.vitorpamplona.quartz.events.toImmutableListOfLists import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf import kotlinx.collections.immutable.toImmutableList @@ -277,11 +275,7 @@ fun CheckHiddenNoteCompose( // Ignores reports as well val state by remember { mutableStateOf( - NoteComposeReportState( - isAcceptable = true, - canPreview = true, - relevantReports = persistentSetOf() - ) + AccountViewModel.NoteComposeReportState() ) } @@ -324,13 +318,6 @@ fun CheckHiddenNoteCompose( } } -@Immutable -data class NoteComposeReportState( - val isAcceptable: Boolean, - val canPreview: Boolean, - val relevantReports: ImmutableSet -) - @Composable fun LoadedNoteCompose( note: Note, @@ -347,19 +334,14 @@ fun LoadedNoteCompose( ) { var state by remember { mutableStateOf( - NoteComposeReportState( - isAcceptable = true, - canPreview = true, - relevantReports = persistentSetOf() - ) + AccountViewModel.NoteComposeReportState() ) } val scope = rememberCoroutineScope() - WatchForReports(note, accountViewModel) { newIsAcceptable, newCanPreview, newRelevantReports -> - if (newIsAcceptable != state.isAcceptable || newCanPreview != state.canPreview) { - val newState = NoteComposeReportState(newIsAcceptable, newCanPreview, newRelevantReports) + WatchForReports(note, accountViewModel) { newState -> + if (state != newState) { scope.launch(Dispatchers.Main) { state = newState } @@ -386,7 +368,7 @@ fun LoadedNoteCompose( @Composable fun RenderReportState( - state: NoteComposeReportState, + state: AccountViewModel.NoteComposeReportState, note: Note, routeForLastRead: String? = null, modifier: Modifier = Modifier, @@ -405,6 +387,7 @@ fun RenderReportState( if (showHiddenNote) { HiddenNote( state.relevantReports, + state.isHiddenAuthor, accountViewModel, modifier, isBoostedNote, @@ -436,7 +419,7 @@ fun RenderReportState( fun WatchForReports( note: Note, accountViewModel: AccountViewModel, - onChange: (Boolean, Boolean, ImmutableSet) -> Unit + onChange: (AccountViewModel.NoteComposeReportState) -> Unit ) { val userFollowsState by accountViewModel.userFollows.observeAsState() val noteReportsState by note.live().reports.observeAsState() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index a6b38f399..c24249ec0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -262,6 +262,7 @@ fun NoteMaster( HiddenNote( reports, + note.author?.let { account.isHidden(it) } ?: false, accountViewModel, Modifier, false, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 0b4a4ede2..2169f3725 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.content.Context import android.content.Intent import android.net.Uri +import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData @@ -410,14 +411,24 @@ class AccountViewModel(val account: Account) : ViewModel() { return account.defaultZapType } - fun isNoteAcceptable(note: Note, onReady: (Boolean, Boolean, ImmutableSet) -> Unit) { + @Immutable + data class NoteComposeReportState( + val isAcceptable: Boolean = true, + val canPreview: Boolean = true, + val isHiddenAuthor: Boolean = false, + val relevantReports: ImmutableSet = persistentSetOf() + ) + + fun isNoteAcceptable(note: Note, onReady: (NoteComposeReportState) -> Unit) { viewModelScope.launch { val isFromLoggedIn = note.author?.pubkeyHex == userProfile().pubkeyHex val isFromLoggedInFollow = note.author?.let { userProfile().isFollowingCached(it) } ?: true if (isFromLoggedIn || isFromLoggedInFollow) { // No need to process if from trusted people - onReady(true, true, persistentSetOf()) + onReady(NoteComposeReportState(true, true, false, persistentSetOf())) + } else if (note.author?.let { account.isHidden(it) } == true) { + onReady(NoteComposeReportState(false, false, true, persistentSetOf())) } else { val newCanPreview = !note.hasAnyReports() @@ -425,11 +436,18 @@ class AccountViewModel(val account: Account) : ViewModel() { if (newCanPreview && newIsAcceptable) { // No need to process reports if nothing is wrong - onReady(true, true, persistentSetOf()) + onReady(NoteComposeReportState(true, true, false, persistentSetOf())) } else { val newRelevantReports = account.getRelevantReports(note) - onReady(newIsAcceptable, newCanPreview, newRelevantReports.toImmutableSet()) + onReady( + NoteComposeReportState( + newIsAcceptable, + newCanPreview, + false, + newRelevantReports.toImmutableSet() + ) + ) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt index e42350ae1..615b06c11 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/VideoScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -52,7 +53,6 @@ import com.vitorpamplona.amethyst.ui.note.FileStorageHeaderDisplay import com.vitorpamplona.amethyst.ui.note.HiddenNote import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture -import com.vitorpamplona.amethyst.ui.note.NoteComposeReportState import com.vitorpamplona.amethyst.ui.note.NoteDropDownMenu import com.vitorpamplona.amethyst.ui.note.NoteUsernameDisplay import com.vitorpamplona.amethyst.ui.note.RenderRelay @@ -76,7 +76,6 @@ import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.events.FileHeaderEvent import com.vitorpamplona.quartz.events.FileStorageHeaderEvent import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentSetOf import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -250,19 +249,14 @@ fun LoadedVideoCompose( ) { var state by remember { mutableStateOf( - NoteComposeReportState( - isAcceptable = true, - canPreview = true, - relevantReports = persistentSetOf() - ) + AccountViewModel.NoteComposeReportState() ) } val scope = rememberCoroutineScope() - WatchForReports(note, accountViewModel) { newIsAcceptable, newCanPreview, newRelevantReports -> - if (newIsAcceptable != state.isAcceptable || newCanPreview != state.canPreview) { - val newState = NoteComposeReportState(newIsAcceptable, newCanPreview, newRelevantReports) + WatchForReports(note, accountViewModel) { newState -> + if (state != newState) { scope.launch(Dispatchers.Main) { state = newState } @@ -281,7 +275,7 @@ fun LoadedVideoCompose( @Composable fun RenderReportState( - state: NoteComposeReportState, + state: AccountViewModel.NoteComposeReportState, note: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit @@ -290,11 +284,12 @@ fun RenderReportState( Crossfade(targetState = !state.isAcceptable && !showReportedNote) { showHiddenNote -> if (showHiddenNote) { - Column(remember { Modifier.fillMaxSize(1f) }, verticalArrangement = Arrangement.Center) { + Column(remember { Modifier.fillMaxSize() }, verticalArrangement = Arrangement.Center) { HiddenNote( state.relevantReports, + state.isHiddenAuthor, accountViewModel, - Modifier, + Modifier.fillMaxWidth(), false, nav, onClick = { showReportedNote = true } From 8ea8cf29851e50fac4b04743dd20971ad4a240f8 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 15:23:30 -0400 Subject: [PATCH 13/18] Marks keep screen on to false when leaving a video player. --- .../java/com/vitorpamplona/amethyst/ui/components/VideoView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 22e677cbe..70a54ff35 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -704,6 +704,7 @@ fun ControlWhenPlayerIsActive( controller.addListener(listener) onDispose { + view.keepScreenOn = false controller.removeListener(listener) } } From f06b5fdacf74728cd04f669b8dde814530bcf040 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 16:41:02 -0400 Subject: [PATCH 14/18] New thread ordering scheme: 1. Thread author, ascending order by date. 2. My replies, descending by date. 3. My follow's replies, descending by date. 4. Everybody else, descending by date. --- .../com/vitorpamplona/amethyst/model/Note.kt | 48 ++++++++++++++++--- .../amethyst/ui/dal/ThreadFeedFilter.kt | 15 ++++-- .../amethyst/ui/screen/FeedViewModel.kt | 6 +-- .../ui/screen/loggedIn/ThreadScreen.kt | 2 +- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt index 5f84ed01c..ad0daf0fe 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Note.kt @@ -136,26 +136,60 @@ open class Note(val idHex: String) { .format(DateTimeFormatter.ofPattern("uuuu-MM-dd-HH:mm:ss")) } + data class LevelSignature(val signature: String, val createdAt: Long?, val author: User?) + /** * This method caches signatures during each execution to avoid recalculation in longer threads */ fun replyLevelSignature( eventsToConsider: Set, - cachedSignatures: MutableMap - ): String { + cachedSignatures: MutableMap, + account: User, + accountFollowingSet: Set, + now: Long + ): LevelSignature { val replyTo = replyTo if (event is RepostEvent || event is GenericRepostEvent || replyTo == null || replyTo.isEmpty()) { - return "/" + formattedDateTime(createdAt() ?: 0) + ";" + return LevelSignature( + signature = "/" + formattedDateTime(createdAt() ?: 0) + ";", + createdAt = createdAt(), + author = author + ) } - val mySignature = ( + val parent = ( replyTo .filter { it in eventsToConsider } // This forces the signature to be based on a branch, avoiding two roots .map { - cachedSignatures[it] ?: it.replyLevelSignature(eventsToConsider, cachedSignatures).apply { cachedSignatures.put(it, this) } + cachedSignatures[it] ?: it.replyLevelSignature( + eventsToConsider, + cachedSignatures, + account, + accountFollowingSet, + now + ).apply { cachedSignatures.put(it, this) } } - .maxByOrNull { it.length }?.removeSuffix(";") ?: "" - ) + "/" + formattedDateTime(createdAt() ?: 0) + ";" + .maxByOrNull { it.signature.length } + ) + + val parentSignature = parent?.signature?.removeSuffix(";") ?: "" + + val threadOrder = if (parent?.author == author && createdAt() != null) { + // author of the thread first, in **ascending** order + "9" + formattedDateTime((parent?.createdAt ?: 0) + (now - (createdAt() ?: 0))) + } else if (author?.pubkeyHex == account.pubkeyHex) { + "8" + formattedDateTime(createdAt() ?: 0) // my replies + } else if (author?.pubkeyHex in accountFollowingSet) { + "7" + formattedDateTime(createdAt() ?: 0) // my follows replies. + } else { + "0" + formattedDateTime(createdAt() ?: 0) // everyone else. + } + + val mySignature = LevelSignature( + signature = parentSignature + "/" + threadOrder + ";", + createdAt = createdAt(), + author = author + ) cachedSignatures[this] = mySignature return mySignature diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt index 411d37104..0f028d4bf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/dal/ThreadFeedFilter.kt @@ -1,22 +1,29 @@ package com.vitorpamplona.amethyst.ui.dal import androidx.compose.runtime.Immutable +import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.model.KIND3_FOLLOWS import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.ThreadAssembler +import com.vitorpamplona.quartz.utils.TimeUtils @Immutable -class ThreadFeedFilter(val noteId: String) : FeedFilter() { +class ThreadFeedFilter(val account: Account, val noteId: String) : FeedFilter() { override fun feedKey(): String { return noteId } override fun feed(): List { - val cachedSignatures: MutableMap = mutableMapOf() - val eventsToWatch = ThreadAssembler().findThreadFor(noteId) ?: emptySet() + val cachedSignatures: MutableMap = mutableMapOf() + val followingSet = account.selectedUsersFollowList(KIND3_FOLLOWS) ?: emptySet() + val eventsToWatch = ThreadAssembler().findThreadFor(noteId) + val now = TimeUtils.now() // Currently orders by date of each event, descending, at each level of the reply stack - val order = compareByDescending { it.replyLevelSignature(eventsToWatch, cachedSignatures) } + val order = compareByDescending { + it.replyLevelSignature(eventsToWatch, cachedSignatures, account.userProfile(), followingSet, now).signature + } return eventsToWatch.sortedWith(order) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt index 7561b818d..f245ee538 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedViewModel.kt @@ -95,10 +95,10 @@ class NostrDiscoverChatFeedViewModel(val account: Account) : FeedViewModel(Disco } } -class NostrThreadFeedViewModel(val noteId: String) : FeedViewModel(ThreadFeedFilter(noteId)) { - class Factory(val noteId: String) : ViewModelProvider.Factory { +class NostrThreadFeedViewModel(account: Account, noteId: String) : FeedViewModel(ThreadFeedFilter(account, noteId)) { + class Factory(val account: Account, val noteId: String) : ViewModelProvider.Factory { override fun create(modelClass: Class): NostrThreadFeedViewModel { - return NostrThreadFeedViewModel(noteId) as NostrThreadFeedViewModel + return NostrThreadFeedViewModel(account, noteId) as NostrThreadFeedViewModel } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt index a7107e819..8df68e327 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ThreadScreen.kt @@ -23,7 +23,7 @@ fun ThreadScreen(noteId: String?, accountViewModel: AccountViewModel, nav: (Stri val feedViewModel: NostrThreadFeedViewModel = viewModel( key = noteId + "NostrThreadFeedViewModel", - factory = NostrThreadFeedViewModel.Factory(noteId) + factory = NostrThreadFeedViewModel.Factory(accountViewModel.account, noteId) ) NostrThreadDataSource.loadThread(noteId) From 8982f02a4af3e246a3c79491ebbc70d6d1d30c88 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 17:13:32 -0400 Subject: [PATCH 15/18] v0.75.11 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0c7b3062f..7a2902b96 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 34 - versionCode 289 - versionName "0.75.10" + versionCode 290 + versionName "0.75.11" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { From 3423626c6005b97937f22c8f41d8bbf8dc7b5700 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 19:02:54 -0400 Subject: [PATCH 16/18] Fixes global feed --- .../com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt index 183fbb935..e69d8651c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrHomeDataSource.kt @@ -54,8 +54,8 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") { } fun createFollowAccountsFilter(): TypedFilter { - val follows = account.selectedUsersFollowList(account.defaultHomeFollowList) ?: emptySet() - val followSet = follows.plus(account.userProfile().pubkeyHex).toList() + val follows = account.selectedUsersFollowList(account.defaultHomeFollowList) + val followSet = follows?.plus(account.userProfile().pubkeyHex)?.toList()?.ifEmpty { null } return TypedFilter( types = setOf(FeedType.FOLLOWS), From 451c5d1648ee74b1df88912a23ec577f334a31ba Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 19:04:07 -0400 Subject: [PATCH 17/18] Removing LiveData Redirections --- .../amethyst/ui/note/UserProfilePicture.kt | 20 +++++-------------- .../ui/screen/loggedIn/AccountViewModel.kt | 12 +++++++---- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt index a7bb6a9fa..90d899f83 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/UserProfilePicture.kt @@ -73,9 +73,7 @@ fun NoteAuthorPicture( modifier: Modifier = Modifier, onClick: ((User) -> Unit)? = null ) { - val author by baseNote.live().metadata.map { - it.note.author - }.distinctUntilChanged().observeAsState(baseNote.author) + val author by baseNote.live().authorChanges.observeAsState(baseNote.author) Crossfade(targetState = author) { if (it == null) { @@ -112,23 +110,19 @@ fun UserPicture( accountViewModel: AccountViewModel, nav: (String) -> Unit ) { - val route by remember { + val route by remember(user) { derivedStateOf { "User/${user.pubkeyHex}" } } - val scope = rememberCoroutineScope() - ClickableUserPicture( baseUser = user, size = size, accountViewModel = accountViewModel, modifier = pictureModifier, onClick = { - scope.launch { - nav(route) - } + nav(route) } ) } @@ -274,9 +268,7 @@ fun InnerBaseUserPicture( accountViewModel: AccountViewModel, modifier: Modifier ) { - val userProfile by baseUser.live().metadata.map { - it.user.profilePicture() - }.distinctUntilChanged().observeAsState(baseUser.profilePicture()) + val userProfile by baseUser.live().profilePictureChanges.observeAsState(baseUser.profilePicture()) PictureAndFollowingMark( userHex = baseUser.pubkeyHex, @@ -508,9 +500,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: MutableState, accountVi fun WatchBookmarksFollowsAndAccount(note: Note, accountViewModel: AccountViewModel, onNew: (DropDownParams) -> Unit) { val followState by accountViewModel.userProfile().live().follows.observeAsState() val bookmarkState by accountViewModel.userProfile().live().bookmarks.observeAsState() - val showSensitiveContent by accountViewModel.accountLiveData.map { - it.account.showSensitiveContent - }.distinctUntilChanged().observeAsState(accountViewModel.account.showSensitiveContent) + val showSensitiveContent by accountViewModel.showSensitiveContentChanges.observeAsState(accountViewModel.account.showSensitiveContent) LaunchedEffect(key1 = followState, key2 = bookmarkState, key3 = showSensitiveContent) { launch(Dispatchers.IO) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 2169f3725..76bb6ab2d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -57,22 +57,26 @@ class AccountViewModel(val account: Account) : ViewModel() { val userFollows: LiveData = account.userProfile().live().follows.map { it } val userRelays: LiveData = account.userProfile().live().relays.map { it } - val discoveryListLiveData = accountLiveData.map { + val discoveryListLiveData = account.live.map { it.account.defaultDiscoveryFollowList }.distinctUntilChanged() - val homeListLiveData = accountLiveData.map { + val homeListLiveData = account.live.map { it.account.defaultHomeFollowList }.distinctUntilChanged() - val notificationListLiveData = accountLiveData.map { + val notificationListLiveData = account.live.map { it.account.defaultNotificationFollowList }.distinctUntilChanged() - val storiesListLiveData = accountLiveData.map { + val storiesListLiveData = account.live.map { it.account.defaultStoriesFollowList }.distinctUntilChanged() + val showSensitiveContentChanges = account.live.map { + it.account.showSensitiveContent + }.distinctUntilChanged() + fun updateAutomaticallyStartPlayback( automaticallyStartPlayback: ConnectivityType ) { From bfae5871c8e093b14b2e55959a9009f6837e2261 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 31 Aug 2023 19:05:12 -0400 Subject: [PATCH 18/18] v0.75.12 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7a2902b96..bb50960e2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { applicationId "com.vitorpamplona.amethyst" minSdk 26 targetSdk 34 - versionCode 290 - versionName "0.75.11" + versionCode 291 + versionName "0.75.12" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables {