Commit 4c4a7c346c1e54900fb853ba79b0142917272799

Authored by Georg Hopp
1 parent 7093450d

incomplete image selector

@@ -8,27 +8,23 @@ pub enum Either<L, R> { @@ -8,27 +8,23 @@ pub enum Either<L, R> {
8 8
9 #[derive(Clone, Debug, Serialize, Deserialize)] 9 #[derive(Clone, Debug, Serialize, Deserialize)]
10 pub struct MarkdownJson { 10 pub struct MarkdownJson {
11 - pub name: String,  
12 - pub content: String,  
13 - pub number_of_versions: i32,  
14 - pub date_created: String,  
15 - pub date_updated: String, 11 + pub name :String,
  12 + pub content :String,
  13 + pub number_of_versions :i32,
  14 + pub date_created :String,
  15 + pub date_updated :String,
16 } 16 }
17 17
18 #[derive(Clone, Debug, Serialize, Deserialize)] 18 #[derive(Clone, Debug, Serialize, Deserialize)]
19 pub struct MarkdownDiffJson { 19 pub struct MarkdownDiffJson {
20 - pub id: i32,  
21 - pub date_created: String, 20 + pub id :i32,
  21 + pub date_created :String,
22 } 22 }
23 23
24 #[derive(Clone, Debug, Serialize, Deserialize)] 24 #[derive(Clone, Debug, Serialize, Deserialize)]
25 pub struct ImageJson { 25 pub struct ImageJson {
26 - pub upload_uuid :Option<Vec<u8>>,  
27 - pub uuid :Option<Vec<u8>>,  
28 - pub size :i32,  
29 - pub dim_x :Option<i32>,  
30 - pub dim_y :Option<i32>,  
31 - pub mime_type :String, 26 + pub id :i32,
  27 + pub uuid :Vec<u8>,
32 pub date_created :String, 28 pub date_created :String,
33 pub date_updated :String 29 pub date_updated :String
34 } 30 }
@@ -57,6 +57,9 @@ async fn main() -> std::io::Result<()> { @@ -57,6 +57,9 @@ async fn main() -> std::io::Result<()> {
57 . service( web::resource("/upload") 57 . service( web::resource("/upload")
58 . route(web::post().to(upload)) 58 . route(web::post().to(upload))
59 ) 59 )
  60 + . service( web::resource("/images")
  61 + . route(web::get().to(get_images))
  62 + )
60 . service( web::resource("/images/{id}") 63 . service( web::resource("/images/{id}")
61 . route(web::get().to(get_image)) 64 . route(web::get().to(get_image))
62 ) 65 )
@@ -240,6 +240,13 @@ pub(crate) fn finalize( pool :Arc<Pool> @@ -240,6 +240,13 @@ pub(crate) fn finalize( pool :Arc<Pool>
240 } 240 }
241 } 241 }
242 242
  243 +pub(crate) fn get_images(pool: Arc<Pool>) -> Result<Vec<Image>>
  244 +{
  245 + use crate::schema::images::dsl::*;
  246 + let db_connection = pool.get()?;
  247 + Ok(images.load::<Image>(&db_connection)?)
  248 +}
  249 +
243 pub(crate) fn get_image( pool :Arc<Pool> 250 pub(crate) fn get_image( pool :Arc<Pool>
244 , ident :i32 ) -> Result<Image> 251 , ident :i32 ) -> Result<Image>
245 { 252 {
@@ -2,7 +2,7 @@ use std::fmt::Display; @@ -2,7 +2,7 @@ use std::fmt::Display;
2 2
3 use crate::{models::image, AppData, error::Error}; 3 use crate::{models::image, AppData, error::Error};
4 4
5 -use actix_web::{Error as ActixError, web, http::StatusCode}; 5 +use actix_web::{Error as ActixError, web, HttpResponse, http::StatusCode};
6 use anyhow::Result; 6 use anyhow::Result;
7 use serde::{Deserialize, Serialize}; 7 use serde::{Deserialize, Serialize};
8 8
@@ -35,6 +35,17 @@ impl Display for Size { @@ -35,6 +35,17 @@ impl Display for Size {
35 } 35 }
36 } 36 }
37 37
  38 +pub async fn get_images(app_data: web::Data<AppData>)
  39 + -> Result<HttpResponse, ActixError>
  40 +{
  41 + let pool = app_data.database_pool.clone();
  42 +
  43 + Ok(web::block(move || image::get_images(pool))
  44 + . await
  45 + . map(|images| HttpResponse::Ok().json(images))
  46 + . map_err(|_| HttpResponse::InternalServerError())?)
  47 +}
  48 +
38 pub async fn get_image( app_data: web::Data<AppData> 49 pub async fn get_image( app_data: web::Data<AppData>
39 , ident: web::Path<i32> 50 , ident: web::Path<i32>
40 , size: web::Query<SizeQuery> 51 , size: web::Query<SizeQuery>
@@ -111,17 +111,17 @@ async fn save_resized( original :&DynamicImage @@ -111,17 +111,17 @@ async fn save_resized( original :&DynamicImage
111 Err(e) if e.kind() == ErrorKind::NotFound => 111 Err(e) if e.kind() == ErrorKind::NotFound =>
112 spawn_blocking(move || -> Result<(), Error> { 112 spawn_blocking(move || -> Result<(), Error> {
113 let mut scaled = original.resize(width, height, Lanczos3); 113 let mut scaled = original.resize(width, height, Lanczos3);
114 - overlay(&mut scaled, CONFIG.copyright_image(), 0_u32, 0_u32);  
115 114
116 if let Size::Thumbnail = size { 115 if let Size::Thumbnail = size {
117 - scaled.save_with_format(&path, Jpeg)?;  
118 } else { 116 } else {
119 - let stegonography = CONFIG.copyright_steganography().as_bytes();  
120 - let encoder = Encoder::new(stegonography, scaled);  
121 - let scaled = encoder.encode_alpha();  
122 - scaled.save_with_format(&path, Jpeg)?; 117 + overlay(&mut scaled, CONFIG.copyright_image(), 0_u32, 0_u32);
123 } 118 }
124 119
  120 + let stegonography = CONFIG.copyright_steganography().as_bytes();
  121 + let encoder = Encoder::new(stegonography, scaled);
  122 + let scaled = encoder.encode_alpha();
  123 + scaled.save_with_format(&path, Jpeg)?;
  124 +
125 let exiv = Metadata::new_from_path(&path)?; 125 let exiv = Metadata::new_from_path(&path)?;
126 exiv.set_tag_string("Exif.Image.Copyright", CONFIG.copyright_exiv())?; 126 exiv.set_tag_string("Exif.Image.Copyright", CONFIG.copyright_exiv())?;
127 exiv.save_to_file(&path)?; 127 exiv.save_to_file(&path)?;
1 -.upload { 1 +.application > div {
2 float: left; 2 float: left;
3 - width: 400px; 3 + width: 30%;
  4 +}
  5 +
  6 +.selector {
  7 + padding: 1em;
  8 + border-radius: .5em;
  9 + border: 1px solid #ddd;
  10 + background: #f7f7f7;
  11 +}
  12 +
  13 +.selector img {
  14 + max-width: 75px;
  15 + max-height: 75px;
  16 + width: auto;
  17 + height: auto;
  18 + vertical-align: middle;
  19 +}
  20 +
  21 +.selector > ul {
  22 + display: flex;
  23 + flex-wrap: wrap;
  24 + gap: 5px;
  25 + justify-content: space-between;
  26 + align-items: center;
  27 + max-height: 15em;
  28 + width: calc(100% - 15px);
  29 + overflow-y: auto;
  30 + overflow-x: auto;
  31 + background: #ffffff;
  32 + border-radius: .35em;
  33 + border: 2px solid #bbb;
  34 + cursor: default;
  35 + padding-left: 5px;
  36 + padding-right: 5px;
  37 + margin-top: 0;
  38 + margin-bottom: 0;
  39 +}
  40 +
  41 +.selector > ul > li {
  42 + display: unset;
  43 + border: 1px solid black;
  44 + width: fit-content;
  45 + height: fit-content;
  46 + margin-bottom: .15em;
  47 +}
  48 +
  49 +.selector > ul > li:last-child {
  50 + margin-bottom: 0;
  51 +}
  52 +
  53 +.upload {
4 padding: 1em; 54 padding: 1em;
5 border-radius: .5em; 55 border-radius: .5em;
6 border: 1px solid #ddd; 56 border: 1px solid #ddd;
@@ -55,7 +105,6 @@ @@ -55,7 +105,6 @@
55 } 105 }
56 106
57 .markdown { 107 .markdown {
58 - float: left;  
59 padding: 1em; 108 padding: 1em;
60 border-radius: .5em; 109 border-radius: .5em;
61 border: 1px solid #ddd; 110 border: 1px solid #ddd;
@@ -76,7 +125,6 @@ @@ -76,7 +125,6 @@
76 125
77 .markdown > div:first-child { 126 .markdown > div:first-child {
78 position: fixed; 127 position: fixed;
79 - width: inherit;  
80 z-index: 10; 128 z-index: 10;
81 } 129 }
82 130
  1 +use std::fmt::Display;
  2 +
  3 +use artshop_common::types::ImageJson;
  4 +
  5 +use super::super::error::*;
  6 +use super::super::client::Client;
  7 +
  8 +#[derive(Debug, Clone)]
  9 +pub struct Image {
  10 + pub json: ImageJson,
  11 +}
  12 +
  13 +pub(crate) async fn images() -> Result<Vec<Image>> {
  14 + let client = Client::new()?;
  15 + let (response, data) = client.get("/api/v0/images").await?;
  16 +
  17 + match response.status() {
  18 + 200 => Ok ( serde_json::from_str(data.as_str())
  19 + . map(|images :Vec<ImageJson>| {
  20 + images.into_iter().map(|json| Image { json }).collect()
  21 + })? ),
  22 + status => Err(status_error(status)),
  23 + }
  24 +}
  25 +
  26 +fn status_error<I: Display>(status :I) -> Error {
  27 + let err_str = format!("Invalid response status: {}", status);
  28 + Error::from(err_str.as_str())
  29 +}
  30 +
  31 +// impl Image {
  32 +// }
  1 +pub(crate) mod image;
1 pub(crate) mod markdown; 2 pub(crate) mod markdown;
2 pub(crate) mod upload; 3 pub(crate) mod upload;
  1 +use mogwai::prelude::*;
  2 +
  3 +use crate::api::image::{Image, images};
  4 +
  5 +use super::{PatchSender, view::image_preview_view};
  6 +
  7 +pub(super) async fn image_preview_logic() {
  8 +}
  9 +
  10 +pub(super) async fn selector_logic( mut rx_dom :broadcast::Receiver<Dom>
  11 + , tx_previews :PatchSender) {
  12 + let mut previews :ListPatchModel<Image> = ListPatchModel::new();
  13 +
  14 + mogwai::spawn(previews.stream().for_each(move |patch| {
  15 + let patch :ListPatch<ViewBuilder<Dom>> = patch.map(|i| {
  16 + let view = image_preview_view(
  17 + String::from(format!( "/api/v0/images/{}?size=thumbnail"
  18 + , i.json.id )));
  19 + let logic = image_preview_logic();
  20 +
  21 + Component::from(view).with_logic(logic).into()
  22 + });
  23 + let tx_previews = tx_previews.clone();
  24 +
  25 + async move {
  26 + tx_previews.send(patch).await.unwrap();
  27 + }
  28 + }));
  29 +
  30 + if let Some(_) = rx_dom.next().await {
  31 + for image in images().await.unwrap().into_iter() {
  32 + previews.list_patch_push(image);
  33 + }
  34 + }
  35 +}
  1 +pub(crate) mod logic;
  2 +mod view;
  3 +
  4 +use mogwai::prelude::*;
  5 +
  6 +use self::{view::selector_view, logic::selector_logic};
  7 +
  8 +type PatchSender = mpmc::Sender<ListPatch<ViewBuilder<Dom>>>;
  9 +type PatchReceiver = mpmc::Receiver<ListPatch<ViewBuilder<Dom>>>;
  10 +
  11 +pub(crate) async fn new() -> Component<Dom> {
  12 + let (tx_previews, rx_previews) = mpmc::bounded(1);
  13 + let (tx_dom, rx_dom) = broadcast::bounded(1);
  14 +
  15 + let view = selector_view(tx_dom, rx_previews);
  16 + let logic = selector_logic(rx_dom, tx_previews);
  17 +
  18 + Component::from(view).with_logic(logic)
  19 +}
  1 +use mogwai::prelude::*;
  2 +
  3 +use crate::component::imageselector::PatchReceiver;
  4 +
  5 +pub(super) fn image_preview_view(image_url :String) -> ViewBuilder<Dom> {
  6 + builder! {
  7 + <li><img src=image_url/></li>
  8 + }
  9 +}
  10 +
  11 +pub(super) fn selector_view( tx_dom :broadcast::Sender<Dom>
  12 + , rx_previews :PatchReceiver) -> ViewBuilder<Dom> {
  13 + let post_build = move |dom: &mut Dom| {
  14 + tx_dom.try_broadcast(dom.clone()).unwrap();
  15 + };
  16 +
  17 + builder! {
  18 + <div class="selector">
  19 + <ul patch:children=rx_previews
  20 + post:build=post_build>
  21 + </ul>
  22 + </div>
  23 + }
  24 +}
@@ -58,7 +58,6 @@ pub(super) fn markdown_view( tx_logic: broadcast::Sender<MarkdownLogic> @@ -58,7 +58,6 @@ pub(super) fn markdown_view( tx_logic: broadcast::Sender<MarkdownLogic>
58 58
59 builder! { 59 builder! {
60 <div class="markdown" 60 <div class="markdown"
61 - style:width="33%"  
62 post:build=move |_: &mut Dom| { 61 post:build=move |_: &mut Dom| {
63 tx_logic.try_broadcast(MarkdownLogic::Choose(None)).unwrap(); 62 tx_logic.try_broadcast(MarkdownLogic::Choose(None)).unwrap();
64 } 63 }
  1 +pub(crate) mod imageselector;
1 pub(crate) mod markdown; 2 pub(crate) mod markdown;
2 pub(crate) mod upload; 3 pub(crate) mod upload;
@@ -29,11 +29,13 @@ pub async fn main() -> Result<(), JsValue> { @@ -29,11 +29,13 @@ pub async fn main() -> Result<(), JsValue> {
29 29
30 let md = markdown::new().await; 30 let md = markdown::new().await;
31 let comp = upload::new().await; 31 let comp = upload::new().await;
  32 + let selector = imageselector::new().await;
32 33
33 let page = Component::from(builder! { 34 let page = Component::from(builder! {
34 - <div> 35 + <div class="application">
35 {comp} 36 {comp}
36 {md} 37 {md}
  38 + {selector}
37 </div> 39 </div>
38 }); 40 });
39 page.build()?.run() 41 page.build()?.run()
Please register or login to post a comment