Skip to content

Commit

Permalink
[*] improve ui
Browse files Browse the repository at this point in the history
  • Loading branch information
heng30 committed May 20, 2024
1 parent 47f7ffd commit 4b4c48e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 25 deletions.
17 changes: 17 additions & 0 deletions src/logic/rss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,21 @@ pub fn init(ui: &AppWindow) {
init_rss(&ui_handle.unwrap());
});

let ui_handle = ui.as_weak();
ui.global::<Logic>().on_current_rsslist_index(move |uuid| {
let ui = ui_handle.unwrap();

for (index, rss) in ui.global::<Store>().get_rss_lists().iter().enumerate() {
if rss.uuid != uuid {
continue;
}

return index as i32;
}

return -1;
});

let ui_handle = ui.as_weak();
ui.global::<Logic>().on_new_rss(move |config| {
let ui = ui_handle.unwrap();
Expand Down Expand Up @@ -785,6 +800,8 @@ async fn sync_rss(ui: Weak<AppWindow>, items: Vec<SyncItem>) -> Vec<ErrorMsg> {
let _ = slint::invoke_from_event_loop(move || {
let ui = ui.unwrap();
super::entry::update_new_entrys(&ui, suuid.as_str(), entrys);
ui.global::<Store>().invoke_refresh_current_tab();

if suuid.as_str() == ui.global::<Store>().get_current_rss_uuid().as_str() {
notify_ui_update_unread_counts(&ui);
}
Expand Down
1 change: 1 addition & 0 deletions ui/logic.slint
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export global Logic {
// when it should be called. The app stay in background for a long time, and killed by the system. After that, restart the app will not load the rss from the database. so we should call it manually.
callback load-all-rss();

callback current-rsslist-index(string) -> int;
callback new-rss(RssConfig);
callback update-rss(string, RssConfig);
callback remove-rss(string); // suuid
Expand Down
32 changes: 22 additions & 10 deletions ui/panel/bodyer/favorite.slint
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ export component Entry inherits Rectangle {
alignment: space-between;

title-txt := Link {
wrap: no-wrap;
overflow: elide;

clicked => {
Util.open-url(root.url);
}
Expand All @@ -61,7 +58,7 @@ export component Entry inherits Rectangle {
font-size: Theme.default-font-size - 1px;
color: Theme.regular-text-color;
text: root.summary;
overflow: elide;
wrap: word-wrap;
}

HorizontalLayout {
Expand Down Expand Up @@ -90,16 +87,29 @@ export component EntryList inherits Rectangle {
lv.viewport-y = 0;
}

lv := ListView {
lv := Flickable {
x: 0px;
width: root.width + Theme.scroll-width;
width: root.width;

private property <length> offset-y: 0;

for item[index] in Store.rss-favorite-entrys: rect := Rectangle {
private property <length> max-move-pixels-up-bound: self.width * 0.04;
private property <length> max-move-pixels-low-bound: self.width * 0.02;
private property <bool> is-show-opt: false;
private property <bool> is-hide-opt: true;

init => {
if (index == 0) {
offset-y = 0;
}

self.y = offset-y;
offset-y = offset-y + entry-vbox.preferred-height;
self.height = entry-vbox.preferred-height;
lv.viewport-height = offset-y;
}

public function show-opt(){
rect.x = -opt.width - Theme.padding;
rect.is-show-opt = true;
Expand All @@ -119,8 +129,8 @@ export component EntryList inherits Rectangle {

TouchArea {
moved => {
if (lv.enabled && (self.pressed-x - self.mouse-x > parent.max-move-pixels-low-bound || self.mouse-x - self.pressed-x > parent.max-move-pixels-low-bound)) {
lv.enabled = false;
if (lv.interactive && (self.pressed-x - self.mouse-x > parent.max-move-pixels-low-bound || self.mouse-x - self.pressed-x > parent.max-move-pixels-low-bound)) {
lv.interactive = false;
}
if (!rect.is-show-opt) {
if (self.pressed-x - self.mouse-x > parent.max-move-pixels-up-bound) {
Expand All @@ -136,7 +146,7 @@ export component EntryList inherits Rectangle {

pointer-event(evt) => {
if (evt.kind == PointerEventKind.up) {
lv.enabled = true;
lv.interactive = true;
}
}
}
Expand All @@ -158,8 +168,9 @@ export component EntryList inherits Rectangle {

opt := VerticalLayout {
x: entry-vbox.width + Theme.padding;
y: 0;
width: 50px;
height: entry-vbox.height - entry-vbox.padding * 2 - Theme.padding;
height: entry-vbox.height;
alignment: center;

Rectangle {
Expand All @@ -174,6 +185,7 @@ export component EntryList inherits Rectangle {
clicked => {
rect.hide-opt();
Logic.remove-favorite-entry(item.uuid);
Store.refresh-current-tab();
}
}
}
Expand Down
55 changes: 44 additions & 11 deletions ui/panel/bodyer/rss.slint
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ListView } from "std-widgets.slint";
import { ListView, ScrollView } from "std-widgets.slint";
import { Theme, Icons } from "../../theme.slint";
import { Store } from "../../store.slint";
import { Logic } from "../../logic.slint";
Expand Down Expand Up @@ -216,11 +216,9 @@ export component Entry inherits Rectangle {
VerticalLayout {
padding: Theme.padding * 2;
spacing: Theme.spacing * 2;
alignment: space-between;
alignment: start;

title-txt := Link {
wrap: no-wrap;
overflow: elide;
is-read: root.is-read;

clicked => {
Expand All @@ -239,7 +237,7 @@ export component Entry inherits Rectangle {
font-size: Theme.default-font-size - 1px;
color: root.is-read ? Theme.have-read-text-color : Theme.regular-text-color;
text: root.summary;
overflow: elide;
wrap: word-wrap;
}

HorizontalLayout {
Expand All @@ -262,22 +260,43 @@ export component Entry inherits Rectangle {
}

export component EntryList inherits Rectangle {
private property <int> current-list-index: -1;

clip: true;

public function scroll-to-top() {
lv.viewport-y = 0;
}

lv := ListView {
lv := Flickable {
x: 0px;
width: root.width + Theme.scroll-width;
viewport-width: root.width;

private property <length> offset-y: 0;

for item[index] in Store.rss-entrys: rect := Rectangle {
private property <length> max-move-pixels-up-bound: self.width * 0.04;
private property <length> max-move-pixels-low-bound: self.width * 0.02;
private property <bool> is-show-opt: false;
private property <bool> is-hide-opt: true;

init => {
if (index == 0) {
offset-y = 0;
lv.viewport-y = 0;
} else if (index == Store.rss-entrys.length - 1) {
current-list-index = Logic.current-rsslist-index(Store.current-rss-uuid);
if (current-list-index >= 0 && current-list-index < Store.rss-lists.length) {
// viewport-y from 0 to -infinity
lv.viewport-y = min(0px, max(lv.height - offset-y, Store.rss-lists[current-list-index].current-viewport-y));
}
}
self.y = offset-y;
offset-y = offset-y + entry-vbox.preferred-height;
self.height = entry-vbox.preferred-height;
lv.viewport-height = offset-y + Theme.padding;
}

public function show-opt() {
rect.x = -opt.width - Theme.padding;
rect.is-show-opt = true;
Expand All @@ -297,8 +316,8 @@ export component EntryList inherits Rectangle {

TouchArea {
moved => {
if (lv.enabled && (self.pressed-x - self.mouse-x > parent.max-move-pixels-low-bound || self.mouse-x - self.pressed-x > parent.max-move-pixels-low-bound)) {
lv.enabled = false;
if (lv.interactive && (self.pressed-x - self.mouse-x > parent.max-move-pixels-low-bound || self.mouse-x - self.pressed-x > parent.max-move-pixels-low-bound)) {
lv.interactive = false;
}
if (!rect.is-show-opt) {
if (self.pressed-x - self.mouse-x > parent.max-move-pixels-up-bound) {
Expand All @@ -314,7 +333,7 @@ export component EntryList inherits Rectangle {

pointer-event(evt) => {
if (evt.kind == PointerEventKind.up) {
lv.enabled = true;
lv.interactive = true;
}
}
}
Expand All @@ -337,8 +356,9 @@ export component EntryList inherits Rectangle {

opt := VerticalLayout {
x: entry-vbox.width + Theme.padding;
y: 0;
width: 50px;
height: entry-vbox.height - entry-vbox.padding * 2 - Theme.padding;
height: entry-vbox.preferred-height;
alignment: center;

Rectangle {
Expand Down Expand Up @@ -367,8 +387,15 @@ export component EntryList inherits Rectangle {
colorize: Theme.danger-color;

clicked => {
current-list-index = Logic.current-rsslist-index(Store.current-rss-uuid);
if (current-list-index >= 0 && current-list-index < Store.rss-lists.length) {
Store.rss-lists[current-list-index].current-viewport-y = lv.viewport-y;
}
rect.hide-opt();
Logic.remove-entry(Store.current-rss-uuid, item.uuid);

// If I don't refresh current tab, the remove entry space will remain on the Flickable
Store.refresh-current-tab();
}
}
}
Expand Down Expand Up @@ -407,6 +434,12 @@ export component EntryList inherits Rectangle {
if (Store.rss-lists.length == 0) {
Logic.load-all-rss();
}

current-list-index = Logic.current-rsslist-index(Store.current-rss-uuid);
if (current-list-index >= 0 && current-list-index < Store.rss-lists.length) {
Store.rss-lists[current-list-index].current-viewport-y = 0;
}

Logic.sync-rss(Store.current-rss-uuid, true);
}
}
Expand Down
16 changes: 12 additions & 4 deletions ui/store.slint
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum TabIndex {
Favorite,
Find,
Setting,
None,
}

export struct FindEntry {
Expand Down Expand Up @@ -38,6 +39,7 @@ export struct RssConfig {
is-update-failed: bool,
unread-counts: int,
entry: [RssEntry],
current-viewport-y: length,
}

export struct MessageItem {
Expand Down Expand Up @@ -96,6 +98,8 @@ export struct AboutDialog {

export global Store {
out property <TabIndex> current-tab-index: TabIndex.Rss;
private property <TabIndex> current-tab-index-tmp: TabIndex.None;

in-out property <string> current-rss-uuid;

in-out property <[RssConfig]> rss-lists: [
Expand Down Expand Up @@ -125,8 +129,6 @@ export global Store {
tags: "rust",
is-read: false,
author: "hello",
summary: "The actor model in computer science is a mathematical model of concurrent computation that treats an actor as the basic building block of concurrent computation.",
// title: "Actors ",
title: "Actors may modify their own private state, but can only affect each other indirectly through messaging (removing the need for lock-based synchronization).",
summary: "The actor model in computer science is a mathematical model of concurrent computation that treats an actor as the basic building block of concurrent computation.",
},
Expand All @@ -149,7 +151,7 @@ export global Store {
tags: "rust",
is-read: false,
author: "hello",
title: "Actors may modify their",
title: "The actor model in computer science is a mathematical model of concurrent computation that treats an actor as the basic building block of concurrent computation.",
summary: "The actor model in computer science is a mathematical model of concurrent computation that treats an actor as the basic building block of concurrent computation.",
},
{
Expand Down Expand Up @@ -212,7 +214,13 @@ export global Store {
"- Click the top-right list icon of the [RSS] selected card to open the RSS list.\n\n" + "- Swipe right on the [RSS] and [Collection] items to collect or delete items.\n\n" + "- After setting, click the back button in the upper left corner. Save the settings.\n\n" + "- In case of don't show the same articles, It will cache the articles after syncing. You can enter the [Setting] selected card to clear cache.\n\n",
};

public function switch-tab(tab-index: TabIndex){
public function switch-tab(tab-index: TabIndex) {
current-tab-index = tab-index;
}

public function refresh-current-tab() {
current-tab-index-tmp = current-tab-index;
current-tab-index = TabIndex.None;
current-tab-index = current-tab-index-tmp;
}
}

0 comments on commit 4b4c48e

Please sign in to comment.