Reformat project and change package id
This commit is contained in:
parent
d71bbcd3f3
commit
fbf4b8dfa5
|
@ -1,3 +1,7 @@
|
||||||
/target
|
/target
|
||||||
/.cargo
|
/.cargo
|
||||||
/_build
|
/_build
|
||||||
|
/builddir
|
||||||
|
/.flatpak
|
||||||
|
/.flatpak-builder
|
||||||
|
/.vscode
|
|
@ -1,3 +1,16 @@
|
||||||
{
|
{
|
||||||
"C_Cpp.default.compileCommands": "builddir/vscode_compile_commands.json"
|
"C_Cpp.default.compileCommands": "builddir/vscode_compile_commands.json",
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/.dart_tool": true,
|
||||||
|
".flatpak/**": true,
|
||||||
|
"_build/**": true
|
||||||
|
},
|
||||||
|
"mesonbuild.configureOnOpen": false,
|
||||||
|
"mesonbuild.buildFolder": "_build",
|
||||||
|
"mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh",
|
||||||
|
"rust-analyzer.server.path": "${workspaceFolder}/.flatpak/rust-analyzer.sh",
|
||||||
|
"rust-analyzer.runnables.command": "${workspaceFolder}/.flatpak/cargo.sh",
|
||||||
|
"rust-analyzer.files.excludeDirs": [
|
||||||
|
".flatpak"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"id": "com.lemmy-gtk.lemoa",
|
"id": "com.lemmygtk.lemoa",
|
||||||
"runtime": "org.gnome.Platform",
|
"runtime": "org.gnome.Platform",
|
||||||
"runtime-version": "44",
|
"runtime-version": "44",
|
||||||
"sdk": "org.gnome.Sdk",
|
"sdk": "org.gnome.Sdk",
|
||||||
|
|
|
@ -8,7 +8,7 @@ project(
|
||||||
|
|
||||||
gnome = import('gnome')
|
gnome = import('gnome')
|
||||||
|
|
||||||
application_id = 'com.lemmy-gtk.lemoa'
|
application_id = 'com.lemmygtk.lemoa'
|
||||||
|
|
||||||
dependency('glib-2.0', version: '>= 2.70')
|
dependency('glib-2.0', version: '>= 2.70')
|
||||||
dependency('gio-2.0', version: '>= 2.70')
|
dependency('gio-2.0', version: '>= 2.70')
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
use lemmy_api_common::{person::Login, sensitive::Sensitive};
|
use lemmy_api_common::{person::Login, sensitive::Sensitive};
|
||||||
|
|
||||||
pub fn login(username_or_email: String, password: String, totp_token: Option<String>) -> std::result::Result<lemmy_api_common::person::LoginResponse, reqwest::Error> {
|
pub fn login(
|
||||||
|
username_or_email: String,
|
||||||
|
password: String,
|
||||||
|
totp_token: Option<String>,
|
||||||
|
) -> std::result::Result<lemmy_api_common::person::LoginResponse, reqwest::Error> {
|
||||||
let params = Login {
|
let params = Login {
|
||||||
username_or_email: Sensitive::new(username_or_email),
|
username_or_email: Sensitive::new(username_or_email),
|
||||||
password: Sensitive::new(password),
|
password: Sensitive::new(password),
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use lemmy_api_common::{comment::{CommentResponse, CreateComment, CreateCommentLike, DeleteComment, EditComment}, lemmy_db_schema::newtypes::{PostId, CommentId}};
|
use lemmy_api_common::{
|
||||||
|
comment::{CommentResponse, CreateComment, CreateCommentLike, DeleteComment, EditComment},
|
||||||
|
lemmy_db_schema::newtypes::{CommentId, PostId},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
|
@ -27,10 +30,7 @@ pub fn like_comment(comment_id: CommentId, score: i16) -> Result<CommentResponse
|
||||||
super::post("/comment/like", ¶ms)
|
super::post("/comment/like", ¶ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edit_comment(
|
pub fn edit_comment(body: String, comment_id: i32) -> Result<CommentResponse, reqwest::Error> {
|
||||||
body: String,
|
|
||||||
comment_id: i32
|
|
||||||
) -> Result<CommentResponse, reqwest::Error> {
|
|
||||||
let params = EditComment {
|
let params = EditComment {
|
||||||
content: Some(body),
|
content: Some(body),
|
||||||
comment_id: CommentId(comment_id),
|
comment_id: CommentId(comment_id),
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
use lemmy_api_common::{community::{ListCommunities, ListCommunitiesResponse}, lemmy_db_schema::{SortType, SearchType, ListingType}, lemmy_db_views_actor::structs::CommunityView};
|
use lemmy_api_common::{
|
||||||
|
community::{ListCommunities, ListCommunitiesResponse},
|
||||||
|
lemmy_db_schema::{ListingType, SearchType, SortType},
|
||||||
|
lemmy_db_views_actor::structs::CommunityView,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::settings;
|
|
||||||
use super::search;
|
use super::search;
|
||||||
|
use crate::settings;
|
||||||
|
|
||||||
pub fn fetch_communities(page: i64, query: Option<String>,listing_type: Option<ListingType>) -> std::result::Result<Vec<CommunityView>, reqwest::Error> {
|
pub fn fetch_communities(
|
||||||
|
page: i64,
|
||||||
|
query: Option<String>,
|
||||||
|
listing_type: Option<ListingType>,
|
||||||
|
) -> std::result::Result<Vec<CommunityView>, reqwest::Error> {
|
||||||
if query.is_none() || query.clone().unwrap().trim().is_empty() {
|
if query.is_none() || query.clone().unwrap().trim().is_empty() {
|
||||||
let params = ListCommunities {
|
let params = ListCommunities {
|
||||||
type_: listing_type,
|
type_: listing_type,
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use lemmy_api_common::{community::{GetCommunity, GetCommunityResponse, CommunityResponse, FollowCommunity}, lemmy_db_schema::newtypes::CommunityId};
|
use lemmy_api_common::{
|
||||||
|
community::{CommunityResponse, FollowCommunity, GetCommunity, GetCommunityResponse},
|
||||||
|
lemmy_db_schema::newtypes::CommunityId,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use reqwest::blocking::multipart::Part;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::fs::File;
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
use serde::Deserialize;
|
|
||||||
use rand::distributions::{Alphanumeric, DistString};
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
|
use reqwest::blocking::multipart::Part;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use super::CLIENT;
|
use super::CLIENT;
|
||||||
|
|
||||||
|
@ -21,9 +21,7 @@ struct UploadImageFile {
|
||||||
pub delete_token: String,
|
pub delete_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upload_image(
|
pub fn upload_image(image: std::path::PathBuf) -> Result<String, reqwest::Error> {
|
||||||
image: std::path::PathBuf,
|
|
||||||
) -> Result<String, reqwest::Error> {
|
|
||||||
let mime_type = mime_guess::from_path(image.clone()).first();
|
let mime_type = mime_guess::from_path(image.clone()).first();
|
||||||
let file_name = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);
|
let file_name = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);
|
||||||
|
|
||||||
|
@ -31,14 +29,19 @@ pub fn upload_image(
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
file.read_to_end(&mut data).unwrap();
|
file.read_to_end(&mut data).unwrap();
|
||||||
|
|
||||||
let part = Part::bytes(data).file_name(file_name).mime_str(&mime_type.unwrap().essence_str())?;
|
let part = Part::bytes(data)
|
||||||
|
.file_name(file_name)
|
||||||
|
.mime_str(&mime_type.unwrap().essence_str())?;
|
||||||
let form = reqwest::blocking::multipart::Form::new().part("images[]", part);
|
let form = reqwest::blocking::multipart::Form::new().part("images[]", part);
|
||||||
let account = settings::get_current_account();
|
let account = settings::get_current_account();
|
||||||
let base_url = account.instance_url;
|
let base_url = account.instance_url;
|
||||||
let path = format!("{}/pictrs/image", base_url);
|
let path = format!("{}/pictrs/image", base_url);
|
||||||
let res: UploadImageResponse = CLIENT
|
let res: UploadImageResponse = CLIENT
|
||||||
.post(&path)
|
.post(&path)
|
||||||
.header("cookie", format!("jwt={}", account.jwt.unwrap().to_string()))
|
.header(
|
||||||
|
"cookie",
|
||||||
|
format!("jwt={}", account.jwt.unwrap().to_string()),
|
||||||
|
)
|
||||||
.multipart(form)
|
.multipart(form)
|
||||||
.send()?
|
.send()?
|
||||||
.json()?;
|
.json()?;
|
||||||
|
|
|
@ -2,26 +2,24 @@ use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
use crate::settings::get_current_account;
|
use crate::settings::get_current_account;
|
||||||
|
|
||||||
|
pub mod auth;
|
||||||
|
pub mod comment;
|
||||||
pub mod communities;
|
pub mod communities;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
|
pub mod image;
|
||||||
|
pub mod moderation;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod posts;
|
pub mod posts;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
pub mod user;
|
|
||||||
pub mod auth;
|
|
||||||
pub mod moderation;
|
|
||||||
pub mod comment;
|
|
||||||
pub mod site;
|
pub mod site;
|
||||||
pub mod image;
|
pub mod user;
|
||||||
|
|
||||||
static API_VERSION: &str = "v3";
|
static API_VERSION: &str = "v3";
|
||||||
|
|
||||||
use reqwest::blocking::Client;
|
|
||||||
use relm4::once_cell::sync::Lazy;
|
use relm4::once_cell::sync::Lazy;
|
||||||
|
use reqwest::blocking::Client;
|
||||||
|
|
||||||
pub static CLIENT: Lazy<Client> = Lazy::new(|| {
|
pub static CLIENT: Lazy<Client> = Lazy::new(|| Client::new());
|
||||||
Client::new()
|
|
||||||
});
|
|
||||||
|
|
||||||
fn get_api_url() -> String {
|
fn get_api_url() -> String {
|
||||||
format!("{}/api/{}", get_current_account().instance_url, API_VERSION).to_string()
|
format!("{}/api/{}", get_current_account().instance_url, API_VERSION).to_string()
|
||||||
|
@ -36,11 +34,7 @@ where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
Params: Serialize + std::fmt::Debug,
|
Params: Serialize + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
CLIENT
|
CLIENT.get(&get_url(path)).query(¶ms).send()?.json()
|
||||||
.get(&get_url(path))
|
|
||||||
.query(¶ms)
|
|
||||||
.send()?
|
|
||||||
.json()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post<T, Params>(path: &str, params: &Params) -> Result<T, reqwest::Error>
|
fn post<T, Params>(path: &str, params: &Params) -> Result<T, reqwest::Error>
|
||||||
|
@ -48,11 +42,7 @@ where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
Params: Serialize + std::fmt::Debug,
|
Params: Serialize + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
CLIENT
|
CLIENT.post(&get_url(path)).json(¶ms).send()?.json()
|
||||||
.post(&get_url(path))
|
|
||||||
.json(¶ms)
|
|
||||||
.send()?
|
|
||||||
.json()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put<T, Params>(path: &str, params: &Params) -> Result<T, reqwest::Error>
|
fn put<T, Params>(path: &str, params: &Params) -> Result<T, reqwest::Error>
|
||||||
|
@ -60,9 +50,5 @@ where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
Params: Serialize + std::fmt::Debug,
|
Params: Serialize + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
CLIENT
|
CLIENT.put(&get_url(path)).json(¶ms).send()?.json()
|
||||||
.put(&get_url(path))
|
|
||||||
.json(¶ms)
|
|
||||||
.send()?
|
|
||||||
.json()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
use lemmy_api_common::{lemmy_db_schema::newtypes::{CommentId, PostId}, comment::{RemoveComment, CommentResponse}, sensitive::Sensitive, post::{PostResponse, RemovePost}};
|
use lemmy_api_common::{
|
||||||
|
comment::{CommentResponse, RemoveComment},
|
||||||
|
lemmy_db_schema::newtypes::{CommentId, PostId},
|
||||||
|
post::{PostResponse, RemovePost},
|
||||||
|
sensitive::Sensitive,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn remove_post(
|
pub fn remove_post(
|
||||||
post_id: i32,
|
post_id: i32,
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
use lemmy_api_common::{post::{GetPost, GetPostResponse, PostResponse, CreatePost, CreatePostLike, DeletePost, EditPost}, lemmy_db_schema::{newtypes::{PostId, CommunityId}, CommentSortType, ListingType}, comment::{GetComments, GetCommentsResponse}, lemmy_db_views::structs::CommentView};
|
use lemmy_api_common::{
|
||||||
|
comment::{GetComments, GetCommentsResponse},
|
||||||
|
lemmy_db_schema::{
|
||||||
|
newtypes::{CommunityId, PostId},
|
||||||
|
CommentSortType, ListingType,
|
||||||
|
},
|
||||||
|
lemmy_db_views::structs::CommentView,
|
||||||
|
post::{
|
||||||
|
CreatePost, CreatePostLike, DeletePost, EditPost, GetPost, GetPostResponse, PostResponse,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
|
@ -6,7 +16,7 @@ pub fn get_post(id: PostId) -> Result<GetPostResponse, reqwest::Error> {
|
||||||
let params = GetPost {
|
let params = GetPost {
|
||||||
id: Some(id),
|
id: Some(id),
|
||||||
comment_id: None,
|
comment_id: None,
|
||||||
auth: settings::get_current_account().jwt
|
auth: settings::get_current_account().jwt,
|
||||||
};
|
};
|
||||||
|
|
||||||
super::get("/post", ¶ms)
|
super::get("/post", ¶ms)
|
||||||
|
@ -54,7 +64,7 @@ pub fn edit_post(
|
||||||
name: String,
|
name: String,
|
||||||
url: Option<reqwest::Url>,
|
url: Option<reqwest::Url>,
|
||||||
body: String,
|
body: String,
|
||||||
post_id: i32
|
post_id: i32,
|
||||||
) -> Result<PostResponse, reqwest::Error> {
|
) -> Result<PostResponse, reqwest::Error> {
|
||||||
let params = EditPost {
|
let params = EditPost {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
use lemmy_api_common::{post::{GetPostsResponse, GetPosts}, lemmy_db_views::structs::PostView, lemmy_db_schema::ListingType};
|
use lemmy_api_common::{
|
||||||
|
lemmy_db_schema::ListingType,
|
||||||
|
lemmy_db_views::structs::PostView,
|
||||||
|
post::{GetPosts, GetPostsResponse},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
pub fn list_posts(page: i64, community_name: Option<String>, listing_type: Option<ListingType>) -> std::result::Result<Vec<PostView>, reqwest::Error> {
|
pub fn list_posts(
|
||||||
|
page: i64,
|
||||||
|
community_name: Option<String>,
|
||||||
|
listing_type: Option<ListingType>,
|
||||||
|
) -> std::result::Result<Vec<PostView>, reqwest::Error> {
|
||||||
let params = GetPosts {
|
let params = GetPosts {
|
||||||
page: Some(page),
|
page: Some(page),
|
||||||
type_: listing_type,
|
type_: listing_type,
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
use lemmy_api_common::{site::{SearchResponse, Search}, lemmy_db_schema::{SortType, SearchType}};
|
use lemmy_api_common::{
|
||||||
|
lemmy_db_schema::{SearchType, SortType},
|
||||||
|
site::{Search, SearchResponse},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
pub fn fetch_search(page: i64, query: String, search_type: Option<SearchType>) -> std::result::Result<SearchResponse, reqwest::Error> {
|
pub fn fetch_search(
|
||||||
|
page: i64,
|
||||||
|
query: String,
|
||||||
|
search_type: Option<SearchType>,
|
||||||
|
) -> std::result::Result<SearchResponse, reqwest::Error> {
|
||||||
let params = Search {
|
let params = Search {
|
||||||
q: query,
|
q: query,
|
||||||
sort: Some(SortType::TopMonth),
|
sort: Some(SortType::TopMonth),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use lemmy_api_common::site::{GetSiteResponse, GetSite};
|
use lemmy_api_common::site::{GetSite, GetSiteResponse};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
use lemmy_api_common::{person::{GetPersonDetailsResponse, GetPersonDetails, GetPersonMentionsResponse, GetRepliesResponse, MarkAllAsRead, GetReplies, GetPersonMentions}, lemmy_db_schema::{CommentSortType, newtypes::PersonId}};
|
use lemmy_api_common::{
|
||||||
|
lemmy_db_schema::{newtypes::PersonId, CommentSortType},
|
||||||
|
person::{
|
||||||
|
GetPersonDetails, GetPersonDetailsResponse, GetPersonMentions, GetPersonMentionsResponse,
|
||||||
|
GetReplies, GetRepliesResponse, MarkAllAsRead,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
|
||||||
pub fn get_user(id: PersonId, page: i64) -> std::result::Result<GetPersonDetailsResponse, reqwest::Error> {
|
pub fn get_user(
|
||||||
|
id: PersonId,
|
||||||
|
page: i64,
|
||||||
|
) -> std::result::Result<GetPersonDetailsResponse, reqwest::Error> {
|
||||||
let params = GetPersonDetails {
|
let params = GetPersonDetails {
|
||||||
page: Some(page),
|
page: Some(page),
|
||||||
person_id: Some(id),
|
person_id: Some(id),
|
||||||
|
@ -17,7 +26,10 @@ pub fn default_person() -> GetPersonDetailsResponse {
|
||||||
serde_json::from_str(include_str!("../examples/person.json")).unwrap()
|
serde_json::from_str(include_str!("../examples/person.json")).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mentions(page: i64, unread_only: bool) -> std::result::Result<GetPersonMentionsResponse, reqwest::Error> {
|
pub fn get_mentions(
|
||||||
|
page: i64,
|
||||||
|
unread_only: bool,
|
||||||
|
) -> std::result::Result<GetPersonMentionsResponse, reqwest::Error> {
|
||||||
let params = GetPersonMentions {
|
let params = GetPersonMentions {
|
||||||
auth: settings::get_current_account().jwt.unwrap(),
|
auth: settings::get_current_account().jwt.unwrap(),
|
||||||
unread_only: Some(unread_only),
|
unread_only: Some(unread_only),
|
||||||
|
@ -28,7 +40,10 @@ pub fn get_mentions(page: i64, unread_only: bool) -> std::result::Result<GetPers
|
||||||
super::get("/user/mention", ¶ms)
|
super::get("/user/mention", ¶ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_replies(page: i64, unread_only: bool) -> std::result::Result<GetRepliesResponse, reqwest::Error> {
|
pub fn get_replies(
|
||||||
|
page: i64,
|
||||||
|
unread_only: bool,
|
||||||
|
) -> std::result::Result<GetRepliesResponse, reqwest::Error> {
|
||||||
let params = GetReplies {
|
let params = GetReplies {
|
||||||
auth: settings::get_current_account().jwt.unwrap(),
|
auth: settings::get_current_account().jwt.unwrap(),
|
||||||
page: Some(page),
|
page: Some(page),
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
|
use gtk::prelude::*;
|
||||||
use lemmy_api_common::lemmy_db_views::structs::CommentView;
|
use lemmy_api_common::lemmy_db_views::structs::CommentView;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
use gtk::prelude::*;
|
|
||||||
use relm4_components::web_image::WebImage;
|
use relm4_components::web_image::WebImage;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::dialogs::editor::EditorData;
|
use crate::dialogs::editor::EditorData;
|
||||||
|
use crate::settings;
|
||||||
use crate::util::get_web_image_url;
|
use crate::util::get_web_image_url;
|
||||||
use crate::util::markdown_to_pango_markup;
|
use crate::util::markdown_to_pango_markup;
|
||||||
use crate::settings;
|
|
||||||
|
|
||||||
use super::post_page::PostInput;
|
use super::post_page::PostInput;
|
||||||
use super::voting_row::VotingRowModel;
|
use super::voting_row::VotingRowModel;
|
||||||
|
@ -17,14 +17,14 @@ use super::voting_row::VotingStats;
|
||||||
pub struct CommentRow {
|
pub struct CommentRow {
|
||||||
pub comment: CommentView,
|
pub comment: CommentView,
|
||||||
avatar: Controller<WebImage>,
|
avatar: Controller<WebImage>,
|
||||||
voting_row: Controller<VotingRowModel>
|
voting_row: Controller<VotingRowModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CommentRowMsg {
|
pub enum CommentRowMsg {
|
||||||
OpenPerson,
|
OpenPerson,
|
||||||
DeleteComment,
|
DeleteComment,
|
||||||
OpenEditCommentDialog
|
OpenEditCommentDialog,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[relm4::factory(pub)]
|
#[relm4::factory(pub)]
|
||||||
|
@ -109,10 +109,21 @@ impl FactoryComponent for CommentRow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||||
let avatar = WebImage::builder().launch(get_web_image_url(value.creator.avatar.clone())).detach();
|
let avatar = WebImage::builder()
|
||||||
let voting_row = VotingRowModel::builder().launch(VotingStats::from_comment(value.counts.clone(), value.my_vote)).detach();
|
.launch(get_web_image_url(value.creator.avatar.clone()))
|
||||||
|
.detach();
|
||||||
|
let voting_row = VotingRowModel::builder()
|
||||||
|
.launch(VotingStats::from_comment(
|
||||||
|
value.counts.clone(),
|
||||||
|
value.my_vote,
|
||||||
|
))
|
||||||
|
.detach();
|
||||||
|
|
||||||
Self { comment: value, avatar, voting_row }
|
Self {
|
||||||
|
comment: value,
|
||||||
|
avatar,
|
||||||
|
voting_row,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_widgets(
|
fn init_widgets(
|
||||||
|
@ -131,13 +142,17 @@ impl FactoryComponent for CommentRow {
|
||||||
fn update(&mut self, message: Self::Input, sender: FactorySender<Self>) {
|
fn update(&mut self, message: Self::Input, sender: FactorySender<Self>) {
|
||||||
match message {
|
match message {
|
||||||
CommentRowMsg::OpenPerson => {
|
CommentRowMsg::OpenPerson => {
|
||||||
sender.output(PostInput::PassAppMessage(crate::AppMsg::OpenPerson(self.comment.creator.id.clone())));
|
sender.output(PostInput::PassAppMessage(crate::AppMsg::OpenPerson(
|
||||||
|
self.comment.creator.id.clone(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
CommentRowMsg::DeleteComment => {
|
CommentRowMsg::DeleteComment => {
|
||||||
let comment_id = self.comment.comment.id;
|
let comment_id = self.comment.comment.id;
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let _ = api::comment::delete_comment(comment_id);
|
let _ = api::comment::delete_comment(comment_id);
|
||||||
let _ = sender.output(PostInput::PassAppMessage(crate::AppMsg::StartFetchPosts(None, true)));
|
let _ = sender.output(PostInput::PassAppMessage(
|
||||||
|
crate::AppMsg::StartFetchPosts(None, true),
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
CommentRowMsg::OpenEditCommentDialog => {
|
CommentRowMsg::OpenEditCommentDialog => {
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
use crate::{util::markdown_to_pango_markup, dialogs::editor::{EditorDialog, DialogMsg, EditorOutput, EditorType, EditorData}};
|
use crate::{
|
||||||
use lemmy_api_common::{lemmy_db_views::structs::PostView, lemmy_db_views_actor::structs::CommunityView, lemmy_db_schema::SubscribedType};
|
dialogs::editor::{DialogMsg, EditorData, EditorDialog, EditorOutput, EditorType},
|
||||||
use relm4::{prelude::*, factory::FactoryVecDeque, MessageBroker};
|
util::markdown_to_pango_markup,
|
||||||
|
};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use lemmy_api_common::{
|
||||||
|
lemmy_db_schema::SubscribedType, lemmy_db_views::structs::PostView,
|
||||||
|
lemmy_db_views_actor::structs::CommunityView,
|
||||||
|
};
|
||||||
|
use relm4::{factory::FactoryVecDeque, prelude::*, MessageBroker};
|
||||||
use relm4_components::web_image::WebImage;
|
use relm4_components::web_image::WebImage;
|
||||||
|
|
||||||
use crate::{api, util::get_web_image_msg, settings};
|
use crate::{api, settings, util::get_web_image_msg};
|
||||||
|
|
||||||
use super::post_row::PostRow;
|
use super::post_row::PostRow;
|
||||||
|
|
||||||
|
@ -16,7 +22,7 @@ pub struct CommunityPage {
|
||||||
posts: FactoryVecDeque<PostRow>,
|
posts: FactoryVecDeque<PostRow>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
create_post_dialog: Controller<EditorDialog>,
|
create_post_dialog: Controller<EditorDialog>,
|
||||||
current_posts_page: i64
|
current_posts_page: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -29,7 +35,7 @@ pub enum CommunityInput {
|
||||||
CreatedPost(PostView),
|
CreatedPost(PostView),
|
||||||
ToggleSubscription,
|
ToggleSubscription,
|
||||||
UpdateSubscriptionState(SubscribedType),
|
UpdateSubscriptionState(SubscribedType),
|
||||||
None
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[relm4::component(pub)]
|
#[relm4::component(pub)]
|
||||||
|
@ -139,10 +145,16 @@ impl SimpleComponent for CommunityPage {
|
||||||
.launch_with_broker(EditorType::Post, &COMMUNITY_PAGE_BROKER)
|
.launch_with_broker(EditorType::Post, &COMMUNITY_PAGE_BROKER)
|
||||||
.forward(sender.input_sender(), |msg| match msg {
|
.forward(sender.input_sender(), |msg| match msg {
|
||||||
EditorOutput::CreateRequest(post, _) => CommunityInput::CreatePostRequest(post),
|
EditorOutput::CreateRequest(post, _) => CommunityInput::CreatePostRequest(post),
|
||||||
_ => CommunityInput::None
|
_ => CommunityInput::None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let model = CommunityPage { info: init, avatar, posts, create_post_dialog: dialog, current_posts_page: 0 };
|
let model = CommunityPage {
|
||||||
|
info: init,
|
||||||
|
avatar,
|
||||||
|
posts,
|
||||||
|
create_post_dialog: dialog,
|
||||||
|
current_posts_page: 0,
|
||||||
|
};
|
||||||
let avatar = model.avatar.widget();
|
let avatar = model.avatar.widget();
|
||||||
let posts = model.posts.widget();
|
let posts = model.posts.widget();
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
@ -154,10 +166,13 @@ impl SimpleComponent for CommunityPage {
|
||||||
match message {
|
match message {
|
||||||
CommunityInput::UpdateCommunity(community) => {
|
CommunityInput::UpdateCommunity(community) => {
|
||||||
self.info = community.clone();
|
self.info = community.clone();
|
||||||
self.avatar.emit(get_web_image_msg(community.community.icon));
|
self.avatar
|
||||||
|
.emit(get_web_image_msg(community.community.icon));
|
||||||
self.posts.guard().clear();
|
self.posts.guard().clear();
|
||||||
self.current_posts_page = 0;
|
self.current_posts_page = 0;
|
||||||
if community.counts.posts == 0 { return; }
|
if community.counts.posts == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
sender.input(CommunityInput::FetchPosts);
|
sender.input(CommunityInput::FetchPosts);
|
||||||
}
|
}
|
||||||
CommunityInput::FetchPosts => {
|
CommunityInput::FetchPosts => {
|
||||||
|
@ -176,9 +191,7 @@ impl SimpleComponent for CommunityPage {
|
||||||
self.posts.guard().push_back(post);
|
self.posts.guard().push_back(post);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CommunityInput::OpenCreatePostDialog => {
|
CommunityInput::OpenCreatePostDialog => COMMUNITY_PAGE_BROKER.send(DialogMsg::Show),
|
||||||
COMMUNITY_PAGE_BROKER.send(DialogMsg::Show)
|
|
||||||
}
|
|
||||||
CommunityInput::CreatedPost(post) => {
|
CommunityInput::CreatedPost(post) => {
|
||||||
self.posts.guard().push_front(post);
|
self.posts.guard().push_front(post);
|
||||||
}
|
}
|
||||||
|
@ -187,23 +200,35 @@ impl SimpleComponent for CommunityPage {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::post::create_post(post.name, post.body, post.url, id) {
|
let message = match api::post::create_post(post.name, post.body, post.url, id) {
|
||||||
Ok(post) => Some(CommunityInput::CreatedPost(post.post_view)),
|
Ok(post) => Some(CommunityInput::CreatedPost(post.post_view)),
|
||||||
Err(err) => { println!("{}", err.to_string()); None }
|
Err(err) => {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(message) = message {
|
||||||
|
sender.input(message)
|
||||||
};
|
};
|
||||||
if let Some(message) = message { sender.input(message) };
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
CommunityInput::ToggleSubscription => {
|
CommunityInput::ToggleSubscription => {
|
||||||
let community_id = self.info.community.id.0;
|
let community_id = self.info.community.id.0;
|
||||||
let new_state = match self.info.subscribed {
|
let new_state = match self.info.subscribed {
|
||||||
SubscribedType::NotSubscribed => true,
|
SubscribedType::NotSubscribed => true,
|
||||||
_ => false
|
_ => false,
|
||||||
};
|
};
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::community::follow_community(community_id, new_state) {
|
let message = match api::community::follow_community(community_id, new_state) {
|
||||||
Ok(community) => Some(CommunityInput::UpdateSubscriptionState(community.community_view.subscribed)),
|
Ok(community) => Some(CommunityInput::UpdateSubscriptionState(
|
||||||
Err(err) => { println!("{}", err.to_string()); None }
|
community.community_view.subscribed,
|
||||||
|
)),
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if message.is_some() {
|
||||||
|
sender.input(message.unwrap())
|
||||||
};
|
};
|
||||||
if message.is_some() { sender.input(message.unwrap()) };
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
CommunityInput::UpdateSubscriptionState(state) => {
|
CommunityInput::UpdateSubscriptionState(state) => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use gtk::prelude::*;
|
||||||
use lemmy_api_common::lemmy_db_views_actor::structs::CommunityView;
|
use lemmy_api_common::lemmy_db_views_actor::structs::CommunityView;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
use gtk::prelude::*;
|
|
||||||
use relm4_components::web_image::WebImage;
|
use relm4_components::web_image::WebImage;
|
||||||
|
|
||||||
use crate::util::get_web_image_url;
|
use crate::util::get_web_image_url;
|
||||||
|
@ -75,9 +75,14 @@ impl FactoryComponent for CommunityRow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||||
let community_image= WebImage::builder().launch(get_web_image_url(value.community.clone().icon)).detach();
|
let community_image = WebImage::builder()
|
||||||
|
.launch(get_web_image_url(value.community.clone().icon))
|
||||||
|
.detach();
|
||||||
|
|
||||||
Self { community: value, community_image }
|
Self {
|
||||||
|
community: value,
|
||||||
|
community_image,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_widgets(
|
fn init_widgets(
|
||||||
|
@ -94,9 +99,9 @@ impl FactoryComponent for CommunityRow {
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Input, sender: FactorySender<Self>) {
|
fn update(&mut self, message: Self::Input, sender: FactorySender<Self>) {
|
||||||
match message {
|
match message {
|
||||||
CommunityRowMsg::OpenCommunity => {
|
CommunityRowMsg::OpenCommunity => sender.output(crate::AppMsg::OpenCommunity(
|
||||||
sender.output(crate::AppMsg::OpenCommunity(self.community.community.id.clone()))
|
self.community.community.id.clone(),
|
||||||
}
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use lemmy_api_common::lemmy_db_views_actor::structs::CommentReplyView;
|
|
||||||
use relm4::{prelude::*, factory::FactoryVecDeque};
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use lemmy_api_common::lemmy_db_views_actor::structs::CommentReplyView;
|
||||||
|
use relm4::{factory::FactoryVecDeque, prelude::*};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ pub struct InboxPage {
|
||||||
mentions: FactoryVecDeque<MentionRow>,
|
mentions: FactoryVecDeque<MentionRow>,
|
||||||
page: i64,
|
page: i64,
|
||||||
unread_only: bool,
|
unread_only: bool,
|
||||||
type_: InboxType
|
type_: InboxType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -75,7 +75,12 @@ impl SimpleComponent for InboxPage {
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
let mentions = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender());
|
let mentions = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender());
|
||||||
let model = Self { mentions, page: 1, unread_only: false, type_: InboxType::Mentions };
|
let model = Self {
|
||||||
|
mentions,
|
||||||
|
page: 1,
|
||||||
|
unread_only: false,
|
||||||
|
type_: InboxType::Mentions,
|
||||||
|
};
|
||||||
let mentions = model.mentions.widget();
|
let mentions = model.mentions.widget();
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
|
@ -94,12 +99,16 @@ impl SimpleComponent for InboxPage {
|
||||||
// It's just a different object, but its contents are exactly the same
|
// It's just a different object, but its contents are exactly the same
|
||||||
let serialised = serde_json::to_string(&response.mentions).unwrap();
|
let serialised = serde_json::to_string(&response.mentions).unwrap();
|
||||||
serde_json::from_str(&serialised).ok()
|
serde_json::from_str(&serialised).ok()
|
||||||
} else { None }
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
InboxType::Replies => {
|
InboxType::Replies => {
|
||||||
if let Ok(response) = api::user::get_replies(page, unread_only) {
|
if let Ok(response) = api::user::get_replies(page, unread_only) {
|
||||||
Some(response.replies)
|
Some(response.replies)
|
||||||
} else { None }
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(comments) = comments {
|
if let Some(comments) = comments {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use gtk::prelude::*;
|
||||||
use lemmy_api_common::lemmy_db_views_actor::structs::CommentReplyView;
|
use lemmy_api_common::lemmy_db_views_actor::structs::CommentReplyView;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
use gtk::prelude::*;
|
|
||||||
use relm4_components::web_image::WebImage;
|
use relm4_components::web_image::WebImage;
|
||||||
|
|
||||||
use crate::util::get_web_image_url;
|
use crate::util::get_web_image_url;
|
||||||
|
@ -14,7 +14,7 @@ pub struct MentionRow {
|
||||||
comment: CommentReplyView,
|
comment: CommentReplyView,
|
||||||
creator_image: Controller<WebImage>,
|
creator_image: Controller<WebImage>,
|
||||||
community_image: Controller<WebImage>,
|
community_image: Controller<WebImage>,
|
||||||
voting_row: Controller<VotingRowModel>
|
voting_row: Controller<VotingRowModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -114,11 +114,25 @@ impl FactoryComponent for MentionRow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||||
let creator_image = WebImage::builder().launch(get_web_image_url(value.creator.avatar.clone())).detach();
|
let creator_image = WebImage::builder()
|
||||||
let community_image = WebImage::builder().launch(get_web_image_url(value.community.icon.clone())).detach();
|
.launch(get_web_image_url(value.creator.avatar.clone()))
|
||||||
let voting_row = VotingRowModel::builder().launch(VotingStats::from_comment(value.counts.clone(), value.my_vote)).detach();
|
.detach();
|
||||||
|
let community_image = WebImage::builder()
|
||||||
|
.launch(get_web_image_url(value.community.icon.clone()))
|
||||||
|
.detach();
|
||||||
|
let voting_row = VotingRowModel::builder()
|
||||||
|
.launch(VotingStats::from_comment(
|
||||||
|
value.counts.clone(),
|
||||||
|
value.my_vote,
|
||||||
|
))
|
||||||
|
.detach();
|
||||||
|
|
||||||
Self { comment: value, creator_image, community_image, voting_row }
|
Self {
|
||||||
|
comment: value,
|
||||||
|
creator_image,
|
||||||
|
community_image,
|
||||||
|
voting_row,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_widgets(
|
fn init_widgets(
|
||||||
|
@ -144,7 +158,9 @@ impl FactoryComponent for MentionRow {
|
||||||
sender.output(crate::AppMsg::OpenPost(self.comment.post.id.clone()));
|
sender.output(crate::AppMsg::OpenPost(self.comment.post.id.clone()));
|
||||||
}
|
}
|
||||||
MentionRowMsg::OpenCommunity => {
|
MentionRowMsg::OpenCommunity => {
|
||||||
sender.output(crate::AppMsg::OpenCommunity(self.comment.community.id.clone()));
|
sender.output(crate::AppMsg::OpenCommunity(
|
||||||
|
self.comment.community.id.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
pub mod post_row;
|
|
||||||
pub mod community_row;
|
|
||||||
pub mod profile_page;
|
|
||||||
pub mod community_page;
|
|
||||||
pub mod post_page;
|
|
||||||
pub mod comment_row;
|
pub mod comment_row;
|
||||||
pub mod voting_row;
|
pub mod community_page;
|
||||||
|
pub mod community_row;
|
||||||
pub mod inbox_page;
|
pub mod inbox_page;
|
||||||
pub mod mention_row;
|
pub mod mention_row;
|
||||||
|
pub mod post_page;
|
||||||
|
pub mod post_row;
|
||||||
|
pub mod profile_page;
|
||||||
|
pub mod voting_row;
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
use lemmy_api_common::{lemmy_db_views::structs::{CommentView, PostView}, post::GetPostResponse};
|
|
||||||
use relm4::{prelude::*, factory::FactoryVecDeque, MessageBroker};
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use lemmy_api_common::{
|
||||||
|
lemmy_db_views::structs::{CommentView, PostView},
|
||||||
|
post::GetPostResponse,
|
||||||
|
};
|
||||||
|
use relm4::{factory::FactoryVecDeque, prelude::*, MessageBroker};
|
||||||
use relm4_components::web_image::WebImage;
|
use relm4_components::web_image::WebImage;
|
||||||
|
|
||||||
use crate::{api, util::{get_web_image_msg, get_web_image_url, markdown_to_pango_markup}, dialogs::editor::{EditorDialog, EditorOutput, DialogMsg, EditorType, EditorData}, settings};
|
use crate::{
|
||||||
|
api,
|
||||||
|
dialogs::editor::{DialogMsg, EditorData, EditorDialog, EditorOutput, EditorType},
|
||||||
|
settings,
|
||||||
|
util::{get_web_image_msg, get_web_image_url, markdown_to_pango_markup},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{comment_row::CommentRow, voting_row::{VotingRowModel, VotingStats, VotingRowInput}};
|
use super::{
|
||||||
|
comment_row::CommentRow,
|
||||||
|
voting_row::{VotingRowInput, VotingRowModel, VotingStats},
|
||||||
|
};
|
||||||
|
|
||||||
pub static POST_PAGE_BROKER: MessageBroker<DialogMsg> = MessageBroker::new();
|
pub static POST_PAGE_BROKER: MessageBroker<DialogMsg> = MessageBroker::new();
|
||||||
|
|
||||||
|
@ -17,7 +28,7 @@ pub struct PostPage {
|
||||||
comments: FactoryVecDeque<CommentRow>,
|
comments: FactoryVecDeque<CommentRow>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
create_comment_dialog: Controller<EditorDialog>,
|
create_comment_dialog: Controller<EditorDialog>,
|
||||||
voting_row: Controller<VotingRowModel>
|
voting_row: Controller<VotingRowModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -200,11 +211,21 @@ impl SimpleComponent for PostPage {
|
||||||
EditorOutput::CreateRequest(comment, _) => PostInput::CreateCommentRequest(comment),
|
EditorOutput::CreateRequest(comment, _) => PostInput::CreateCommentRequest(comment),
|
||||||
EditorOutput::EditRequest(post, type_) => match type_ {
|
EditorOutput::EditRequest(post, type_) => match type_ {
|
||||||
EditorType::Post => PostInput::EditPostRequest(post),
|
EditorType::Post => PostInput::EditPostRequest(post),
|
||||||
EditorType::Comment => PostInput::EditCommentRequest(post)
|
EditorType::Comment => PostInput::EditCommentRequest(post),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
let voting_row = VotingRowModel::builder().launch(VotingStats::default()).detach();
|
let voting_row = VotingRowModel::builder()
|
||||||
let model = PostPage { info: init, image, comments, creator_avatar, community_avatar, create_comment_dialog: dialog, voting_row };
|
.launch(VotingStats::default())
|
||||||
|
.detach();
|
||||||
|
let model = PostPage {
|
||||||
|
info: init,
|
||||||
|
image,
|
||||||
|
comments,
|
||||||
|
creator_avatar,
|
||||||
|
community_avatar,
|
||||||
|
create_comment_dialog: dialog,
|
||||||
|
voting_row,
|
||||||
|
};
|
||||||
|
|
||||||
let image = model.image.widget();
|
let image = model.image.widget();
|
||||||
let comments = model.comments.widget();
|
let comments = model.comments.widget();
|
||||||
|
@ -221,15 +242,24 @@ impl SimpleComponent for PostPage {
|
||||||
PostInput::UpdatePost(post) => {
|
PostInput::UpdatePost(post) => {
|
||||||
self.info = post.clone();
|
self.info = post.clone();
|
||||||
|
|
||||||
self.image.emit(get_web_image_msg(post.post_view.post.thumbnail_url));
|
self.image
|
||||||
self.community_avatar.emit(get_web_image_msg(post.community_view.community.icon));
|
.emit(get_web_image_msg(post.post_view.post.thumbnail_url));
|
||||||
self.creator_avatar.emit(get_web_image_msg(post.post_view.creator.avatar));
|
self.community_avatar
|
||||||
|
.emit(get_web_image_msg(post.community_view.community.icon));
|
||||||
|
self.creator_avatar
|
||||||
|
.emit(get_web_image_msg(post.post_view.creator.avatar));
|
||||||
|
|
||||||
self.voting_row.emit(VotingRowInput::UpdateStats(VotingStats::from_post(post.post_view.counts.clone(), post.post_view.my_vote)));
|
self.voting_row
|
||||||
|
.emit(VotingRowInput::UpdateStats(VotingStats::from_post(
|
||||||
|
post.post_view.counts.clone(),
|
||||||
|
post.post_view.my_vote,
|
||||||
|
)));
|
||||||
self.comments.guard().clear();
|
self.comments.guard().clear();
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
if post.post_view.counts.comments == 0 { return; }
|
if post.post_view.counts.comments == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let comments = api::post::get_comments(post.post_view.post.id);
|
let comments = api::post::get_comments(post.post_view.post.id);
|
||||||
if let Ok(comments) = comments {
|
if let Ok(comments) = comments {
|
||||||
sender.input(PostInput::DoneFetchComments(comments));
|
sender.input(PostInput::DoneFetchComments(comments));
|
||||||
|
@ -258,7 +288,9 @@ impl SimpleComponent for PostPage {
|
||||||
if link.is_empty() {
|
if link.is_empty() {
|
||||||
link = get_web_image_url(post.embed_video_url);
|
link = get_web_image_url(post.embed_video_url);
|
||||||
}
|
}
|
||||||
if link.is_empty() { return; }
|
if link.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
gtk::show_uri(None::<&relm4::gtk::Window>, &link, 0);
|
gtk::show_uri(None::<&relm4::gtk::Window>, &link, 0);
|
||||||
}
|
}
|
||||||
PostInput::OpenCreateCommentDialog => {
|
PostInput::OpenCreateCommentDialog => {
|
||||||
|
@ -273,9 +305,14 @@ impl SimpleComponent for PostPage {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::comment::create_comment(id, post.body, None) {
|
let message = match api::comment::create_comment(id, post.body, None) {
|
||||||
Ok(comment) => Some(PostInput::CreatedComment(comment.comment_view)),
|
Ok(comment) => Some(PostInput::CreatedComment(comment.comment_view)),
|
||||||
Err(err) => { println!("{}", err.to_string()); None }
|
Err(err) => {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(message) = message {
|
||||||
|
sender.input(message)
|
||||||
};
|
};
|
||||||
if let Some(message) = message { sender.input(message) };
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
PostInput::DeletePost => {
|
PostInput::DeletePost => {
|
||||||
|
@ -288,11 +325,17 @@ impl SimpleComponent for PostPage {
|
||||||
PostInput::OpenEditPostDialog => {
|
PostInput::OpenEditPostDialog => {
|
||||||
let url = match self.info.post_view.post.url.clone() {
|
let url = match self.info.post_view.post.url.clone() {
|
||||||
Some(url) => url.to_string(),
|
Some(url) => url.to_string(),
|
||||||
None => String::from("")
|
None => String::from(""),
|
||||||
};
|
};
|
||||||
let data = EditorData {
|
let data = EditorData {
|
||||||
name: self.info.post_view.post.name.clone(),
|
name: self.info.post_view.post.name.clone(),
|
||||||
body: self.info.post_view.post.body.clone().unwrap_or(String::from("")),
|
body: self
|
||||||
|
.info
|
||||||
|
.post_view
|
||||||
|
.post
|
||||||
|
.body
|
||||||
|
.clone()
|
||||||
|
.unwrap_or(String::from("")),
|
||||||
url: reqwest::Url::parse(&url).ok(),
|
url: reqwest::Url::parse(&url).ok(),
|
||||||
id: None,
|
id: None,
|
||||||
};
|
};
|
||||||
|
@ -305,9 +348,14 @@ impl SimpleComponent for PostPage {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::post::edit_post(post.name, post.url, post.body, id) {
|
let message = match api::post::edit_post(post.name, post.url, post.body, id) {
|
||||||
Ok(post) => Some(PostInput::DoneEditPost(post.post_view)),
|
Ok(post) => Some(PostInput::DoneEditPost(post.post_view)),
|
||||||
Err(err) => { println!("{}", err.to_string()); None }
|
Err(err) => {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(message) = message {
|
||||||
|
sender.input(message)
|
||||||
};
|
};
|
||||||
if let Some(message) = message { sender.input(message) };
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
PostInput::DoneEditPost(post) => {
|
PostInput::DoneEditPost(post) => {
|
||||||
|
@ -322,9 +370,14 @@ impl SimpleComponent for PostPage {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::comment::edit_comment(data.body, data.id.unwrap()) {
|
let message = match api::comment::edit_comment(data.body, data.id.unwrap()) {
|
||||||
Ok(comment) => Some(PostInput::UpdateComment(comment.comment_view)),
|
Ok(comment) => Some(PostInput::UpdateComment(comment.comment_view)),
|
||||||
Err(err) => { println!("{}", err.to_string()); None }
|
Err(err) => {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(message) = message {
|
||||||
|
sender.input(message)
|
||||||
};
|
};
|
||||||
if let Some(message) = message { sender.input(message) };
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
PostInput::UpdateComment(comment) => {
|
PostInput::UpdateComment(comment) => {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
use gtk::prelude::*;
|
||||||
use lemmy_api_common::lemmy_db_views::structs::PostView;
|
use lemmy_api_common::lemmy_db_views::structs::PostView;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
use gtk::prelude::*;
|
|
||||||
use relm4_components::web_image::WebImage;
|
use relm4_components::web_image::WebImage;
|
||||||
|
|
||||||
use crate::{util::get_web_image_url, api};
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
use crate::{api, util::get_web_image_url};
|
||||||
|
|
||||||
use super::voting_row::{VotingRowModel, VotingStats};
|
use super::voting_row::{VotingRowModel, VotingStats};
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ pub struct PostRow {
|
||||||
post: PostView,
|
post: PostView,
|
||||||
author_image: Controller<WebImage>,
|
author_image: Controller<WebImage>,
|
||||||
community_image: Controller<WebImage>,
|
community_image: Controller<WebImage>,
|
||||||
voting_row: Controller<VotingRowModel>
|
voting_row: Controller<VotingRowModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -21,7 +21,7 @@ pub enum PostViewMsg {
|
||||||
OpenPost,
|
OpenPost,
|
||||||
OpenCommunity,
|
OpenCommunity,
|
||||||
OpenPerson,
|
OpenPerson,
|
||||||
DeletePost
|
DeletePost,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[relm4::factory(pub)]
|
#[relm4::factory(pub)]
|
||||||
|
@ -123,14 +123,27 @@ impl FactoryComponent for PostRow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forward_to_parent(output: Self::Output) -> Option<Self::ParentInput> { Some(output) }
|
fn forward_to_parent(output: Self::Output) -> Option<Self::ParentInput> {
|
||||||
|
Some(output)
|
||||||
|
}
|
||||||
|
|
||||||
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
fn init_model(value: Self::Init, _index: &DynamicIndex, _sender: FactorySender<Self>) -> Self {
|
||||||
let author_image= WebImage::builder().launch(get_web_image_url(value.creator.avatar.clone())).detach();
|
let author_image = WebImage::builder()
|
||||||
let community_image= WebImage::builder().launch(get_web_image_url(value.community.icon.clone())).detach();
|
.launch(get_web_image_url(value.creator.avatar.clone()))
|
||||||
let voting_row = VotingRowModel::builder().launch(VotingStats::from_post(value.counts.clone(), value.my_vote)).detach();
|
.detach();
|
||||||
|
let community_image = WebImage::builder()
|
||||||
|
.launch(get_web_image_url(value.community.icon.clone()))
|
||||||
|
.detach();
|
||||||
|
let voting_row = VotingRowModel::builder()
|
||||||
|
.launch(VotingStats::from_post(value.counts.clone(), value.my_vote))
|
||||||
|
.detach();
|
||||||
|
|
||||||
Self { post: value, author_image, community_image, voting_row }
|
Self {
|
||||||
|
post: value,
|
||||||
|
author_image,
|
||||||
|
community_image,
|
||||||
|
voting_row,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_widgets(
|
fn init_widgets(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use lemmy_api_common::person::GetPersonDetailsResponse;
|
|
||||||
use relm4::{prelude::*, factory::FactoryVecDeque};
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use lemmy_api_common::person::GetPersonDetailsResponse;
|
||||||
|
use relm4::{factory::FactoryVecDeque, prelude::*};
|
||||||
use relm4_components::web_image::WebImage;
|
use relm4_components::web_image::WebImage;
|
||||||
|
|
||||||
use crate::util::get_web_image_msg;
|
use crate::util::get_web_image_msg;
|
||||||
|
@ -11,7 +11,7 @@ use super::post_row::PostRow;
|
||||||
pub struct ProfilePage {
|
pub struct ProfilePage {
|
||||||
info: GetPersonDetailsResponse,
|
info: GetPersonDetailsResponse,
|
||||||
avatar: Controller<WebImage>,
|
avatar: Controller<WebImage>,
|
||||||
posts: FactoryVecDeque<PostRow>
|
posts: FactoryVecDeque<PostRow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -84,7 +84,11 @@ impl SimpleComponent for ProfilePage {
|
||||||
) -> relm4::ComponentParts<Self> {
|
) -> relm4::ComponentParts<Self> {
|
||||||
let avatar = WebImage::builder().launch("".to_string()).detach();
|
let avatar = WebImage::builder().launch("".to_string()).detach();
|
||||||
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender());
|
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.output_sender());
|
||||||
let model = ProfilePage { info: init, avatar, posts };
|
let model = ProfilePage {
|
||||||
|
info: init,
|
||||||
|
avatar,
|
||||||
|
posts,
|
||||||
|
};
|
||||||
let avatar = model.avatar.widget();
|
let avatar = model.avatar.widget();
|
||||||
let posts = model.posts.widget();
|
let posts = model.posts.widget();
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
@ -96,7 +100,8 @@ impl SimpleComponent for ProfilePage {
|
||||||
match message {
|
match message {
|
||||||
ProfileInput::UpdatePerson(person) => {
|
ProfileInput::UpdatePerson(person) => {
|
||||||
self.info = person.clone();
|
self.info = person.clone();
|
||||||
self.avatar.emit(get_web_image_msg(person.person_view.person.avatar));
|
self.avatar
|
||||||
|
.emit(get_web_image_msg(person.person_view.person.avatar));
|
||||||
self.posts.guard().clear();
|
self.posts.guard().clear();
|
||||||
for post in person.posts {
|
for post in person.posts {
|
||||||
self.posts.guard().push_back(post);
|
self.posts.guard().push_back(post);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use lemmy_api_common::{lemmy_db_schema::{aggregates::structs::{PostAggregates, CommentAggregates}, newtypes::{PostId, CommentId}}};
|
|
||||||
use relm4::{SimpleComponent, ComponentParts, gtk};
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use lemmy_api_common::lemmy_db_schema::{
|
||||||
|
aggregates::structs::{CommentAggregates, PostAggregates},
|
||||||
|
newtypes::{CommentId, PostId},
|
||||||
|
};
|
||||||
|
use relm4::{gtk, ComponentParts, SimpleComponent};
|
||||||
|
|
||||||
use crate::{api, settings};
|
use crate::{api, settings};
|
||||||
|
|
||||||
|
@ -15,7 +18,7 @@ pub struct VotingStats {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
id: i32,
|
id: i32,
|
||||||
post_id: Option<i32>,
|
post_id: Option<i32>,
|
||||||
comment_id: Option<i32>
|
comment_id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VotingStats {
|
impl VotingStats {
|
||||||
|
@ -46,7 +49,7 @@ impl VotingStats {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VotingRowModel {
|
pub struct VotingRowModel {
|
||||||
stats: VotingStats
|
stats: VotingStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -56,9 +59,7 @@ pub enum VotingRowInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum VotingRowOutput {
|
pub enum VotingRowOutput {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[relm4::component(pub)]
|
#[relm4::component(pub)]
|
||||||
impl SimpleComponent for VotingRowModel {
|
impl SimpleComponent for VotingRowModel {
|
||||||
|
@ -105,24 +106,52 @@ impl SimpleComponent for VotingRowModel {
|
||||||
match message {
|
match message {
|
||||||
VotingRowInput::Vote(vote) => {
|
VotingRowInput::Vote(vote) => {
|
||||||
let mut score = self.stats.own_vote.unwrap_or(0) + vote;
|
let mut score = self.stats.own_vote.unwrap_or(0) + vote;
|
||||||
if score < -1 || score > 1 { score = 0 };
|
if score < -1 || score > 1 {
|
||||||
if settings::get_current_account().jwt.is_none() { return; }
|
score = 0
|
||||||
|
};
|
||||||
|
if settings::get_current_account().jwt.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let stats = self.stats.clone();
|
let stats = self.stats.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let info = if stats.post_id.is_some() {
|
let info = if stats.post_id.is_some() {
|
||||||
let response = api::post::like_post(PostId { 0: stats.post_id.unwrap() }, score);
|
let response = api::post::like_post(
|
||||||
|
PostId {
|
||||||
|
0: stats.post_id.unwrap(),
|
||||||
|
},
|
||||||
|
score,
|
||||||
|
);
|
||||||
match response {
|
match response {
|
||||||
Ok(post) => Some(VotingStats::from_post(post.post_view.counts, post.post_view.my_vote)),
|
Ok(post) => Some(VotingStats::from_post(
|
||||||
Err(err) => { println!("{}", err.to_string()); None }
|
post.post_view.counts,
|
||||||
|
post.post_view.my_vote,
|
||||||
|
)),
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let response = api::comment::like_comment(CommentId { 0: stats.comment_id.unwrap() }, score);
|
let response = api::comment::like_comment(
|
||||||
|
CommentId {
|
||||||
|
0: stats.comment_id.unwrap(),
|
||||||
|
},
|
||||||
|
score,
|
||||||
|
);
|
||||||
match response {
|
match response {
|
||||||
Ok(comment) => Some(VotingStats::from_comment(comment.comment_view.counts, comment.comment_view.my_vote)),
|
Ok(comment) => Some(VotingStats::from_comment(
|
||||||
Err(err) => { println!("{}", err.to_string()); None }
|
comment.comment_view.counts,
|
||||||
|
comment.comment_view.my_vote,
|
||||||
|
)),
|
||||||
|
Err(err) => {
|
||||||
|
println!("{}", err.to_string());
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(info) = info { sender.input(VotingRowInput::UpdateStats(info)) };
|
if let Some(info) = info {
|
||||||
|
sender.input(VotingRowInput::UpdateStats(info))
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
VotingRowInput::UpdateStats(stats) => {
|
VotingRowInput::UpdateStats(stats) => {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use relm4::{prelude::*, gtk::{ResponseType, FileFilter}};
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use relm4::{
|
||||||
|
gtk::{FileFilter, ResponseType},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
|
|
||||||
|
@ -8,7 +11,7 @@ pub struct EditorData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub body: String,
|
pub body: String,
|
||||||
pub url: Option<reqwest::Url>,
|
pub url: Option<reqwest::Url>,
|
||||||
pub id: Option<i32>
|
pub id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EditorDialog {
|
pub struct EditorDialog {
|
||||||
|
@ -20,13 +23,13 @@ pub struct EditorDialog {
|
||||||
body_buffer: gtk::TextBuffer,
|
body_buffer: gtk::TextBuffer,
|
||||||
// Optional field to temporarily store the post or comment id
|
// Optional field to temporarily store the post or comment id
|
||||||
id: Option<i32>,
|
id: Option<i32>,
|
||||||
window: gtk::Window
|
window: gtk::Window,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum EditorType {
|
pub enum EditorType {
|
||||||
Post,
|
Post,
|
||||||
Comment
|
Comment,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -38,13 +41,13 @@ pub enum DialogMsg {
|
||||||
Okay,
|
Okay,
|
||||||
ChooseImage,
|
ChooseImage,
|
||||||
UploadImage(std::path::PathBuf),
|
UploadImage(std::path::PathBuf),
|
||||||
AppendBody(String)
|
AppendBody(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum EditorOutput {
|
pub enum EditorOutput {
|
||||||
CreateRequest(EditorData, EditorType),
|
CreateRequest(EditorData, EditorType),
|
||||||
EditRequest(EditorData, EditorType)
|
EditRequest(EditorData, EditorType),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[relm4::component(pub)]
|
#[relm4::component(pub)]
|
||||||
|
@ -151,7 +154,16 @@ impl SimpleComponent for EditorDialog {
|
||||||
let url_buffer = gtk::EntryBuffer::builder().build();
|
let url_buffer = gtk::EntryBuffer::builder().build();
|
||||||
let body_buffer = gtk::TextBuffer::builder().build();
|
let body_buffer = gtk::TextBuffer::builder().build();
|
||||||
let window = root.toplevel_window().unwrap();
|
let window = root.toplevel_window().unwrap();
|
||||||
let model = EditorDialog { type_: init, visible: false, is_new: true, name_buffer, url_buffer, body_buffer, id: None, window };
|
let model = EditorDialog {
|
||||||
|
type_: init,
|
||||||
|
visible: false,
|
||||||
|
is_new: true,
|
||||||
|
name_buffer,
|
||||||
|
url_buffer,
|
||||||
|
body_buffer,
|
||||||
|
id: None,
|
||||||
|
window,
|
||||||
|
};
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
}
|
}
|
||||||
|
@ -164,17 +176,22 @@ impl SimpleComponent for EditorDialog {
|
||||||
self.url_buffer.set_text("");
|
self.url_buffer.set_text("");
|
||||||
self.body_buffer.set_text("");
|
self.body_buffer.set_text("");
|
||||||
self.visible = false;
|
self.visible = false;
|
||||||
},
|
}
|
||||||
DialogMsg::Okay => {
|
DialogMsg::Okay => {
|
||||||
let name = self.name_buffer.text().to_string();
|
let name = self.name_buffer.text().to_string();
|
||||||
let url = self.url_buffer.text().to_string();
|
let url = self.url_buffer.text().to_string();
|
||||||
let (start, end) = &self.body_buffer.bounds();
|
let (start, end) = &self.body_buffer.bounds();
|
||||||
let body = self.body_buffer.text(start, end, true).to_string();
|
let body = self.body_buffer.text(start, end, true).to_string();
|
||||||
let url = reqwest::Url::parse(&url).ok();
|
let url = reqwest::Url::parse(&url).ok();
|
||||||
let post = EditorData { name, body, url, id: self.id };
|
let post = EditorData {
|
||||||
|
name,
|
||||||
|
body,
|
||||||
|
url,
|
||||||
|
id: self.id,
|
||||||
|
};
|
||||||
let message = match self.is_new {
|
let message = match self.is_new {
|
||||||
true => EditorOutput::CreateRequest(post, self.type_),
|
true => EditorOutput::CreateRequest(post, self.type_),
|
||||||
false => EditorOutput::EditRequest(post, self.type_)
|
false => EditorOutput::EditRequest(post, self.type_),
|
||||||
};
|
};
|
||||||
let _ = sender.output(message);
|
let _ = sender.output(message);
|
||||||
self.visible = false;
|
self.visible = false;
|
||||||
|
@ -185,22 +202,32 @@ impl SimpleComponent for EditorDialog {
|
||||||
}
|
}
|
||||||
DialogMsg::UpdateData(data) => {
|
DialogMsg::UpdateData(data) => {
|
||||||
self.name_buffer.set_text(data.name);
|
self.name_buffer.set_text(data.name);
|
||||||
if let Some(url) = data.url { self.url_buffer.set_text(url.to_string()); }
|
if let Some(url) = data.url {
|
||||||
|
self.url_buffer.set_text(url.to_string());
|
||||||
|
}
|
||||||
self.body_buffer.set_text(&data.body.clone());
|
self.body_buffer.set_text(&data.body.clone());
|
||||||
}
|
}
|
||||||
DialogMsg::ChooseImage => {
|
DialogMsg::ChooseImage => {
|
||||||
let buttons = [("_Cancel", ResponseType::Cancel), ("_Okay", ResponseType::Accept)];
|
let buttons = [
|
||||||
let dialog = gtk::FileChooserDialog::new(Some("Upload image"), None::<>k::ApplicationWindow>, gtk::FileChooserAction::Open, &buttons);
|
("_Cancel", ResponseType::Cancel),
|
||||||
|
("_Okay", ResponseType::Accept),
|
||||||
|
];
|
||||||
|
let dialog = gtk::FileChooserDialog::new(
|
||||||
|
Some("Upload image"),
|
||||||
|
None::<>k::ApplicationWindow>,
|
||||||
|
gtk::FileChooserAction::Open,
|
||||||
|
&buttons,
|
||||||
|
);
|
||||||
dialog.set_transient_for(Some(&self.window));
|
dialog.set_transient_for(Some(&self.window));
|
||||||
let image_filter = FileFilter::new();
|
let image_filter = FileFilter::new();
|
||||||
image_filter.add_pattern("image/*");
|
image_filter.add_pattern("image/*");
|
||||||
dialog.add_filter(&image_filter);
|
dialog.add_filter(&image_filter);
|
||||||
dialog.run_async(move |dialog, result | {
|
dialog.run_async(move |dialog, result| {
|
||||||
match result {
|
match result {
|
||||||
ResponseType::Accept => {
|
ResponseType::Accept => {
|
||||||
let path = dialog.file().unwrap().path();
|
let path = dialog.file().unwrap().path();
|
||||||
sender.input(DialogMsg::UploadImage(path.unwrap()))
|
sender.input(DialogMsg::UploadImage(path.unwrap()))
|
||||||
},
|
}
|
||||||
_ => dialog.hide(),
|
_ => dialog.hide(),
|
||||||
}
|
}
|
||||||
dialog.destroy();
|
dialog.destroy();
|
||||||
|
@ -217,7 +244,8 @@ impl SimpleComponent for EditorDialog {
|
||||||
DialogMsg::AppendBody(new_text) => {
|
DialogMsg::AppendBody(new_text) => {
|
||||||
let (start, end) = &self.body_buffer.bounds();
|
let (start, end) = &self.body_buffer.bounds();
|
||||||
let body = self.body_buffer.text(start, end, true).to_string();
|
let body = self.body_buffer.text(start, end, true).to_string();
|
||||||
self.body_buffer.set_text(&format!("{}\n{}", body, new_text));
|
self.body_buffer
|
||||||
|
.set_text(&format!("{}\n{}", body, new_text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
176
src/main.rs
176
src/main.rs
|
@ -1,18 +1,39 @@
|
||||||
pub mod settings;
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod util;
|
pub mod config;
|
||||||
pub mod dialogs;
|
pub mod dialogs;
|
||||||
|
pub mod settings;
|
||||||
|
pub mod util;
|
||||||
|
|
||||||
use api::{user::default_person, community::default_community, post::default_post};
|
use api::{community::default_community, post::default_post, user::default_person};
|
||||||
use components::{post_row::PostRow, community_row::CommunityRow, profile_page::{ProfilePage, self}, community_page::{CommunityPage, self}, post_page::{PostPage, self}, inbox_page::{InboxPage, InboxInput}};
|
use components::{
|
||||||
|
community_page::{self, CommunityPage},
|
||||||
|
community_row::CommunityRow,
|
||||||
|
inbox_page::{InboxInput, InboxPage},
|
||||||
|
post_page::{self, PostPage},
|
||||||
|
post_row::PostRow,
|
||||||
|
profile_page::{self, ProfilePage},
|
||||||
|
};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use lemmy_api_common::{lemmy_db_views_actor::structs::CommunityView, lemmy_db_views::structs::PostView, person::GetPersonDetailsResponse, lemmy_db_schema::{newtypes::{PostId, CommunityId, PersonId}, ListingType}, post::GetPostResponse, community::GetCommunityResponse};
|
use lemmy_api_common::{
|
||||||
use relm4::{prelude::*, factory::FactoryVecDeque, set_global_css, actions::{RelmAction, RelmActionGroup}};
|
community::GetCommunityResponse,
|
||||||
|
lemmy_db_schema::{
|
||||||
|
newtypes::{CommunityId, PersonId, PostId},
|
||||||
|
ListingType,
|
||||||
|
},
|
||||||
|
lemmy_db_views::structs::PostView,
|
||||||
|
lemmy_db_views_actor::structs::CommunityView,
|
||||||
|
person::GetPersonDetailsResponse,
|
||||||
|
post::GetPostResponse,
|
||||||
|
};
|
||||||
|
use relm4::{
|
||||||
|
actions::{RelmAction, RelmActionGroup},
|
||||||
|
factory::FactoryVecDeque,
|
||||||
|
prelude::*,
|
||||||
|
set_global_css,
|
||||||
|
};
|
||||||
use settings::get_current_account;
|
use settings::get_current_account;
|
||||||
|
|
||||||
static APP_ID: &str = "com.lemmy-gtk.lemoa";
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum AppState {
|
enum AppState {
|
||||||
Loading,
|
Loading,
|
||||||
|
@ -24,7 +45,7 @@ enum AppState {
|
||||||
Post,
|
Post,
|
||||||
Login,
|
Login,
|
||||||
Message,
|
Message,
|
||||||
Inbox
|
Inbox,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
|
@ -65,7 +86,7 @@ pub enum AppMsg {
|
||||||
OpenPost(PostId),
|
OpenPost(PostId),
|
||||||
DoneFetchPost(GetPostResponse),
|
DoneFetchPost(GetPostResponse),
|
||||||
OpenInbox,
|
OpenInbox,
|
||||||
PopBackStack
|
PopBackStack,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[relm4::component]
|
#[relm4::component]
|
||||||
|
@ -322,22 +343,52 @@ impl SimpleComponent for App {
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
let current_account = settings::get_current_account();
|
let current_account = settings::get_current_account();
|
||||||
let state = if current_account.instance_url.is_empty() { AppState::ChooseInstance } else { AppState::Loading };
|
let state = if current_account.instance_url.is_empty() {
|
||||||
|
AppState::ChooseInstance
|
||||||
|
} else {
|
||||||
|
AppState::Loading
|
||||||
|
};
|
||||||
let logged_in = current_account.jwt.is_some();
|
let logged_in = current_account.jwt.is_some();
|
||||||
|
|
||||||
// initialize all controllers and factories
|
// initialize all controllers and factories
|
||||||
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
|
let posts = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
|
||||||
let communities = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
|
let communities = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
|
||||||
let profile_page = ProfilePage::builder().launch(default_person()).forward(sender.input_sender(), |msg| msg);
|
let profile_page = ProfilePage::builder()
|
||||||
let community_page = CommunityPage::builder().launch(default_community().community_view).forward(sender.input_sender(), |msg| msg);
|
.launch(default_person())
|
||||||
let post_page = PostPage::builder().launch(default_post()).forward(sender.input_sender(), |msg| msg);
|
.forward(sender.input_sender(), |msg| msg);
|
||||||
let inbox_page = InboxPage::builder().launch(()).forward(sender.input_sender(), |msg| msg);
|
let community_page = CommunityPage::builder()
|
||||||
|
.launch(default_community().community_view)
|
||||||
|
.forward(sender.input_sender(), |msg| msg);
|
||||||
|
let post_page = PostPage::builder()
|
||||||
|
.launch(default_post())
|
||||||
|
.forward(sender.input_sender(), |msg| msg);
|
||||||
|
let inbox_page = InboxPage::builder()
|
||||||
|
.launch(())
|
||||||
|
.forward(sender.input_sender(), |msg| msg);
|
||||||
let community_search_buffer = gtk::EntryBuffer::builder().build();
|
let community_search_buffer = gtk::EntryBuffer::builder().build();
|
||||||
|
|
||||||
let model = App { state, back_queue: vec![], logged_in, posts, communities, profile_page, community_page, post_page, inbox_page, message: None, current_communities_type: None, current_posts_type: None, current_communities_page: 1, current_posts_page: 1, community_search_buffer };
|
let model = App {
|
||||||
|
state,
|
||||||
|
back_queue: vec![],
|
||||||
|
logged_in,
|
||||||
|
posts,
|
||||||
|
communities,
|
||||||
|
profile_page,
|
||||||
|
community_page,
|
||||||
|
post_page,
|
||||||
|
inbox_page,
|
||||||
|
message: None,
|
||||||
|
current_communities_type: None,
|
||||||
|
current_posts_type: None,
|
||||||
|
current_communities_page: 1,
|
||||||
|
current_posts_page: 1,
|
||||||
|
community_search_buffer,
|
||||||
|
};
|
||||||
|
|
||||||
// fetch posts if that's the initial page
|
// fetch posts if that's the initial page
|
||||||
if !current_account.instance_url.is_empty() { sender.input(AppMsg::StartFetchPosts(None, true)) };
|
if !current_account.instance_url.is_empty() {
|
||||||
|
sender.input(AppMsg::StartFetchPosts(None, true))
|
||||||
|
};
|
||||||
|
|
||||||
// setup all widgets and different stack pages
|
// setup all widgets and different stack pages
|
||||||
let posts_box = model.posts.widget();
|
let posts_box = model.posts.widget();
|
||||||
|
@ -351,13 +402,16 @@ impl SimpleComponent for App {
|
||||||
|
|
||||||
// create the header bar menu and its actions
|
// create the header bar menu and its actions
|
||||||
let instance_sender = sender.clone();
|
let instance_sender = sender.clone();
|
||||||
let instance_action: RelmAction<ChangeInstanceAction> = RelmAction::new_stateless(move |_| {
|
let instance_action: RelmAction<ChangeInstanceAction> =
|
||||||
|
RelmAction::new_stateless(move |_| {
|
||||||
instance_sender.input(AppMsg::ChooseInstance);
|
instance_sender.input(AppMsg::ChooseInstance);
|
||||||
});
|
});
|
||||||
let profile_sender = sender.clone();
|
let profile_sender = sender.clone();
|
||||||
let profile_action: RelmAction<ProfileAction> = RelmAction::new_stateless(move |_| {
|
let profile_action: RelmAction<ProfileAction> = RelmAction::new_stateless(move |_| {
|
||||||
let person = settings::get_current_account();
|
let person = settings::get_current_account();
|
||||||
if !person.name.is_empty() { profile_sender.input(AppMsg::OpenPerson(PersonId(person.id))); }
|
if !person.name.is_empty() {
|
||||||
|
profile_sender.input(AppMsg::OpenPerson(PersonId(person.id)));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
let login_sender = sender.clone();
|
let login_sender = sender.clone();
|
||||||
let login_action: RelmAction<LoginAction> = RelmAction::new_stateless(move |_| {
|
let login_action: RelmAction<LoginAction> = RelmAction::new_stateless(move |_| {
|
||||||
|
@ -380,15 +434,20 @@ impl SimpleComponent for App {
|
||||||
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
|
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
|
||||||
// save the back queue
|
// save the back queue
|
||||||
match msg {
|
match msg {
|
||||||
AppMsg::DoneFetchCommunities(_) | AppMsg::DoneFetchCommunity(_) | AppMsg::DoneFetchPerson(_) | AppMsg::DoneFetchPost(_) | AppMsg::DoneFetchPosts(_) | AppMsg::ShowMessage(_) => {
|
AppMsg::DoneFetchCommunities(_)
|
||||||
self.back_queue.push(msg.clone())
|
| AppMsg::DoneFetchCommunity(_)
|
||||||
}
|
| AppMsg::DoneFetchPerson(_)
|
||||||
|
| AppMsg::DoneFetchPost(_)
|
||||||
|
| AppMsg::DoneFetchPosts(_)
|
||||||
|
| AppMsg::ShowMessage(_) => self.back_queue.push(msg.clone()),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
AppMsg::DoneChoosingInstance(instance_url) => {
|
AppMsg::DoneChoosingInstance(instance_url) => {
|
||||||
if instance_url.trim().is_empty() { return; }
|
if instance_url.trim().is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let mut current_account = settings::get_current_account();
|
let mut current_account = settings::get_current_account();
|
||||||
current_account.instance_url = instance_url;
|
current_account.instance_url = instance_url;
|
||||||
settings::update_current_account(current_account);
|
settings::update_current_account(current_account);
|
||||||
|
@ -400,41 +459,58 @@ impl SimpleComponent for App {
|
||||||
}
|
}
|
||||||
AppMsg::StartFetchPosts(type_, remove_previous) => {
|
AppMsg::StartFetchPosts(type_, remove_previous) => {
|
||||||
self.current_posts_type = type_;
|
self.current_posts_type = type_;
|
||||||
let page = if remove_previous { 1 } else { self.current_posts_page + 1 };
|
let page = if remove_previous {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
self.current_posts_page + 1
|
||||||
|
};
|
||||||
self.current_posts_page = page;
|
self.current_posts_page = page;
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::posts::list_posts(page, None, type_) {
|
let message = match api::posts::list_posts(page, None, type_) {
|
||||||
Ok(posts) => AppMsg::DoneFetchPosts(posts),
|
Ok(posts) => AppMsg::DoneFetchPosts(posts),
|
||||||
Err(err) => AppMsg::ShowMessage(err.to_string())
|
Err(err) => AppMsg::ShowMessage(err.to_string()),
|
||||||
};
|
};
|
||||||
sender.input(message);
|
sender.input(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AppMsg::DoneFetchPosts(posts) => {
|
AppMsg::DoneFetchPosts(posts) => {
|
||||||
self.state = AppState::Posts;
|
self.state = AppState::Posts;
|
||||||
if self.current_posts_page == 1 { self.posts.guard().clear(); }
|
if self.current_posts_page == 1 {
|
||||||
|
self.posts.guard().clear();
|
||||||
|
}
|
||||||
for post in posts {
|
for post in posts {
|
||||||
self.posts.guard().push_back(post);
|
self.posts.guard().push_back(post);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AppMsg::FetchCommunities(listing_type, remove_previous) => {
|
AppMsg::FetchCommunities(listing_type, remove_previous) => {
|
||||||
let query_text = self.community_search_buffer.text().as_str().to_owned();
|
let query_text = self.community_search_buffer.text().as_str().to_owned();
|
||||||
let query = if query_text.is_empty() { None } else { Some(query_text) };
|
let query = if query_text.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(query_text)
|
||||||
|
};
|
||||||
self.state = AppState::Communities;
|
self.state = AppState::Communities;
|
||||||
let page = if remove_previous { 1 } else { self.current_communities_page + 1 };
|
let page = if remove_previous {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
self.current_communities_page + 1
|
||||||
|
};
|
||||||
self.current_communities_page = page;
|
self.current_communities_page = page;
|
||||||
self.current_communities_type = listing_type;
|
self.current_communities_type = listing_type;
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::communities::fetch_communities(page, query, listing_type) {
|
let message =
|
||||||
|
match api::communities::fetch_communities(page, query, listing_type) {
|
||||||
Ok(communities) => AppMsg::DoneFetchCommunities(communities),
|
Ok(communities) => AppMsg::DoneFetchCommunities(communities),
|
||||||
Err(err) => AppMsg::ShowMessage(err.to_string())
|
Err(err) => AppMsg::ShowMessage(err.to_string()),
|
||||||
};
|
};
|
||||||
sender.input(message);
|
sender.input(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AppMsg::DoneFetchCommunities(communities) => {
|
AppMsg::DoneFetchCommunities(communities) => {
|
||||||
self.state = AppState::Communities;
|
self.state = AppState::Communities;
|
||||||
if self.current_communities_page == 1 { self.communities.guard().clear(); }
|
if self.current_communities_page == 1 {
|
||||||
|
self.communities.guard().clear();
|
||||||
|
}
|
||||||
for community in communities {
|
for community in communities {
|
||||||
self.communities.guard().push_back(community);
|
self.communities.guard().push_back(community);
|
||||||
}
|
}
|
||||||
|
@ -444,13 +520,15 @@ impl SimpleComponent for App {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::user::get_user(person_id, 1) {
|
let message = match api::user::get_user(person_id, 1) {
|
||||||
Ok(person) => AppMsg::DoneFetchPerson(person),
|
Ok(person) => AppMsg::DoneFetchPerson(person),
|
||||||
Err(err) => AppMsg::ShowMessage(err.to_string())
|
Err(err) => AppMsg::ShowMessage(err.to_string()),
|
||||||
};
|
};
|
||||||
sender.input(message);
|
sender.input(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AppMsg::DoneFetchPerson(person) => {
|
AppMsg::DoneFetchPerson(person) => {
|
||||||
self.profile_page.sender().emit(profile_page::ProfileInput::UpdatePerson(person));
|
self.profile_page
|
||||||
|
.sender()
|
||||||
|
.emit(profile_page::ProfileInput::UpdatePerson(person));
|
||||||
self.state = AppState::Person;
|
self.state = AppState::Person;
|
||||||
}
|
}
|
||||||
AppMsg::OpenCommunity(community_id) => {
|
AppMsg::OpenCommunity(community_id) => {
|
||||||
|
@ -458,13 +536,17 @@ impl SimpleComponent for App {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::community::get_community(community_id) {
|
let message = match api::community::get_community(community_id) {
|
||||||
Ok(community) => AppMsg::DoneFetchCommunity(community),
|
Ok(community) => AppMsg::DoneFetchCommunity(community),
|
||||||
Err(err) => AppMsg::ShowMessage(err.to_string())
|
Err(err) => AppMsg::ShowMessage(err.to_string()),
|
||||||
};
|
};
|
||||||
sender.input(message);
|
sender.input(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AppMsg::DoneFetchCommunity(community) => {
|
AppMsg::DoneFetchCommunity(community) => {
|
||||||
self.community_page.sender().emit(community_page::CommunityInput::UpdateCommunity(community.community_view));
|
self.community_page
|
||||||
|
.sender()
|
||||||
|
.emit(community_page::CommunityInput::UpdateCommunity(
|
||||||
|
community.community_view,
|
||||||
|
));
|
||||||
self.state = AppState::Community;
|
self.state = AppState::Community;
|
||||||
}
|
}
|
||||||
AppMsg::OpenPost(post_id) => {
|
AppMsg::OpenPost(post_id) => {
|
||||||
|
@ -472,21 +554,29 @@ impl SimpleComponent for App {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::post::get_post(post_id) {
|
let message = match api::post::get_post(post_id) {
|
||||||
Ok(post) => AppMsg::DoneFetchPost(post),
|
Ok(post) => AppMsg::DoneFetchPost(post),
|
||||||
Err(err) => AppMsg::ShowMessage(err.to_string())
|
Err(err) => AppMsg::ShowMessage(err.to_string()),
|
||||||
};
|
};
|
||||||
sender.input(message);
|
sender.input(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
AppMsg::DoneFetchPost(post) => {
|
AppMsg::DoneFetchPost(post) => {
|
||||||
self.post_page.sender().emit(post_page::PostInput::UpdatePost(post));
|
self.post_page
|
||||||
|
.sender()
|
||||||
|
.emit(post_page::PostInput::UpdatePost(post));
|
||||||
self.state = AppState::Post;
|
self.state = AppState::Post;
|
||||||
}
|
}
|
||||||
AppMsg::ShowLogin => {
|
AppMsg::ShowLogin => {
|
||||||
self.state = AppState::Login;
|
self.state = AppState::Login;
|
||||||
}
|
}
|
||||||
AppMsg::Login(username, password, totp_token) => {
|
AppMsg::Login(username, password, totp_token) => {
|
||||||
if get_current_account().instance_url.is_empty() { return; }
|
if get_current_account().instance_url.is_empty() {
|
||||||
let token = if totp_token.is_empty() { None } else { Some(totp_token) };
|
return;
|
||||||
|
}
|
||||||
|
let token = if totp_token.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(totp_token)
|
||||||
|
};
|
||||||
self.state = AppState::Loading;
|
self.state = AppState::Loading;
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let message = match api::auth::login(username, password, token) {
|
let message = match api::auth::login(username, password, token) {
|
||||||
|
@ -506,7 +596,7 @@ impl SimpleComponent for App {
|
||||||
AppMsg::ShowMessage("Wrong credentials!".to_string())
|
AppMsg::ShowMessage("Wrong credentials!".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => AppMsg::ShowMessage(err.to_string())
|
Err(err) => AppMsg::ShowMessage(err.to_string()),
|
||||||
};
|
};
|
||||||
sender.input(message);
|
sender.input(message);
|
||||||
});
|
});
|
||||||
|
@ -531,7 +621,9 @@ impl SimpleComponent for App {
|
||||||
}
|
}
|
||||||
AppMsg::PopBackStack => {
|
AppMsg::PopBackStack => {
|
||||||
let action = self.back_queue.get(self.back_queue.len() - 2);
|
let action = self.back_queue.get(self.back_queue.len() - 2);
|
||||||
if let Some(action) = action { sender.input(action.clone()); }
|
if let Some(action) = action {
|
||||||
|
sender.input(action.clone());
|
||||||
|
}
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
self.back_queue.remove(self.back_queue.len() - 1);
|
self.back_queue.remove(self.back_queue.len() - 1);
|
||||||
}
|
}
|
||||||
|
@ -547,7 +639,7 @@ relm4::new_stateless_action!(LoginAction, WindowActionGroup, "login");
|
||||||
relm4::new_stateless_action!(LogoutAction, WindowActionGroup, "logout");
|
relm4::new_stateless_action!(LogoutAction, WindowActionGroup, "logout");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = RelmApp::new(APP_ID);
|
let app = RelmApp::new(config::APP_ID);
|
||||||
set_global_css(include_str!("style.css"));
|
set_global_css(include_str!("style.css"));
|
||||||
app.run::<App>(());
|
app.run::<App>(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::{fs::File, path::PathBuf};
|
use crate::config::APP_ID;
|
||||||
use crate::gtk::glib;
|
use crate::gtk::glib;
|
||||||
use lemmy_api_common::sensitive::Sensitive;
|
use lemmy_api_common::sensitive::Sensitive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::APP_ID;
|
use std::{fs::File, path::PathBuf};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Default, Clone)]
|
#[derive(Deserialize, Serialize, Default, Clone)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
|
@ -15,7 +15,7 @@ pub struct Account {
|
||||||
#[derive(Deserialize, Serialize, Default)]
|
#[derive(Deserialize, Serialize, Default)]
|
||||||
pub struct Preferences {
|
pub struct Preferences {
|
||||||
pub accounts: Vec<Account>,
|
pub accounts: Vec<Account>,
|
||||||
pub current_account_index: u32
|
pub current_account_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_path() -> PathBuf {
|
pub fn data_path() -> PathBuf {
|
||||||
|
|
10
src/util.rs
10
src/util.rs
|
@ -4,15 +4,19 @@ use relm4_components::web_image::WebImageMsg;
|
||||||
pub fn get_web_image_msg(url: Option<DbUrl>) -> WebImageMsg {
|
pub fn get_web_image_msg(url: Option<DbUrl>) -> WebImageMsg {
|
||||||
return if let Some(url) = url {
|
return if let Some(url) = url {
|
||||||
WebImageMsg::LoadImage(url.to_string())
|
WebImageMsg::LoadImage(url.to_string())
|
||||||
} else { WebImageMsg::Unload };
|
} else {
|
||||||
|
WebImageMsg::Unload
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_web_image_url(url: Option<DbUrl>) -> String {
|
pub fn get_web_image_url(url: Option<DbUrl>) -> String {
|
||||||
return if let Some(url) = url {
|
return if let Some(url) = url {
|
||||||
url.to_string()
|
url.to_string()
|
||||||
} else { String::from("") }
|
} else {
|
||||||
|
String::from("")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn markdown_to_pango_markup(text: String) -> String {
|
pub fn markdown_to_pango_markup(text: String) -> String {
|
||||||
return html2pango::markup_html(&markdown::to_html(&text)).unwrap_or(text)
|
return html2pango::markup_html(&markdown::to_html(&text)).unwrap_or(text);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue