diff --git a/resources/xml/fragment/inbox_chat.xml b/resources/xml/fragment/inbox_chat.xml index bb312f986..7796a7f98 100644 --- a/resources/xml/fragment/inbox_chat.xml +++ b/resources/xml/fragment/inbox_chat.xml @@ -4,16 +4,19 @@ height="auto" width="auto"> - - - + + + @@ -16,15 +17,15 @@ textColor="@theme/font/grey" /> + width="auto" + height="auto" + grow="1" + wireframe="false" /> - - - - + + diff --git a/wiliwili/include/api/bilibili.h b/wiliwili/include/api/bilibili.h index 160284bd0..def48c95d 100644 --- a/wiliwili/include/api/bilibili.h +++ b/wiliwili/include/api/bilibili.h @@ -134,7 +134,7 @@ class BilibiliClient { const ErrorCallback& error = nullptr); /// 批量获取用户昵称头像 - static void get_user_cards(const std::vector uids, + static void get_user_cards(const std::vector& uids, const std::function& callback = nullptr, const ErrorCallback& error = nullptr); diff --git a/wiliwili/include/api/bilibili/api.h b/wiliwili/include/api/bilibili/api.h index 7d3b24b34..4db803789 100644 --- a/wiliwili/include/api/bilibili/api.h +++ b/wiliwili/include/api/bilibili/api.h @@ -175,6 +175,7 @@ const std::string MsgFeedReply = _apiBase + "/x/msgfeed/reply"; const std::string UserCards = _vcBase + "/account/v1/user/cards"; const std::string UserDynamicStat = _vcBase + "/dynamic_svr/v1/dynamic_svr/space_num_ex"; const std::string ChatSessions = _vcBase + "/session_svr/v1/session_svr/new_sessions"; +const std::string ChatUpdateAct = _vcBase + "/session_svr/v1/session_svr/update_ack"; const std::string ChatFetchMsgs = _vcBase + "/svr_sync/v1/svr_sync/fetch_session_msgs"; const std::string ChatSendMsg = _vcBase + "/web_im/v1/web_im/send_msg"; /// 用户追番/追剧 diff --git a/wiliwili/include/api/bilibili/result/inbox_result.h b/wiliwili/include/api/bilibili/result/inbox_result.h index 1d1286c05..081130150 100644 --- a/wiliwili/include/api/bilibili/result/inbox_result.h +++ b/wiliwili/include/api/bilibili/result/inbox_result.h @@ -30,8 +30,9 @@ class MsgFeedItem { std::string title; std::string image; std::string source_content; + std::string uri; }; -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(MsgFeedItem, subject_id, source_id, type, title, image, source_content); +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MsgFeedItem, subject_id, source_id, type, title, image, source_content, uri); class FeedReplyResult { public: @@ -116,12 +117,17 @@ class InboxMessageResult { uint64_t sender_uid, receiver_id; uint64_t msg_seqno; std::vector at_uids; - int receiver_type, msg_type; - std::string content; + int msg_type, msg_source; + nlohmann::json content; time_t timestamp; }; -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(InboxMessageResult, sender_uid, receiver_id, receiver_type, msg_seqno, at_uids, - msg_type, content, timestamp); +inline void from_json(const nlohmann::json& nlohmann_json_j, InboxMessageResult& nlohmann_json_t) { + if (nlohmann_json_j.contains("content") && nlohmann_json_j.at("content").is_string()) { + nlohmann::json::parse(nlohmann_json_j.at("content").get()).get_to(nlohmann_json_t.content); + } + NLOHMANN_JSON_EXPAND( + NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, sender_uid, receiver_id, msg_seqno, msg_type, msg_source, timestamp)); +} typedef std::vector InboxMessageListResult; @@ -162,11 +168,18 @@ class InboxChatResult { uint64_t talker_id; int session_type; time_t session_ts; + uint64_t max_seqno; + int unread_count; InboxAccountInfo account_info; InboxMessageResult last_msg; }; -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(InboxChatResult, talker_id, session_type, session_ts, account_info, - last_msg); +inline void from_json(const nlohmann::json& nlohmann_json_j, InboxChatResult& nlohmann_json_t) { + if (nlohmann_json_j.contains("last_msg") && nlohmann_json_j.at("last_msg").is_object()) { + nlohmann_json_j.at("last_msg").get_to(nlohmann_json_t.last_msg); + } + NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, talker_id, session_type, session_ts, max_seqno, + unread_count, account_info)); +} typedef std::vector InboxChatListResult; diff --git a/wiliwili/include/fragment/inbox_chat.hpp b/wiliwili/include/fragment/inbox_chat.hpp index 61089f139..5b5832b23 100644 --- a/wiliwili/include/fragment/inbox_chat.hpp +++ b/wiliwili/include/fragment/inbox_chat.hpp @@ -5,11 +5,14 @@ #include "presenter/inbox_msg.hpp" +namespace brls { +class Label; +}; class RecyclingGrid; class InboxChat : public brls::Box, public InboxMsgRequest { public: - InboxChat(uint64_t talker_id, int session_type); + InboxChat(const bilibili::InboxChatResult& r); ~InboxChat() override; @@ -19,4 +22,5 @@ class InboxChat : public brls::Box, public InboxMsgRequest { private: BRLS_BIND(RecyclingGrid, recyclingGrid, "inbox/msgList"); + BRLS_BIND(brls::Label, labelTalker, "inbox/talker"); }; \ No newline at end of file diff --git a/wiliwili/include/fragment/inbox_view.hpp b/wiliwili/include/fragment/inbox_view.hpp index e6d614d18..5c83c803d 100644 --- a/wiliwili/include/fragment/inbox_view.hpp +++ b/wiliwili/include/fragment/inbox_view.hpp @@ -23,8 +23,8 @@ class InboxView : public brls::Box, public InboxChatRequest { void onError(const std::string& error) override; private: - BRLS_BIND(ButtonClose, closebtn, "button/close"); + BRLS_BIND(ButtonClose, closebtn, "inbox/close"); BRLS_BIND(brls::Box, cancel, "player/cancel"); - BRLS_BIND(AutoTabFrame, inboxFrame, "inbox/tab/frame"); + BRLS_BIND(AutoTabFrame, tabFrame, "inbox/tab/frame"); BRLS_BIND(RecyclingGrid, recyclingGrid, "inbox/chatList"); }; \ No newline at end of file diff --git a/wiliwili/include/presenter/inbox_chat.hpp b/wiliwili/include/presenter/inbox_chat.hpp index d74446319..e1493be66 100644 --- a/wiliwili/include/presenter/inbox_chat.hpp +++ b/wiliwili/include/presenter/inbox_chat.hpp @@ -7,6 +7,8 @@ #include "bilibili/result/inbox_result.h" #include "presenter.h" +typedef std::unordered_map InboxUserMap; + class InboxChatRequest : public Presenter { public: virtual void onChatList(const bilibili::InboxChatListResult& result, bool refresh); @@ -17,6 +19,4 @@ class InboxChatRequest : public Presenter { protected: time_t last_time = 0; - - std::unordered_map user_map; }; \ No newline at end of file diff --git a/wiliwili/include/view/inbox_msg_card.hpp b/wiliwili/include/view/inbox_msg_card.hpp new file mode 100644 index 000000000..a0018a433 --- /dev/null +++ b/wiliwili/include/view/inbox_msg_card.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "view/recycling_grid.hpp" +#include "bilibili/result/inbox_result.h" + +class TextBox; + +typedef std::shared_ptr InboxEmotePtr; +typedef std::unordered_map IEMap; + +class InboxMsgCard : public RecyclingGridItem { +public: + InboxMsgCard(); + + void setCard(const bilibili::InboxMessageResult& r, const IEMap& m, uint64_t talker); + + void setTime(const std::string& time_str); + + void setAvatar(const std::string& face); + +private: + BRLS_BIND(TextBox, textBox, "msg/content"); + BRLS_BIND(brls::Box, msgBox, "msg/content_box"); + BRLS_BIND(brls::Image, talker, "avatar/talker"); + BRLS_BIND(brls::Image, mine, "avatar/mine"); + BRLS_BIND(brls::Label, msgTime, "msg/time"); +}; diff --git a/wiliwili/source/activity/main_activity.cpp b/wiliwili/source/activity/main_activity.cpp index 2d16dd26e..a2336991f 100644 --- a/wiliwili/source/activity/main_activity.cpp +++ b/wiliwili/source/activity/main_activity.cpp @@ -18,6 +18,7 @@ #include "activity/main_activity.hpp" #include "utils/activity_helper.hpp" +#include "utils/config_helper.hpp" #include "view/custom_button.hpp" #include "view/auto_tab_frame.hpp" #include "view/svg_image.hpp" @@ -74,8 +75,10 @@ void MainActivity::onContentAvailable() { }); this->settingBtn->addGestureRecognizer(new brls::TapGestureRecognizer(this->settingBtn)); - this->inboxBtn->registerClickAction([](brls::View* view) -> bool { - Intent::openInbox(); + this->inboxBtn->registerClickAction([this](brls::View* view) -> bool { + if (ProgramConfig::instance().hasLoginInfo()) { + Intent::openInbox(); + } return true; }); diff --git a/wiliwili/source/api/mine_api.cpp b/wiliwili/source/api/mine_api.cpp index a370c58cf..c0470e672 100644 --- a/wiliwili/source/api/mine_api.cpp +++ b/wiliwili/source/api/mine_api.cpp @@ -126,7 +126,7 @@ void BilibiliClient::get_user_dynamic_count(const std::string& mid, HTTP::getResultAsync(Api::UserDynamicStat, {{"uids", mid}}, callback, error); } -void BilibiliClient::get_user_cards(const std::vector uids, +void BilibiliClient::get_user_cards(const std::vector& uids, const std::function& callback, const ErrorCallback& error) { std::string mid = fmt::format("{}", fmt::join(uids, ",")); @@ -136,7 +136,10 @@ void BilibiliClient::get_user_cards(const std::vector uids, void BilibiliClient::new_inbox_sessions(time_t begin_ts, const std::function& callback, const ErrorCallback& error) { - HTTP::getResultAsync(Api::ChatSessions, {{"begin_ts", std::to_string(begin_ts)}}, callback, error); + HTTP::getResultAsync(Api::ChatSessions, { + {"begin_ts", std::to_string(begin_ts)}, + {"mobi_app", "web"}, + }, callback, error); } void BilibiliClient::fetch_inbox_msgs(const std::string& talker_id, size_t size, @@ -145,10 +148,12 @@ void BilibiliClient::fetch_inbox_msgs(const std::string& talker_id, size_t size, const std::function& callback, const ErrorCallback& error) { HTTP::getResultAsync(Api::ChatFetchMsgs, { + {"sender_device_id", "1"}, {"talker_id", talker_id}, {"session_type", std::to_string(session_type)}, {"begin_seqno", begin_seqno}, {"size", std::to_string(size)}, + {"mobi_app", "web"}, }, callback, error); } diff --git a/wiliwili/source/fragment/inbox_chat.cpp b/wiliwili/source/fragment/inbox_chat.cpp index a661caaec..6a2794d8b 100644 --- a/wiliwili/source/fragment/inbox_chat.cpp +++ b/wiliwili/source/fragment/inbox_chat.cpp @@ -2,94 +2,31 @@ #include #include "fragment/inbox_chat.hpp" -#include "view/recycling_grid.hpp" - -#include "view/text_box.hpp" +#include "view/inbox_msg_card.hpp" +#include "utils/number_helper.hpp" using namespace brls::literals; -class ChatMsgCard : public RecyclingGridItem { -public: - ChatMsgCard() { this->inflateFromXMLRes("xml/views/inbox_msg.xml"); } - - void setCard(const bilibili::InboxMessageResult& r) { - try { - auto j = nlohmann::json::parse(r.content); - switch (r.msg_type) { - case 1: - this->textBox->setText(j.at("content").get()); - this->msgBox->setVisibility(brls::Visibility::VISIBLE); - this->picBox->setVisibility(brls::Visibility::GONE); - break; - case 2: { - std::string pic = j.at("url").get(); - float width = j.at("width").get(); - float height = j.at("height").get(); - - if (width > 400.f) { - height = height * 400.f / width; - width = 400.f; - } - this->picBox->setWidth(width); - this->picBox->setHeight(height); - ImageHelper::with(this->msgPic)->load(pic); - - this->picBox->setVisibility(brls::Visibility::VISIBLE); - this->msgBox->setVisibility(brls::Visibility::GONE); - break; - } - } - - } catch (const std::exception& ex) { - } - } - - void setTime(const std::string& time_str) { - if (time_str.empty()) { - this->labelTime->setVisibility(brls::Visibility::GONE); - } else { - this->labelTime->setText(time_str); - this->labelTime->setVisibility(brls::Visibility::VISIBLE); - } - } - - void setTalker(bool talker) { - auto theme = brls::Application::getTheme(); - if (talker) { - this->talker->setVisibility(brls::Visibility::VISIBLE); - this->mine->setVisibility(brls::Visibility::INVISIBLE); - this->msgBox->setBackgroundColor(theme.getColor("color/grey_2")); - } else { - this->talker->setVisibility(brls::Visibility::INVISIBLE); - this->mine->setVisibility(brls::Visibility::VISIBLE); - this->msgBox->setBackgroundColor(theme.getColor("color/bilibili")); - } - } - -private: - BRLS_BIND(TextBox, textBox, "msg/content"); - BRLS_BIND(brls::Box, msgBox, "msg/content_box"); - BRLS_BIND(brls::Box, picBox, "msg/picture_box"); - BRLS_BIND(brls::Image, msgPic, "msg/picture"); - BRLS_BIND(brls::Image, talker, "avatar/talker"); - BRLS_BIND(brls::Image, mine, "avatar/mine"); - BRLS_BIND(brls::Label, labelTime, "msg/time"); -}; - class DataSourceMsgList : public RecyclingGridDataSource { public: - explicit DataSourceMsgList(const bilibili::InboxMessageListResult& result, uint64_t mid) - : list(std::move(result)), talkerId(mid) { - std::reverse(this->list.begin(), this->list.end()); + explicit DataSourceMsgList(const bilibili::InboxMessageResultWrapper& result, uint64_t mid) + : list(std::move(result.messages)), talkerId(mid) { + std::sort(this->list.begin(), this->list.end(), + [](const bilibili::InboxMessageResult& x, const bilibili::InboxMessageResult& y) { + return x.msg_seqno < y.msg_seqno; + }); + + for (auto& e : result.e_infos) { + this->emotes.insert({e.text, std::make_shared(e)}); + } } RecyclingGridItem* cellForRow(RecyclingGrid* recycler, size_t index) override { //从缓存列表中取出 或者 新生成一个表单项 - auto* item = (ChatMsgCard*)recycler->dequeueReusableCell("Cell"); + auto* item = (InboxMsgCard*)recycler->dequeueReusableCell("Cell"); auto& r = this->list[index]; std::string t = wiliwili::sec2date(r.timestamp); - item->setTalker(r.sender_uid == this->talkerId); - item->setCard(r); + item->setCard(r, this->emotes, this->talkerId); if (this->lastTime == t) { item->setTime(""); } else { @@ -123,11 +60,12 @@ class DataSourceMsgList : public RecyclingGridDataSource { private: bilibili::InboxMessageListResult list; + IEMap emotes; uint64_t talkerId; std::string lastTime; }; -InboxChat::InboxChat(uint64_t talker_id, int session_type) { +InboxChat::InboxChat(const bilibili::InboxChatResult& r) { this->inflateFromXMLRes("xml/fragment/inbox_chat.xml"); brls::Logger::debug("Fragment InboxChat: create"); @@ -136,12 +74,18 @@ InboxChat::InboxChat(uint64_t talker_id, int session_type) { return true; }); - this->setTalkerId(talker_id); + this->setTalkerId(r.talker_id); + + recyclingGrid->registerCell("Cell", [r]() { + auto* card = new InboxMsgCard(); + card->setAvatar(r.account_info.pic_url); + return card; + }); + recyclingGrid->onNextPage([this, r]() { this->requestData(false, r.session_type); }); - recyclingGrid->registerCell("Cell", []() { return new ChatMsgCard(); }); - recyclingGrid->onNextPage([this, session_type]() { this->requestData(false, session_type); }); + labelTalker->setText(r.account_info.name); - this->requestData(true, session_type); + this->requestData(true, r.session_type); } InboxChat::~InboxChat() { brls::Logger::debug("Fragment InboxChat: delete"); } @@ -159,7 +103,7 @@ void InboxChat::onMsgList(const bilibili::InboxMessageResultWrapper& result, boo recyclingGrid->notifyDataChanged(); } } else { - auto dataSource = new DataSourceMsgList(result.messages, this->talkerId); + auto dataSource = new DataSourceMsgList(result, this->talkerId); recyclingGrid->setDataSource(dataSource); } }); diff --git a/wiliwili/source/fragment/inbox_feed.cpp b/wiliwili/source/fragment/inbox_feed.cpp index 1c38be7ea..3491a7301 100644 --- a/wiliwili/source/fragment/inbox_feed.cpp +++ b/wiliwili/source/fragment/inbox_feed.cpp @@ -5,6 +5,7 @@ #include "view/recycling_grid.hpp" #include "view/text_box.hpp" #include "utils/image_helper.hpp" +#include "utils/activity_helper.hpp" using namespace brls::literals; @@ -40,6 +41,16 @@ class FeedCard : public RecyclingGridItem { this->labelMisc->setText(brls::getStr("wiliwili/inbox/reply/" + r.item.type)); } + void prepareForReuse() override { + this->avatar->setImageFromRes("pictures/default_avatar.png"); + this->picture->setImageFromRes("pictures/video-card-bg.png"); + } + + void cacheForReuse() override { + ImageHelper::clear(this->avatar); + ImageHelper::clear(this->picture); + } + private: BRLS_BIND(brls::Image, avatar, "feed/avatar"); BRLS_BIND(brls::Label, labelAuthor, "feed/label/author"); @@ -63,9 +74,16 @@ class DataSourceFeedList : public RecyclingGridDataSource { size_t getItemCount() override { return list.size(); } - void onItemSelected(RecyclingGrid* recycler, size_t index) override {} - - void appendData(const std::vector& data) {} + void onItemSelected(RecyclingGrid* recycler, size_t index) override { + auto& r = this->list[index]; + if (r.item.type == "video" || r.item.type == "reply") { + // 解析BV号 + size_t pos = r.item.uri.find_last_of('/'); + if (pos > 0) { + Intent::openBV(r.item.uri.substr(pos + 1, r.item.source_id)); + } + } + } void clearData() override { this->list.clear(); } diff --git a/wiliwili/source/fragment/inbox_view.cpp b/wiliwili/source/fragment/inbox_view.cpp index 61f9d282d..951dc2af4 100644 --- a/wiliwili/source/fragment/inbox_view.cpp +++ b/wiliwili/source/fragment/inbox_view.cpp @@ -19,20 +19,31 @@ class ChatUserCard : public RecyclingGridItem { void setCard(const bilibili::InboxChatResult& r) { std::string misc; if (r.last_msg.msg_type == 1) { - auto j = nlohmann::json::parse(r.last_msg.content); - misc = j.at("content").get(); + misc = r.last_msg.content.at("content"); } else if (r.last_msg.msg_type == 2) { - misc = "Image"; + misc = "[图片]"; + } else if (r.last_msg.msg_type == 10) { + misc = r.last_msg.content.at("title"); } this->talker->setUserInfo(r.account_info.pic_url + ImageHelper::face_ext, r.account_info.name, misc); if (r.last_msg.timestamp > 0) { this->time->setText(wiliwili::sec2date(r.last_msg.timestamp)); } + if (r.unread_count > 0) { + this->badge->setVisibility(brls::Visibility::VISIBLE); + } else { + this->badge->setVisibility(brls::Visibility::INVISIBLE); + } } + void prepareForReuse() override { this->talker->getAvatar()->setImageFromRes("pictures/default_avatar.png"); } + + void cacheForReuse() override { ImageHelper::clear(this->talker->getAvatar()); } + private: BRLS_BIND(UserInfoView, talker, "chat/talker"); BRLS_BIND(brls::Label, time, "inbox/lastTime"); + BRLS_BIND(brls::Rectangle, badge, "badge"); }; class DataSourceChatList : public RecyclingGridDataSource { @@ -50,7 +61,7 @@ class DataSourceChatList : public RecyclingGridDataSource { void onItemSelected(RecyclingGrid* recycler, size_t index) override { auto& r = this->list[index]; - auto* view = new InboxChat(r.talker_id, r.session_type); + auto* view = new InboxChat(r); recycler->present(view); brls::sync([view]() { brls::Application::giveFocus(view); }); } @@ -83,6 +94,36 @@ InboxView::InboxView() { return true; }); + this->registerAction( + "上一项", brls::ControllerButton::BUTTON_LT, + [this](brls::View* view) -> bool { + tabFrame->focus2LastTab(); + return true; + }, + true); + this->registerAction( + "上一项", brls::ControllerButton::BUTTON_LB, + [this](brls::View* view) -> bool { + tabFrame->focus2LastTab(); + return true; + }, + true); + + this->registerAction( + "下一项", brls::ControllerButton::BUTTON_RT, + [this](brls::View* view) -> bool { + tabFrame->focus2NextTab(); + return true; + }, + true); + this->registerAction( + "下一项", brls::ControllerButton::BUTTON_RB, + [this](brls::View* view) -> bool { + tabFrame->focus2NextTab(); + return true; + }, + true); + recyclingGrid->registerCell("Cell", []() { return new ChatUserCard(); }); recyclingGrid->onNextPage([this]() { this->requestData(false); }); @@ -93,7 +134,7 @@ InboxView::~InboxView() { brls::Logger::debug("Fragment InboxView: delete"); } bool InboxView::isTranslucent() { return true; } -brls::View* InboxView::getDefaultFocus() { return this->inboxFrame->getDefaultFocus(); } +brls::View* InboxView::getDefaultFocus() { return this->tabFrame->getDefaultFocus(); } void InboxView::onChatList(const bilibili::InboxChatListResult& result, bool refresh) { brls::Threading::sync([this, result, refresh]() { diff --git a/wiliwili/source/presenter/inbox_chat.cpp b/wiliwili/source/presenter/inbox_chat.cpp index 80f5177ef..467a354d9 100644 --- a/wiliwili/source/presenter/inbox_chat.cpp +++ b/wiliwili/source/presenter/inbox_chat.cpp @@ -8,12 +8,12 @@ void InboxChatRequest::onError(const std::string& error) {} void InboxChatRequest::requestData(bool refresh) { BILI::new_inbox_sessions( - this->last_time, + refresh ? 0 : this->last_time, [this, refresh](const bilibili::InboxChatResultWrapper& result) { - std::vector uids; + std::vector uids; for (auto& s : result.session_list) { if (s.account_info.name.empty()) { - uids.push_back(s.talker_id); + uids.push_back(std::to_string(s.talker_id)); } } this->last_time = wiliwili::unix_time() * 1000000; @@ -21,21 +21,21 @@ void InboxChatRequest::requestData(bool refresh) { BILI::get_user_cards( uids, [this, result, refresh](const bilibili::UserCardListResult& users) { - for (auto& u : users) { - user_map[u.mid] = u; - } + InboxUserMap user_map; + for (auto& u : users) user_map[u.mid] = u; + auto list = result.session_list; for (auto& s : list) { auto it = user_map.find(s.talker_id); if (it != user_map.end()) { - s.account_info.name = it->second.name; + s.account_info.name = it->second.name; s.account_info.pic_url = it->second.face; } } this->onChatList(list, refresh); }, [this](BILI_ERR) { this->onError(error); }); - } + } }, [this](BILI_ERR) { this->onError(error); }); } \ No newline at end of file diff --git a/wiliwili/source/presenter/inbox_msg.cpp b/wiliwili/source/presenter/inbox_msg.cpp index 56e58f763..7ff10550d 100644 --- a/wiliwili/source/presenter/inbox_msg.cpp +++ b/wiliwili/source/presenter/inbox_msg.cpp @@ -7,7 +7,7 @@ void InboxMsgRequest::onError(const std::string& error) {} void InboxMsgRequest::requestData(bool refresh, int session_type) { BILI::fetch_inbox_msgs( - std::to_string(this->talkerId), 10, session_type, std::to_string(this->msgSeq), + std::to_string(this->talkerId), 20, session_type, std::to_string(this->msgSeq), [this, refresh](const bilibili::InboxMessageResultWrapper& result) { this->onMsgList(result, refresh); this->msgSeq = result.max_seqno; diff --git a/wiliwili/source/view/inbox_msg_card.cpp b/wiliwili/source/view/inbox_msg_card.cpp new file mode 100644 index 000000000..eeac7ec23 --- /dev/null +++ b/wiliwili/source/view/inbox_msg_card.cpp @@ -0,0 +1,120 @@ +#include "view/inbox_msg_card.hpp" +#include "view/text_box.hpp" + +InboxMsgCard::InboxMsgCard() { this->inflateFromXMLRes("xml/views/inbox_msg.xml"); } + +void InboxMsgCard::setCard(const bilibili::InboxMessageResult& r, const IEMap& m, uint64_t talker) { + RichTextData d; + auto theme = brls::Application::getTheme(); + auto textColor = theme.getColor("brls/text"); + + this->textBox->setFontSize(20); + this->msgBox->setBackgroundColor(theme.getColor("color/grey_1")); + + // 设置用户头像 + if (r.msg_type >= 10) { + this->talker->setVisibility(brls::Visibility::GONE); + this->mine->setVisibility(brls::Visibility::GONE); + } else if (talker == r.sender_uid) { + this->talker->setVisibility(brls::Visibility::VISIBLE); + this->mine->setVisibility(brls::Visibility::INVISIBLE); + } else { + this->talker->setVisibility(brls::Visibility::INVISIBLE); + this->mine->setVisibility(brls::Visibility::VISIBLE); + } + + switch (r.msg_type) { + case 1: { // 文本消息 + std::string msg = r.content.at("content"); + size_t start = 0; + for (size_t i = 0; i < msg.length(); i++) { + InboxEmotePtr matched = nullptr; + size_t nextMatch = -1; + for (auto& key : m) { + size_t position = msg.find(key.first, i); + if (position < nextMatch) { + nextMatch = position; + matched = key.second; + break; + } + } + if (matched == nullptr) nextMatch = msg.length(); + if (start < nextMatch) { + // 纯文本 + std::string text = msg.substr(start, nextMatch - start); + d.push_back(std::make_shared(text, textColor)); + } + if (matched == nullptr) break; + + // 处理表情 + std::shared_ptr item; + if (matched->size == 2) { + item = std::make_shared(matched->url, 50, 50); + item->t_margin = 4; + } else { + item = std::make_shared(matched->url, 30, 30); + } + item->v_align = 4; + item->l_margin = 2; + item->r_margin = 2; + d.push_back(item); + + i = nextMatch + matched->text.length() - 1; + start = i + 1; + } + break; + } + case 2: { // 图片消息 + std::string pic = r.content.at("url"); + float width = r.content.at("width"); + float height = r.content.at("height"); + + if (width > 400.f) { + height = height * 400.f / width; + width = 400.f; + } + d.push_back(std::make_shared(pic, width, height)); + this->msgBox->setBackgroundColor(theme.getColor("brls/background")); + break; + } + case 7: { // 分享消息 + std::string title = r.content.at("title"); + std::string thumb = r.content.at("thumb"); + d.push_back(std::make_shared(title, textColor)); + d.push_back(std::make_shared(thumb, 400.f, 100.f)); + break; + } + case 10: { // 系统消息 + std::string title = r.content.at("title"); + std::string text = r.content.at("text"); + d.push_back(std::make_shared(title, theme.getColor("color/bilibili"))); + d.push_back(std::make_shared()); + d.push_back(std::make_shared(text, textColor)); + break; + } + case 18: { // 通知消息 + auto result = nlohmann::json::parse(r.content.at("content").get()); + d.push_back(std::make_shared(result[0]["text"], theme.getColor("font/grey"))); + this->textBox->setHorizontalAlign(brls::HorizontalAlign::CENTER); + this->textBox->setFontSize(16); + this->msgBox->setBackgroundColor(theme.getColor("brls/background")); + break; + } + default:; + } + + this->textBox->setRichText(d); +} + +void InboxMsgCard::setTime(const std::string& time_str) { + if (time_str.empty()) { + this->msgTime->setVisibility(brls::Visibility::GONE); + } else { + this->msgTime->setText(time_str); + this->msgTime->setVisibility(brls::Visibility::VISIBLE); + } +} + +void InboxMsgCard::setAvatar(const std::string& face) { + ImageHelper::with(this->talker)->load(face + ImageHelper::face_ext); +}