From a74e8ec90ee44266caa8ff38948d4ac50c6844ef Mon Sep 17 00:00:00 2001 From: cEvolve05 Date: Fri, 30 Aug 2024 11:34:25 +0800 Subject: [PATCH 1/7] fix: `ColorScheme.unknown` will not change display mode (temp) --- ui/global.slint | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/global.slint b/ui/global.slint index 7de7f659..aec00d27 100644 --- a/ui/global.slint +++ b/ui/global.slint @@ -17,6 +17,9 @@ export global Token { out property color <=> MdStyleToken.color; out property elevation <=> MdStyleToken.elevation; public function set-display-mode(color-scheme: ColorScheme) { + if (color-scheme == ColorScheme.unknown) { + return; + } Palette.color-scheme = color-scheme; } public function switch-display-mode() { From ebe28ce8d9fbfd39bf8ed9ee382ffa2e64426e93 Mon Sep 17 00:00:00 2001 From: cEvolve05 Date: Fri, 30 Aug 2024 11:37:36 +0800 Subject: [PATCH 2/7] feat(message): support multiple message --- src/Controller/Core/MessageManager.cc | 104 +++++++++++++---- src/Controller/Core/MessageManager.h | 47 +++++++- ui/app.slint | 72 +++++++++--- ui/components/toast.slint | 162 +++++++++++++++----------- ui/logic/index.slint | 2 + ui/logic/message_manager.slint | 28 ++++- 6 files changed, 302 insertions(+), 113 deletions(-) diff --git a/src/Controller/Core/MessageManager.cc b/src/Controller/Core/MessageManager.cc index bef5620e..9b5b5073 100644 --- a/src/Controller/Core/MessageManager.cc +++ b/src/Controller/Core/MessageManager.cc @@ -1,10 +1,10 @@ +#include #include #include #include #include -#include +#include #include -#include EVENTO_UI_START @@ -13,43 +13,107 @@ MessageManager::MessageManager(slint::ComponentHandle uiEntry, UiBr , bridge(bridge) { auto& self = *this; + toastList = std::make_shared>(); + self->on_show_message([this](slint::SharedString content, MessageType type) { showMessage(std::string(content), type); }); + + self->on_get_message([this](int id) -> MessageData { return getMessage(id); }); + + self->on_hide_message([this](int id) { hideMessage(id); }); + + self->set_toast_list(toastList); } void MessageManager::showMessage(std::string content, MessageType type, std::chrono::steady_clock::duration timeout) { auto& self = *this; + auto id = nextId++; - if (isMessageShow) { - hideMessage(); - evento::executor()->asyncExecute( - doNothing, - [=, this] { showMessage(content, type, timeout); }, - animationLength, - AsyncExecutor::Once | AsyncExecutor::Delay); - return; - } - + newToast(id, {.content = slint::SharedString(content), .type = type}); UiUtility::StylishLog::newMessageShowed(logOrigin, content); - isMessageShow = true; - self->set_type(type); - self->set_content(std::string_view(content)); - self->set_visible(true); + + // set auto hide evento::executor()->asyncExecute( doNothing, - [this] { hideMessage(); }, + [this, id] { hideMessage(id); }, timeout + animationLength, AsyncExecutor::Once | AsyncExecutor::Delay); } -void MessageManager::hideMessage() { +void MessageManager::hideMessage(int id) { + if (auto index = getIndex(id); index != -1 && !toastList->row_data(getIndex(id))->removed) { + hideToast(id); + } +} + +int MessageManager::getIndex(int id) { + for (int i = 0; i < toastList->row_count(); i++) { + if (toastList->row_data(i)->id == id) { + return i; + } + } + return -1; +} + +void MessageManager::newToast(int id, MessageData data) { + // prepare data then instantiate a toast + messageData.insert({id, data}); + toastList->push_back({id, 0}); + + // make animation available + slint::invoke_from_event_loop([this, id] { showToast(id); }); +} + +void MessageManager::showToast(int id) { + operateToastData(id, increaseElevation); + + // correct existing toast elevation + for (int i = 0; i < toastList->row_count(); i++) { + if (i != getIndex(id)) { + operateToastData(toastList->row_data(i)->id, increaseElevation); + } + } +} + +void MessageManager::hideToast(int id) { + operateToastData(id, markRemoved); + + // wait animation finished + evento::executor()->asyncExecute( + doNothing, + [this, id] { deleteToast(id); }, + animationLength, + AsyncExecutor::Once | AsyncExecutor::Delay); +} + +void MessageManager::deleteToast(int id) { + // correct existing toast elevation bigger than given id + int removedElevation = toastList->row_data(getIndex(id))->elevation; + for (int i = 0; i < toastList->row_count(); i++) { + auto toastData = toastList->row_data(i); + if (toastData->elevation > removedElevation) { + operateToastData(toastData->id, decreaseElevation); + } + } + + // delete instance and data + toastList->erase(getIndex(id)); + messageData.erase(id); +} + +void MessageManager::operateToastData(int id, std::function operation) { + auto index = getIndex(id); + auto data = toastList->row_data(index).value(); + toastList->set_row_data(index, operation(data)); +} + +MessageData MessageManager::getMessage(int id) { auto& self = *this; - isMessageShow = false; - self->set_visible(false); + return messageData.at(id); } EVENTO_UI_END \ No newline at end of file diff --git a/src/Controller/Core/MessageManager.h b/src/Controller/Core/MessageManager.h index 978c4a49..1b3b0b09 100644 --- a/src/Controller/Core/MessageManager.h +++ b/src/Controller/Core/MessageManager.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include EVENTO_UI_START @@ -12,9 +14,6 @@ class MessageManager : private GlobalAgent { UiBridge& bridge; std::string logOrigin = "MessageManager"; - bool isMessageShow = false; - const static inline auto animationLength = std::chrono::milliseconds(200); - public: MessageManager(slint::ComponentHandle uiEntry, UiBridge& bridge); MessageManager(MessageManager&) = delete; @@ -24,9 +23,49 @@ class MessageManager : private GlobalAgent { std::chrono::steady_clock::duration timeout = std::chrono::milliseconds(3000)); // unnecessary to invoke if set correct timeout - void hideMessage(); + void hideMessage(int id); private: + // id, int + int nextId = 0; + + // sync with slint, every line stand for a toast instance + std::shared_ptr> toastList; + // every toast instance will read data from here, mapping id to message data + std::map messageData; + MessageData getMessage(int id); + int getIndex(int id); + + /** + * toast life cycle: + * - called newToast() + * - new instance, invisible (elevation=0) + * - called showToast() + * - visible + * - called hideToast() + * - invisible (removed) (exist in list) + * - called deleteToast() + */ + void newToast(int id, MessageData data); + void showToast(int id); + void hideToast(int id); + void deleteToast(int id); + + void operateToastData(int id, std::function operation); + static inline auto increaseElevation = [](ToastData data) -> ToastData { + data.elevation += 1; + return data; + }; + static inline auto decreaseElevation = [](ToastData data) -> ToastData { + data.elevation -= 1; + return data; + }; + static inline auto markRemoved = [](ToastData data) -> ToastData { + data.removed = true; + return data; + }; + + const static inline auto animationLength = std::chrono::milliseconds(200); static auto inline doNothing = []() -> Task { co_return; }; }; diff --git a/ui/app.slint b/ui/app.slint index 49556e3f..06a79124 100644 --- a/ui/app.slint +++ b/ui/app.slint @@ -13,7 +13,9 @@ import { AccountManager, MessageManager, ViewName, - MessageType + MessageType, + MessageData, + ToastData } from "./logic/index.slint"; import { @@ -44,11 +46,10 @@ export { ViewManagerBridge, AccountManagerBridge, MessageManagerBridge, - ViewManager, - AccountManager, - MessageManager, ViewName, MessageType, + MessageData, + ToastData, LoginOverlayBridge, MenuOverlayBridge, DiscoveryPageBridge, @@ -250,6 +251,23 @@ export component App inherits Window { ViewManager.navigate-to(ViewName.MenuOverlay); } } + + CircleButton { + image: Token.image.icon.error; + property idx: 0; + clicked => { + idx += 1; + MessageManager.show-message(idx + " " + animation-tick() / 1ms, MessageType.Info); + } + } + + CircleButton { + image: Token.image.icon.locate; + property idx: 0; + clicked => { + debug(MessageManager.toast-list[0]); + } + } } PageRegion { } @@ -260,29 +278,51 @@ export component App inherits Window { width: 100%; } - Toast { - x: root.width - self.width - 16px; - y: root.height + 16px; + for item in MessageManager.toast-list: Toast { + toast-data: item; + x: root.width - toast-padding - self.width; + y: root.height + toast-padding; width: self.min-width > (parent.width * (1 - 0.618) / 2) ? self.preferred-width : parent.width * (1 - 0.618) / 2; + animate y { + duration: 200ms; + easing: ease-out-quart; + } states [ - visible when MessageManager.visible: { - y: root.height - self.height - 16px; + removed when self.removed: { + y: root.get-toast-y(self.elevation); + x: root.width - toast-padding - self.width / 2; + opacity: 0; in { - animate y { + animate opacity { duration: 200ms; - easing: ease-out-quart; + easing: linear; } - } - out { - animate y { + animate x { duration: 200ms; easing: ease-in-quart; } } } - invisible when !MessageManager.visible: { - y: root.height + 16px; + // self.elevation > 0 + visible when self.elevation > 0: { + y: root.get-toast-y(self.elevation); + opacity: 1; + } + invisible when self.elevation == 0: { + y: root.height + toast-padding; + opacity: 0; } ] } + private property toast-padding: 16px; + private property toast-vertical-spacing: 8px; + private property toast-height: 48px; + private property toast-origin: { x: root.width - toast-padding, y: root.height - toast-padding }; + function get-toast-y(elevation: int) -> length { + if (elevation > 0) { + return toast-origin.y - elevation * toast-height - (elevation - 1) * toast-vertical-spacing; + } else { + return root.height + toast-padding; + } + } } diff --git a/ui/components/toast.slint b/ui/components/toast.slint index ab0d5f7d..36553669 100644 --- a/ui/components/toast.slint +++ b/ui/components/toast.slint @@ -1,81 +1,109 @@ -import { MessageManager, MessageType } from "../logic/message_manager.slint"; -import { Token } from "../global.slint"; -import { Button } from "../modules/surrealism-ui/src/button/button.slint"; -import { MessageManagerBridge } from "../logic/index.slint"; +import { MessageManager, MessageManagerBridge, MessageType, MessageData, ToastData } from "../logic/message_manager.slint"; +import { Token, MdFontData } from "../global.slint"; +import { Button } from "./button.slint"; +import { Empty } from "view_base.slint"; -export component Toast inherits Rectangle { - property have-icon: false; - property icon: Token.image.icon.info; - property surface: Token.color.surface-variant; - property on-surface: Token.color.on-surface-variant; - clip: true; - background: surface; - border-radius: 8px; - height: 48px; - content := HorizontalLayout { - padding: 16px; - spacing: 12px; - alignment: start; - if have-icon: Rectangle { - width: 24px; - Image { - height: 24px; - width: 24px; - source: icon; - colorize: on-surface; +export component Toast { + // option + in property toast-data; + // out + out property elevation: toast-data.elevation; + out property removed: toast-data.removed; + // implement + min-height: 48px; + min-width: _body.min-width; + preferred-height: 48px; + preferred-width: _body.preferred-width; + private property surface: Token.color.surface-variant; + private property on-surface: Token.color.on-surface-variant; + private property font: Token.font.body.large; + private property have-icon: false; + private property icon; + private property message-data: MessageManager.get-message(toast-data.id); + // private property message-data: { content: "123", type: MessageType.Info }; + _body := Rectangle { + x: 0; + y: 0; + clip: true; + height <=> root.height; + width <=> root.width; + background: surface; + border-radius: 8px; + _area := TouchArea { + clicked => { + MessageManager.hide-message(toast-data.id); } } - text := Text { - max-width: self.preferred-width; - vertical-alignment: center; - horizontal-alignment: left; - text: MessageManager.content; - color: on-surface; - font-size: Token.font.body.large.size; + + _content := HorizontalLayout { + padding: 16px; + spacing: 12px; + alignment: start; + if have-icon: _icon := Empty { + width: 24px; + Image { + height: 24px; + width: 24px; + source: icon; + colorize: on-surface; + } + } + _text := Text { + vertical-alignment: center; + horizontal-alignment: left; + text: message-data.content; + color: on-surface; + font-size: font.size; + font-weight: font.weight; + } } } - states [ - error when MessageManager.type == MessageType.Error: { - have-icon: true; - icon: Token.image.icon.error; - surface: Token.color.error; - on-surface: Token.color.on-error; - } - warning when MessageManager.type == MessageType.Warning: { - have-icon: true; - icon: Token.image.icon.error; - } - info when MessageManager.type == MessageType.Info: { - have-icon: false; - } - ] + // TODO: support more type + // states [ + // error when MessageManager.type == MessageType.Error: { + // have-icon: true;// icon: Token.image.icon.error; + // surface: Token.color.error; + // on-surface: Token.color.on-error; + // } + // warning when MessageManager.type == MessageType.Warning: { + // have-icon: true;// icon: Token.image.icon.error; + // } + // info when MessageManager.type == MessageType.Info: { + // have-icon: false; + // } + // ] } component Test { - HorizontalLayout { - y: - self.height; - Button { - text: "Info"; - clicked => { - MessageManagerBridge.type = MessageType.Info; - } - } + // HorizontalLayout { + // y: - self.height; + // Button { + // content: "Info"; + // clicked => { + // MessageManagerBridge.type = MessageType.Info; + // } + // } - Button { - text: "Warning"; - clicked => { - MessageManagerBridge.type = MessageType.Warning; - } - } + // Button { + // content: "Warning"; + // clicked => { + // MessageManagerBridge.type = MessageType.Warning; + // } + // } - Button { - text: "Error"; - clicked => { - MessageManagerBridge.type = MessageType.Error; - } + // Button { + // content: "Error"; + // clicked => { + // MessageManagerBridge.type = MessageType.Error; + // } + // } + // } + + Toast { + // width: 20px; + init => { + debug(self.width) } } - - Toast { } } diff --git a/ui/logic/index.slint b/ui/logic/index.slint index ba8035f1..1ed3cbf6 100644 --- a/ui/logic/index.slint +++ b/ui/logic/index.slint @@ -13,4 +13,6 @@ export { MessageManager, MessageManagerBridge, MessageType, + MessageData, + ToastData } from "./message_manager.slint"; diff --git a/ui/logic/message_manager.slint b/ui/logic/message_manager.slint index 6f53b6ff..9288dc75 100644 --- a/ui/logic/message_manager.slint +++ b/ui/logic/message_manager.slint @@ -4,18 +4,34 @@ export enum MessageType{ Error } +export struct MessageData { + content: string, + type: MessageType, +} + +export struct ToastData { + id: int, + elevation: int, + removed: bool, +} + export global MessageManagerBridge { - in-out property content: "Test content"; - in-out property visible; - in-out property type; + in-out property <[ToastData]> toast-list; + in-out property refresh; callback show-message(string, MessageType); + pure callback get-message(int) -> MessageData; + callback hide-message(int); } export global MessageManager { - out property content: MessageManagerBridge.content; - out property visible: MessageManagerBridge.visible; - out property type: MessageManagerBridge.type; + out property <[ToastData]> toast-list: MessageManagerBridge.toast-list; public function show-message(content: string, type: MessageType) { MessageManagerBridge.show-message(content, type); } + pure public function get-message(id: int) -> MessageData { + return MessageManagerBridge.get-message(id); + } + public function hide-message(id: int) { + MessageManagerBridge.hide-message(id); + } } From 279797628240a29749728838b41017b2896d34b4 Mon Sep 17 00:00:00 2001 From: cEvolve05 Date: Fri, 30 Aug 2024 14:27:40 +0800 Subject: [PATCH 3/7] feat(toast): add message type support --- ui/app.slint | 30 +++++------------------------- ui/components/toast.slint | 28 +++++++++++++++------------- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/ui/app.slint b/ui/app.slint index 06a79124..4483a215 100644 --- a/ui/app.slint +++ b/ui/app.slint @@ -251,23 +251,6 @@ export component App inherits Window { ViewManager.navigate-to(ViewName.MenuOverlay); } } - - CircleButton { - image: Token.image.icon.error; - property idx: 0; - clicked => { - idx += 1; - MessageManager.show-message(idx + " " + animation-tick() / 1ms, MessageType.Info); - } - } - - CircleButton { - image: Token.image.icon.locate; - property idx: 0; - clicked => { - debug(MessageManager.toast-list[0]); - } - } } PageRegion { } @@ -278,10 +261,14 @@ export component App inherits Window { width: 100%; } + private property toast-padding: 16px; + private property toast-vertical-spacing: 8px; + private property toast-height: 48px; + private property toast-origin: { x: root.width - toast-padding, y: root.height - toast-padding }; for item in MessageManager.toast-list: Toast { toast-data: item; x: root.width - toast-padding - self.width; - y: root.height + toast-padding; + y: get-toast-y(self.elevation); width: self.min-width > (parent.width * (1 - 0.618) / 2) ? self.preferred-width : parent.width * (1 - 0.618) / 2; animate y { duration: 200ms; @@ -289,7 +276,6 @@ export component App inherits Window { } states [ removed when self.removed: { - y: root.get-toast-y(self.elevation); x: root.width - toast-padding - self.width / 2; opacity: 0; in { @@ -305,19 +291,13 @@ export component App inherits Window { } // self.elevation > 0 visible when self.elevation > 0: { - y: root.get-toast-y(self.elevation); opacity: 1; } invisible when self.elevation == 0: { - y: root.height + toast-padding; opacity: 0; } ] } - private property toast-padding: 16px; - private property toast-vertical-spacing: 8px; - private property toast-height: 48px; - private property toast-origin: { x: root.width - toast-padding, y: root.height - toast-padding }; function get-toast-y(elevation: int) -> length { if (elevation > 0) { return toast-origin.y - elevation * toast-height - (elevation - 1) * toast-vertical-spacing; diff --git a/ui/components/toast.slint b/ui/components/toast.slint index 36553669..f7c2c9e7 100644 --- a/ui/components/toast.slint +++ b/ui/components/toast.slint @@ -60,19 +60,21 @@ export component Toast { } // TODO: support more type - // states [ - // error when MessageManager.type == MessageType.Error: { - // have-icon: true;// icon: Token.image.icon.error; - // surface: Token.color.error; - // on-surface: Token.color.on-error; - // } - // warning when MessageManager.type == MessageType.Warning: { - // have-icon: true;// icon: Token.image.icon.error; - // } - // info when MessageManager.type == MessageType.Info: { - // have-icon: false; - // } - // ] + states [ + error when message-data.type == MessageType.Error: { + have-icon: true; + icon: Token.image.icon.error; + surface: Token.color.error; + on-surface: Token.color.on-error; + } + warning when message-data.type == MessageType.Warning: { + have-icon: true; + icon: Token.image.icon.error; + } + info when message-data.type == MessageType.Info: { + have-icon: false; + } + ] } component Test { From 9bc44c06e9496ed3a9736011ad830e3a9787d167 Mon Sep 17 00:00:00 2001 From: cEvolve05 Date: Fri, 30 Aug 2024 14:29:05 +0800 Subject: [PATCH 4/7] refactor: remove redundant code --- src/Controller/Core/ViewManager.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Controller/Core/ViewManager.cc b/src/Controller/Core/ViewManager.cc index f1aea667..882b9b3e 100644 --- a/src/Controller/Core/ViewManager.cc +++ b/src/Controller/Core/ViewManager.cc @@ -13,10 +13,10 @@ ViewManager::ViewManager(slint::ComponentHandle uiEntry, UiBridge& , bridge(bridge) { auto& self = *this; - self->on_navigate_to([this](ViewName newView) { return navigateTo(newView); }); - self->on_clean_navigate_to([this](ViewName newView) { return cleanNavigateTo(newView); }); - self->on_replace_navigate_to([this](ViewName newView) { return replaceNavigateTo(newView); }); - self->on_prior_view([this]() { return priorView(); }); + self->on_navigate_to([this](ViewName newView) { navigateTo(newView); }); + self->on_clean_navigate_to([this](ViewName newView) { cleanNavigateTo(newView); }); + self->on_replace_navigate_to([this](ViewName newView) { replaceNavigateTo(newView); }); + self->on_prior_view([this]() { priorView(); }); self->on_is_show([&self](ViewName target) { // used to trigger re-calculate @@ -33,7 +33,7 @@ void ViewManager::initStack(ViewName newView, std::any data) { static bool scheduleSync = false; if (!scheduleSync) { scheduleSync = true; - slint::invoke_from_event_loop([this] { return syncViewVisibility(); }); + slint::invoke_from_event_loop([this] { syncViewVisibility(); }); } } From ab3436aadc9cd2537f94c3314aecf312ca77ed91 Mon Sep 17 00:00:00 2001 From: cEvolve05 Date: Fri, 30 Aug 2024 17:35:03 +0800 Subject: [PATCH 5/7] feat: improve log --- src/Controller/Core/MessageManager.cc | 10 +++++++++- src/Controller/Core/UiUtility.cc | 15 --------------- src/Controller/Core/UiUtility.h | 15 ++++++++++++--- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/Controller/Core/MessageManager.cc b/src/Controller/Core/MessageManager.cc index 9b5b5073..ae7d6ca5 100644 --- a/src/Controller/Core/MessageManager.cc +++ b/src/Controller/Core/MessageManager.cc @@ -32,8 +32,9 @@ void MessageManager::showMessage(std::string content, auto& self = *this; auto id = nextId++; + UiUtility::StylishLog::general(logOrigin, + std::format("new message [{}] content = \"{}\"", id, content)); newToast(id, {.content = slint::SharedString(content), .type = type}); - UiUtility::StylishLog::newMessageShowed(logOrigin, content); // set auto hide evento::executor()->asyncExecute( @@ -46,6 +47,9 @@ void MessageManager::showMessage(std::string content, void MessageManager::hideMessage(int id) { if (auto index = getIndex(id); index != -1 && !toastList->row_data(getIndex(id))->removed) { hideToast(id); + } else { + UiUtility::StylishLog::messageOperation( + logOrigin, id, "scheduled hide cancelled: already hidden or deleted"); } } @@ -62,6 +66,7 @@ void MessageManager::newToast(int id, MessageData data) { // prepare data then instantiate a toast messageData.insert({id, data}); toastList->push_back({id, 0}); + UiUtility::StylishLog::messageOperation(logOrigin, id, "instantiate toast, data added"); // make animation available slint::invoke_from_event_loop([this, id] { showToast(id); }); @@ -69,6 +74,7 @@ void MessageManager::newToast(int id, MessageData data) { void MessageManager::showToast(int id) { operateToastData(id, increaseElevation); + UiUtility::StylishLog::messageOperation(logOrigin, id, "show"); // correct existing toast elevation for (int i = 0; i < toastList->row_count(); i++) { @@ -80,6 +86,7 @@ void MessageManager::showToast(int id) { void MessageManager::hideToast(int id) { operateToastData(id, markRemoved); + UiUtility::StylishLog::messageOperation(logOrigin, id, "hide"); // wait animation finished evento::executor()->asyncExecute( @@ -102,6 +109,7 @@ void MessageManager::deleteToast(int id) { // delete instance and data toastList->erase(getIndex(id)); messageData.erase(id); + UiUtility::StylishLog::general(logOrigin, std::format("delete message [{}]", id)); } void MessageManager::operateToastData(int id, std::function operation) { diff --git a/src/Controller/Core/UiUtility.cc b/src/Controller/Core/UiUtility.cc index aa7f1784..aabbabbb 100644 --- a/src/Controller/Core/UiUtility.cc +++ b/src/Controller/Core/UiUtility.cc @@ -18,19 +18,4 @@ bool UiUtility::isTransparent(ViewName target) { return overlayList.find(target) != overlayList.end(); } -void UiUtility::StylishLog::viewActionTriggered(std::string origin, - std::string actionName, - std::string viewName) { - spdlog::debug("{}: {}: triggered {}", origin, viewName, actionName); -} - -void UiUtility::StylishLog::viewVisibilityChanged(std::string origin, - std::string actionName, - std::string viewName) { - spdlog::debug("{}: {} visibility changed: {}", origin, viewName, actionName); -} -void UiUtility::StylishLog::newMessageShowed(std::string origin, std::string content) { - spdlog::debug("{}: new message: {}", origin, content); -} - EVENTO_UI_END \ No newline at end of file diff --git a/src/Controller/Core/UiUtility.h b/src/Controller/Core/UiUtility.h index 259d5016..e20509a2 100644 --- a/src/Controller/Core/UiUtility.h +++ b/src/Controller/Core/UiUtility.h @@ -12,13 +12,22 @@ class UiUtility { class StylishLog { public: + static void general(std::string origin, std::string content) { + spdlog::debug("{}: {}", origin, content); + } static void viewActionTriggered(std::string origin, std::string actionName, - std::string viewName = std::string("All-View")); + std::string viewName = std::string("All-View")) { + spdlog::debug("{}: {}: triggered {}", origin, viewName, actionName); + } static void viewVisibilityChanged(std::string origin, std::string actionName, - std::string viewName); - static void newMessageShowed(std::string origin, std::string content); + std::string viewName) { + spdlog::debug("{}: {} visibility changed: {}", origin, viewName, actionName); + } + static void messageOperation(std::string origin, int id, std::string content) { + spdlog::debug("{}: message [{}]: {}", origin, id, content); + } }; private: From 3b89319edd0909bb3b12a5a4d5ee9251620780e1 Mon Sep 17 00:00:00 2001 From: cEvolve05 Date: Sat, 31 Aug 2024 20:58:49 +0800 Subject: [PATCH 6/7] feat(message): add success type --- ui/assets/image/icon/arrow-left.svg | 6 +-- ui/assets/image/icon/check-circle.svg | 4 ++ ui/assets/image/image_token.slint | 2 + ui/components/toast.slint | 71 ++++++++++----------------- ui/logic/message_manager.slint | 7 +-- ui/views/overlay/login.slint | 2 +- ui/views/overlay/menu.slint | 2 +- ui/views/page/setting.slint | 5 +- 8 files changed, 41 insertions(+), 58 deletions(-) create mode 100644 ui/assets/image/icon/check-circle.svg diff --git a/ui/assets/image/icon/arrow-left.svg b/ui/assets/image/icon/arrow-left.svg index bedbb28b..1401ed18 100644 --- a/ui/assets/image/icon/arrow-left.svg +++ b/ui/assets/image/icon/arrow-left.svg @@ -1,4 +1,4 @@ - - arrow-left - + + \ No newline at end of file diff --git a/ui/assets/image/icon/check-circle.svg b/ui/assets/image/icon/check-circle.svg new file mode 100644 index 00000000..2f12ec0d --- /dev/null +++ b/ui/assets/image/icon/check-circle.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/ui/assets/image/image_token.slint b/ui/assets/image/image_token.slint index 1cf0a25c..b0136ca3 100644 --- a/ui/assets/image/image_token.slint +++ b/ui/assets/image/image_token.slint @@ -31,6 +31,7 @@ struct EventoIconCollection { tree-list: image, account-box: image, pentagon: image, + check-circle: image, } struct EventoDisplayCollection { @@ -88,6 +89,7 @@ export global EventoImageToken { tree-list: @image-url("./icon/tree-list.svg"), account-box: @image-url("./icon/account-box-outline.svg"), pentagon: @image-url("./icon/pentagon.svg"), + check-circle: @image-url("./icon/check-circle.svg"), }; // display used as images bigger than icon // most display image won't change according to darkmode switch diff --git a/ui/components/toast.slint b/ui/components/toast.slint index f7c2c9e7..90baeeba 100644 --- a/ui/components/toast.slint +++ b/ui/components/toast.slint @@ -36,11 +36,13 @@ export component Toast { } _content := HorizontalLayout { - padding: 16px; - spacing: 12px; + padding-left: 16px; + padding-right: 16px; + spacing: 8px; alignment: start; if have-icon: _icon := Empty { width: 24px; + height: 100%; Image { height: 24px; width: 24px; @@ -48,64 +50,41 @@ export component Toast { colorize: on-surface; } } - _text := Text { - vertical-alignment: center; - horizontal-alignment: left; - text: message-data.content; - color: on-surface; - font-size: font.size; - font-weight: font.weight; + Empty { + height: 100%; + _text := Text { + text: message-data.content; + color: on-surface; + font-size: font.size; + font-weight: font.weight; + } } + + states [ + have-icon when have-icon: { + padding-left: 12px; + } + ] } } - // TODO: support more type states [ - error when message-data.type == MessageType.Error: { + error when message-data.type == MessageType.error: { have-icon: true; icon: Token.image.icon.error; surface: Token.color.error; on-surface: Token.color.on-error; } - warning when message-data.type == MessageType.Warning: { + warning when message-data.type == MessageType.warning: { have-icon: true; icon: Token.image.icon.error; } - info when message-data.type == MessageType.Info: { + success when message-data.type == MessageType.success: { + have-icon: true; + icon: Token.image.icon.check-circle; + } + info when message-data.type == MessageType.info: { have-icon: false; } ] } - -component Test { - // HorizontalLayout { - // y: - self.height; - // Button { - // content: "Info"; - // clicked => { - // MessageManagerBridge.type = MessageType.Info; - // } - // } - - // Button { - // content: "Warning"; - // clicked => { - // MessageManagerBridge.type = MessageType.Warning; - // } - // } - - // Button { - // content: "Error"; - // clicked => { - // MessageManagerBridge.type = MessageType.Error; - // } - // } - // } - - Toast { - // width: 20px; - init => { - debug(self.width) - } - } -} diff --git a/ui/logic/message_manager.slint b/ui/logic/message_manager.slint index 9288dc75..cdb6fb45 100644 --- a/ui/logic/message_manager.slint +++ b/ui/logic/message_manager.slint @@ -1,7 +1,8 @@ export enum MessageType{ - Info, - Warning, - Error + info, + success, + warning, + error } export struct MessageData { diff --git a/ui/views/overlay/login.slint b/ui/views/overlay/login.slint index 1dd10581..5fd9366e 100644 --- a/ui/views/overlay/login.slint +++ b/ui/views/overlay/login.slint @@ -8,7 +8,7 @@ export global LoginOverlayBridge { in-out property version:"v0.0.0-00000000"; callback link-login(); public function guest-login() { - MessageManager.show-message("访客登录尚未完成", MessageType.Info); + MessageManager.show-message("访客登录尚未完成", MessageType.info); // ViewManager.prior-view(); } } diff --git a/ui/views/overlay/menu.slint b/ui/views/overlay/menu.slint index 7d294b96..708d6ad1 100644 --- a/ui/views/overlay/menu.slint +++ b/ui/views/overlay/menu.slint @@ -196,7 +196,7 @@ export component MenuOverlay inherits Overlay { label: "纪念卡"; clicked => { // NOTE: Unsupport - MessageManager.show-message("功能还在开发中,咕咕咕 😣", MessageType.Info); + MessageManager.show-message("功能还在开发中,咕咕咕 😣", MessageType.info); } } if AccountManager.is-login:Divider { } diff --git a/ui/views/page/setting.slint b/ui/views/page/setting.slint index 5ca4a079..b84ce900 100644 --- a/ui/views/page/setting.slint +++ b/ui/views/page/setting.slint @@ -9,7 +9,6 @@ export global SettingPageBridge { in-out property notice-begin: false; in-out property notice-end: false; in-out property minimal-to-tray: false; - public function change-theme() { if (theme-index == 1) { Token.set-display-mode(ColorScheme.light); @@ -19,7 +18,6 @@ export global SettingPageBridge { Token.set-display-mode(ColorScheme.unknown); } } - callback language-changed(); callback theme-changed(); callback notice-begin-changed(); @@ -65,7 +63,6 @@ export component SettingPage inherits Page { alignment: LayoutAlignment.start; padding: 50px; spacing: 15px; - Text { text: "设置"; font-size: Token.font.display.medium.size; @@ -129,7 +126,7 @@ export component SettingPage inherits Page { checked <=> SettingPageBridge.minimal-to-tray; toggled => { SettingPageBridge.minimal-to-tray-changed(); - MessageManager.show-message("下次启动应用时生效", MessageType.Info); + MessageManager.show-message("下次启动应用时生效", MessageType.info); } } } From 0d4a602cf9761b7676421a9c9d22f5c7abad5aad Mon Sep 17 00:00:00 2001 From: cEvolve05 Date: Sun, 1 Sep 2024 11:01:03 +0800 Subject: [PATCH 7/7] feat(message-manager): return id when show message --- src/Controller/Core/MessageManager.cc | 10 ++++++---- src/Controller/Core/MessageManager.h | 7 ++++--- ui/logic/message_manager.slint | 6 +++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Controller/Core/MessageManager.cc b/src/Controller/Core/MessageManager.cc index ae7d6ca5..52ce624b 100644 --- a/src/Controller/Core/MessageManager.cc +++ b/src/Controller/Core/MessageManager.cc @@ -16,7 +16,7 @@ MessageManager::MessageManager(slint::ComponentHandle uiEntry, UiBr toastList = std::make_shared>(); self->on_show_message([this](slint::SharedString content, MessageType type) { - showMessage(std::string(content), type); + return showMessage(std::string(content), type); }); self->on_get_message([this](int id) -> MessageData { return getMessage(id); }); @@ -26,9 +26,9 @@ MessageManager::MessageManager(slint::ComponentHandle uiEntry, UiBr self->set_toast_list(toastList); } -void MessageManager::showMessage(std::string content, - MessageType type, - std::chrono::steady_clock::duration timeout) { +int MessageManager::showMessage(std::string content, + MessageType type, + std::chrono::steady_clock::duration timeout) { auto& self = *this; auto id = nextId++; @@ -42,6 +42,8 @@ void MessageManager::showMessage(std::string content, [this, id] { hideMessage(id); }, timeout + animationLength, AsyncExecutor::Once | AsyncExecutor::Delay); + + return id; } void MessageManager::hideMessage(int id) { diff --git a/src/Controller/Core/MessageManager.h b/src/Controller/Core/MessageManager.h index 1b3b0b09..830ca1e0 100644 --- a/src/Controller/Core/MessageManager.h +++ b/src/Controller/Core/MessageManager.h @@ -18,9 +18,10 @@ class MessageManager : private GlobalAgent { MessageManager(slint::ComponentHandle uiEntry, UiBridge& bridge); MessageManager(MessageManager&) = delete; - void showMessage(std::string content, - MessageType type = MessageType::Info, - std::chrono::steady_clock::duration timeout = std::chrono::milliseconds(3000)); + // @return message id + int showMessage(std::string content, + MessageType type = MessageType::Info, + std::chrono::steady_clock::duration timeout = std::chrono::milliseconds(3000)); // unnecessary to invoke if set correct timeout void hideMessage(int id); diff --git a/ui/logic/message_manager.slint b/ui/logic/message_manager.slint index cdb6fb45..36764272 100644 --- a/ui/logic/message_manager.slint +++ b/ui/logic/message_manager.slint @@ -19,15 +19,15 @@ export struct ToastData { export global MessageManagerBridge { in-out property <[ToastData]> toast-list; in-out property refresh; - callback show-message(string, MessageType); + callback show-message(string, MessageType) -> int; pure callback get-message(int) -> MessageData; callback hide-message(int); } export global MessageManager { out property <[ToastData]> toast-list: MessageManagerBridge.toast-list; - public function show-message(content: string, type: MessageType) { - MessageManagerBridge.show-message(content, type); + public function show-message(content: string, type: MessageType) -> int { + return MessageManagerBridge.show-message(content, type); } pure public function get-message(id: int) -> MessageData { return MessageManagerBridge.get-message(id);