feat: replied message view
This commit is contained in:
parent
e633c61820
commit
baf9cf43d7
4 changed files with 120 additions and 57 deletions
|
|
@ -4,14 +4,13 @@ use anyhow::{Context as _, bail};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
all::{
|
all::{
|
||||||
Attachment, CacheHttp, ChannelId, Component, Context, CreateComponent, CreateMediaGallery,
|
CacheHttp, ChannelId, Component, Context, CreateComponent, CreateMediaGallery,
|
||||||
CreateMediaGalleryItem, CreateSeparator, CreateTextDisplay, CreateUnfurledMediaItem,
|
CreateMediaGalleryItem, CreateSeparator, CreateTextDisplay, CreateUnfurledMediaItem,
|
||||||
CreateWebhook, EditWebhookMessage, EventHandler, ExecuteWebhook, FullEvent,
|
CreateWebhook, EditWebhookMessage, EventHandler, ExecuteWebhook, FullEvent,
|
||||||
GenericChannelId, GuildId, Interaction, Message, MessageFlags, MessageId, MessageSnapshot,
|
GenericChannelId, GuildId, Interaction, Message, MessageFlags, MessageId, MessageSnapshot,
|
||||||
Reaction, StickerFormatType, StickerItem, Webhook, WebhookId,
|
Reaction, Webhook, WebhookId,
|
||||||
},
|
},
|
||||||
async_trait,
|
async_trait,
|
||||||
small_fixed_array::{FixedArray, FixedString},
|
|
||||||
};
|
};
|
||||||
use sqlx::{PgExecutor, PgPool};
|
use sqlx::{PgExecutor, PgPool};
|
||||||
use tokio::sync::Semaphore;
|
use tokio::sync::Semaphore;
|
||||||
|
|
@ -19,20 +18,17 @@ use tokio::sync::Semaphore;
|
||||||
use crate::{
|
use crate::{
|
||||||
commands,
|
commands,
|
||||||
db::{GuildRow, MessageRow, WebhookRow},
|
db::{GuildRow, MessageRow, WebhookRow},
|
||||||
|
message_builder::{CloneBuilderMessage, get_message_components},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CloneBuilderMessage {
|
|
||||||
pub content: FixedString<u16>,
|
|
||||||
pub attachments: FixedArray<Attachment>,
|
|
||||||
pub sticker_items: FixedArray<StickerItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Message> for CloneBuilderMessage {
|
impl From<Message> for CloneBuilderMessage {
|
||||||
fn from(value: Message) -> Self {
|
fn from(value: Message) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
link: Some(value.link()),
|
||||||
content: value.content,
|
content: value.content,
|
||||||
attachments: value.attachments,
|
attachments: value.attachments,
|
||||||
sticker_items: value.sticker_items,
|
sticker_items: value.sticker_items,
|
||||||
|
replied_message: value.referenced_message.map(|m| Box::new(Self::from(*m))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,9 +36,11 @@ impl From<Message> for CloneBuilderMessage {
|
||||||
impl From<MessageSnapshot> for CloneBuilderMessage {
|
impl From<MessageSnapshot> for CloneBuilderMessage {
|
||||||
fn from(value: MessageSnapshot) -> Self {
|
fn from(value: MessageSnapshot) -> Self {
|
||||||
CloneBuilderMessage {
|
CloneBuilderMessage {
|
||||||
|
link: None,
|
||||||
content: value.content,
|
content: value.content,
|
||||||
attachments: value.attachments,
|
attachments: value.attachments,
|
||||||
sticker_items: value.sticker_items,
|
sticker_items: value.sticker_items,
|
||||||
|
replied_message: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -325,54 +323,7 @@ impl Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !reference_msg.content.is_empty() {
|
get_message_components(&reference_msg, &mut components, &guild.lang);
|
||||||
components.push(CreateComponent::TextDisplay(CreateTextDisplay::new(
|
|
||||||
&reference_msg.content,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let images = reference_msg
|
|
||||||
.attachments
|
|
||||||
.iter()
|
|
||||||
.filter(|x| x.width.is_some())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if !images.is_empty() {
|
|
||||||
components.push(CreateComponent::MediaGallery(CreateMediaGallery::new(
|
|
||||||
images
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| {
|
|
||||||
CreateMediaGalleryItem::new(CreateUnfurledMediaItem::new(x.url.clone()))
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(sticker_url) = reference_msg
|
|
||||||
.sticker_items
|
|
||||||
.iter()
|
|
||||||
.filter_map(|x| {
|
|
||||||
let ext = match x.format_type {
|
|
||||||
StickerFormatType::Png | StickerFormatType::Apng => "png",
|
|
||||||
StickerFormatType::Gif => "gif",
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let url = format!(
|
|
||||||
"https://media.discordapp.net/stickers/{}.{}?size=160&quality=lossless",
|
|
||||||
&x.id, ext
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(url)
|
|
||||||
})
|
|
||||||
.next()
|
|
||||||
{
|
|
||||||
let item = CreateMediaGalleryItem::new(CreateUnfurledMediaItem::new(sticker_url));
|
|
||||||
|
|
||||||
components.push(CreateComponent::MediaGallery(CreateMediaGallery::new(
|
|
||||||
vec![item],
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
components.push(CreateComponent::Separator(CreateSeparator::new(true)));
|
components.push(CreateComponent::Separator(CreateSeparator::new(true)));
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ pub trait Locale: Send + Sync {
|
||||||
fn original_message(&self) -> &'static str;
|
fn original_message(&self) -> &'static str;
|
||||||
fn admin_required(&self) -> &'static str;
|
fn admin_required(&self) -> &'static str;
|
||||||
|
|
||||||
|
fn replied_message(&self, link: &str) -> String;
|
||||||
fn lang_changed(&self, new_lang: Lang) -> String;
|
fn lang_changed(&self, new_lang: Lang) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,6 +63,10 @@ impl Locale for Korean {
|
||||||
fn admin_required(&self) -> &'static str {
|
fn admin_required(&self) -> &'static str {
|
||||||
"관리자 권한이 필요합니다"
|
"관리자 권한이 필요합니다"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn replied_message(&self, link: &str) -> String {
|
||||||
|
format!("[답장한 메시지]({link})")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct English;
|
struct English;
|
||||||
|
|
@ -78,4 +83,8 @@ impl Locale for English {
|
||||||
fn admin_required(&self) -> &'static str {
|
fn admin_required(&self) -> &'static str {
|
||||||
"Administrator permission is required"
|
"Administrator permission is required"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn replied_message(&self, link: &str) -> String {
|
||||||
|
format!("[Replied Message]({link})")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ mod config;
|
||||||
mod db;
|
mod db;
|
||||||
mod handler;
|
mod handler;
|
||||||
mod lang;
|
mod lang;
|
||||||
|
mod message_builder;
|
||||||
mod modal;
|
mod modal;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
||||||
102
src/bot/message_builder.rs
Normal file
102
src/bot/message_builder.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
use serenity::{all::*, small_fixed_array::*};
|
||||||
|
|
||||||
|
use crate::lang::Lang;
|
||||||
|
|
||||||
|
pub struct CloneBuilderMessage {
|
||||||
|
pub link: Option<MessageLink>,
|
||||||
|
pub content: FixedString<u16>,
|
||||||
|
pub attachments: FixedArray<Attachment>,
|
||||||
|
pub sticker_items: FixedArray<StickerItem>,
|
||||||
|
pub replied_message: Option<Box<CloneBuilderMessage>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_message_components(
|
||||||
|
reference_msg: &CloneBuilderMessage,
|
||||||
|
components: &mut Vec<CreateComponent<'_>>,
|
||||||
|
lang: &Lang,
|
||||||
|
) {
|
||||||
|
if let Some(replied) = &reference_msg.replied_message
|
||||||
|
&& let Some(link) = &reference_msg.link
|
||||||
|
{
|
||||||
|
let mut replied_components = vec![];
|
||||||
|
get_message_components(replied, &mut replied_components, lang);
|
||||||
|
|
||||||
|
let mut inner = vec![];
|
||||||
|
|
||||||
|
inner.push(CreateContainerComponent::TextDisplay(
|
||||||
|
CreateTextDisplay::new(lang.to_locale().replied_message(&link.to_string())),
|
||||||
|
));
|
||||||
|
|
||||||
|
inner.extend(replied_components.into_iter().filter_map(|x| match x {
|
||||||
|
CreateComponent::ActionRow(create_action_row) => {
|
||||||
|
Some(CreateContainerComponent::ActionRow(create_action_row))
|
||||||
|
}
|
||||||
|
CreateComponent::Section(create_section) => {
|
||||||
|
Some(CreateContainerComponent::Section(create_section))
|
||||||
|
}
|
||||||
|
CreateComponent::TextDisplay(create_text_display) => {
|
||||||
|
Some(CreateContainerComponent::TextDisplay(create_text_display))
|
||||||
|
}
|
||||||
|
CreateComponent::MediaGallery(create_media_gallery) => {
|
||||||
|
Some(CreateContainerComponent::MediaGallery(create_media_gallery))
|
||||||
|
}
|
||||||
|
CreateComponent::File(create_file) => Some(CreateContainerComponent::File(create_file)),
|
||||||
|
CreateComponent::Separator(create_separator) => {
|
||||||
|
Some(CreateContainerComponent::Separator(create_separator))
|
||||||
|
}
|
||||||
|
CreateComponent::Container(_create_container) => None,
|
||||||
|
CreateComponent::Label(_create_label) => None,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let comp = CreateComponent::Container(CreateContainer::new(inner));
|
||||||
|
components.push(comp);
|
||||||
|
components.push(CreateComponent::Separator(CreateSeparator::new(false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reference_msg.content.is_empty() {
|
||||||
|
components.push(CreateComponent::TextDisplay(CreateTextDisplay::new(
|
||||||
|
reference_msg.content.clone(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let images = reference_msg
|
||||||
|
.attachments
|
||||||
|
.iter()
|
||||||
|
.filter(|x| x.width.is_some())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if !images.is_empty() {
|
||||||
|
components.push(CreateComponent::MediaGallery(CreateMediaGallery::new(
|
||||||
|
images
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| CreateMediaGalleryItem::new(CreateUnfurledMediaItem::new(x.url.clone())))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(sticker_url) = reference_msg
|
||||||
|
.sticker_items
|
||||||
|
.iter()
|
||||||
|
.filter_map(|x| {
|
||||||
|
let ext = match x.format_type {
|
||||||
|
StickerFormatType::Png | StickerFormatType::Apng => "png",
|
||||||
|
StickerFormatType::Gif => "gif",
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = format!(
|
||||||
|
"https://media.discordapp.net/stickers/{}.{}?size=160&quality=lossless",
|
||||||
|
&x.id, ext
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(url)
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
{
|
||||||
|
let item = CreateMediaGalleryItem::new(CreateUnfurledMediaItem::new(sticker_url));
|
||||||
|
|
||||||
|
components.push(CreateComponent::MediaGallery(CreateMediaGallery::new(
|
||||||
|
vec![item],
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue