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 serenity::{
|
||||
all::{
|
||||
Attachment, CacheHttp, ChannelId, Component, Context, CreateComponent, CreateMediaGallery,
|
||||
CacheHttp, ChannelId, Component, Context, CreateComponent, CreateMediaGallery,
|
||||
CreateMediaGalleryItem, CreateSeparator, CreateTextDisplay, CreateUnfurledMediaItem,
|
||||
CreateWebhook, EditWebhookMessage, EventHandler, ExecuteWebhook, FullEvent,
|
||||
GenericChannelId, GuildId, Interaction, Message, MessageFlags, MessageId, MessageSnapshot,
|
||||
Reaction, StickerFormatType, StickerItem, Webhook, WebhookId,
|
||||
Reaction, Webhook, WebhookId,
|
||||
},
|
||||
async_trait,
|
||||
small_fixed_array::{FixedArray, FixedString},
|
||||
};
|
||||
use sqlx::{PgExecutor, PgPool};
|
||||
use tokio::sync::Semaphore;
|
||||
|
|
@ -19,20 +18,17 @@ use tokio::sync::Semaphore;
|
|||
use crate::{
|
||||
commands,
|
||||
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 {
|
||||
fn from(value: Message) -> Self {
|
||||
Self {
|
||||
link: Some(value.link()),
|
||||
content: value.content,
|
||||
attachments: value.attachments,
|
||||
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 {
|
||||
fn from(value: MessageSnapshot) -> Self {
|
||||
CloneBuilderMessage {
|
||||
link: None,
|
||||
content: value.content,
|
||||
attachments: value.attachments,
|
||||
sticker_items: value.sticker_items,
|
||||
replied_message: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -325,54 +323,7 @@ impl Handler {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if !reference_msg.content.is_empty() {
|
||||
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],
|
||||
)));
|
||||
}
|
||||
get_message_components(&reference_msg, &mut components, &guild.lang);
|
||||
}
|
||||
|
||||
components.push(CreateComponent::Separator(CreateSeparator::new(true)));
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ pub trait Locale: Send + Sync {
|
|||
fn original_message(&self) -> &'static str;
|
||||
fn admin_required(&self) -> &'static str;
|
||||
|
||||
fn replied_message(&self, link: &str) -> String;
|
||||
fn lang_changed(&self, new_lang: Lang) -> String;
|
||||
}
|
||||
|
||||
|
|
@ -62,6 +63,10 @@ impl Locale for Korean {
|
|||
fn admin_required(&self) -> &'static str {
|
||||
"관리자 권한이 필요합니다"
|
||||
}
|
||||
|
||||
fn replied_message(&self, link: &str) -> String {
|
||||
format!("[답장한 메시지]({link})")
|
||||
}
|
||||
}
|
||||
|
||||
struct English;
|
||||
|
|
@ -78,4 +83,8 @@ impl Locale for English {
|
|||
fn admin_required(&self) -> &'static str {
|
||||
"Administrator permission is required"
|
||||
}
|
||||
|
||||
fn replied_message(&self, link: &str) -> String {
|
||||
format!("[Replied Message]({link})")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ mod config;
|
|||
mod db;
|
||||
mod handler;
|
||||
mod lang;
|
||||
mod message_builder;
|
||||
mod modal;
|
||||
|
||||
#[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