Compare commits
10 commits
c40a4b3fe1
...
b56425c671
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b56425c671 | ||
![]() |
504b4bc944 | ||
![]() |
92f2b18a20 | ||
![]() |
fbcb6afc7a | ||
![]() |
26975c2004 | ||
![]() |
8d9e00cb7a | ||
![]() |
0ba3e7588b | ||
![]() |
da735aa00b | ||
![]() |
6fe0bf8fe2 | ||
![]() |
b1d938acba |
45 changed files with 1711 additions and 819 deletions
|
@ -30,7 +30,10 @@ include(ECMPoQmTools)
|
|||
|
||||
kde_enable_exceptions()
|
||||
|
||||
find_package(Qt6 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Core5Compat Quick Test Gui Qml QuickControls2 Widgets Sql QmlImportScanner WebEngineQuick)
|
||||
set(CXXQT_QTCOMPONENTS Core Gui Qml QuickControls2 QuickTest Test)
|
||||
set(CXXQT_QTCOMPONENTS ${CXXQT_QTCOMPONENTS} QmlImportScanner)
|
||||
|
||||
find_package(Qt6 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Core5Compat Quick Test Gui Qml QuickControls2 Widgets Sql QmlImportScanner WebEngineQuick Multimedia)
|
||||
find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Kirigami CoreAddons I18n)
|
||||
|
||||
# find_package(KF6FileMetaData ${KF6_MIN_VERSION})
|
||||
|
@ -57,45 +60,70 @@ set_package_properties(Ytdlp PROPERTIES TYPE RUNTIME)
|
|||
# execute_process(COMMAND ${XDG-DESKTOP-MENU_EXECUTABLE} install --novender librepresenter.desktop)
|
||||
|
||||
get_target_property(QMAKE Qt::qmake IMPORTED_LOCATION)
|
||||
find_package(Corrosion QUIET)
|
||||
if(NOT Corrosion_FOUND)
|
||||
find_package(CxxQt QUIET)
|
||||
if(NOT CxxQt_FOUND)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
Corrosion
|
||||
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
||||
GIT_TAG v0.3.0
|
||||
CxxQt
|
||||
GIT_REPOSITORY https://github.com/kdab/cxx-qt-cmake.git
|
||||
GIT_TAG v0.7.0
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(Corrosion)
|
||||
FetchContent_MakeAvailable(CxxQt)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
# find_package(Corrosion QUIET)
|
||||
# if(NOT Corrosion_FOUND)
|
||||
# include(FetchContent)
|
||||
# FetchContent_Declare(
|
||||
# Corrosion
|
||||
# GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
|
||||
# GIT_TAG v0.3.0
|
||||
# )
|
||||
|
||||
# FetchContent_MakeAvailable(Corrosion)
|
||||
# endif()
|
||||
|
||||
|
||||
set(CRATE liblumina)
|
||||
|
||||
# CXX-Qt (using Corrosion) creates a CMake target with the same name as the crate.
|
||||
cxx_qt_import_crate(
|
||||
MANIFEST_PATH Cargo.toml
|
||||
CRATES liblumina
|
||||
QT_MODULES Qt::Core Qt::Gui Qt::Qml Qt::QuickControls2 Qt::WebEngineQuick)
|
||||
|
||||
cxx_qt_import_qml_module(liblumina_qml_module
|
||||
URI "org.presenter"
|
||||
SOURCE_CRATE liblumina)
|
||||
|
||||
|
||||
# Corrosion creates a CMake target with the same name as the crate.
|
||||
corrosion_import_crate(MANIFEST_PATH Cargo.toml CRATES ${CRATE})
|
||||
# corrosion_import_crate(MANIFEST_PATH Cargo.toml CRATES ${CRATE})
|
||||
|
||||
# The Rust library's build script needs to be told where to output the
|
||||
# generated headers so CMake can find them. To do this, tell Corrosion
|
||||
# to set the CXXQT_EXPORT_DIR environment variable when calling `cargo build`.
|
||||
# Also, set the QMAKE environment variable to ensure the Rust library uses
|
||||
# the same installation of Qt as CMake.
|
||||
set(CXXQT_EXPORT_DIR "${CMAKE_CURRENT_BINARY_DIR}/cxxqt")
|
||||
corrosion_set_env_vars(${CRATE}
|
||||
"CXXQT_EXPORT_DIR=${CXXQT_EXPORT_DIR}"
|
||||
"QMAKE=${QMAKE}"
|
||||
)
|
||||
# set(CXXQT_EXPORT_DIR "${CMAKE_CURRENT_BINARY_DIR}/cxxqt")
|
||||
# corrosion_set_env_vars(${CRATE}
|
||||
# "CXXQT_EXPORT_DIR=${CXXQT_EXPORT_DIR}"
|
||||
# "QMAKE=${QMAKE}"
|
||||
# )
|
||||
|
||||
add_library(${APP_NAME}_lib INTERFACE)
|
||||
add_subdirectory(src)
|
||||
# Include the headers generated by the Rust library's build script. Each
|
||||
# crate gets its own subdirectory under CXXQT_EXPORT_DIR. This allows you
|
||||
# to include headers generated by multiple crates without risk of one crate
|
||||
# overwriting another's files.
|
||||
target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
|
||||
target_include_directories(liblumina INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
|
||||
|
||||
|
||||
# Link the Rust INTERFACE library target to Qt. Do this on the library target
|
||||
# rather than the main executable. This way, CMake targets besides the main
|
||||
# executable which link the Rust library, for example tests, will also link Qt.
|
||||
target_link_libraries(${APP_NAME}_lib INTERFACE
|
||||
target_link_libraries(liblumina INTERFACE
|
||||
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-static>"
|
||||
Qt6::Quick
|
||||
Qt6::Qml
|
||||
|
@ -104,6 +132,7 @@ target_link_libraries(${APP_NAME}_lib INTERFACE
|
|||
Qt6::Widgets
|
||||
Qt6::Sql
|
||||
Qt6::WebEngineQuick
|
||||
Qt6::Multimedia
|
||||
KF6::Kirigami
|
||||
KF6::I18n
|
||||
KF6::CoreAddons
|
||||
|
@ -114,8 +143,9 @@ target_link_libraries(${APP_NAME}_lib INTERFACE
|
|||
crypto
|
||||
)
|
||||
|
||||
|
||||
# Link to the Rust library
|
||||
target_link_libraries(${APP_NAME} PRIVATE ${APP_NAME}_lib)
|
||||
target_link_libraries(${APP_NAME} PRIVATE liblumina)
|
||||
|
||||
# If we are using a statically linked Qt then we need to import any qml plugins
|
||||
qt_import_qml_plugins(${APP_NAME})
|
||||
|
|
159
Cargo.lock
generated
159
Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
|
@ -338,6 +338,19 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blah"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-qt",
|
||||
"cxx-qt-build",
|
||||
"cxx-qt-lib",
|
||||
"cxx-qt-lib-extras",
|
||||
"markdown",
|
||||
"qt-build-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
|
@ -490,32 +503,6 @@ dependencies = [
|
|||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"configparser",
|
||||
"dirs",
|
||||
"fastrand 2.1.1",
|
||||
"obws",
|
||||
"pretty_assertions",
|
||||
"quote",
|
||||
"reqwest",
|
||||
"rfd",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tar",
|
||||
"time",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"youtube_dl",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
|
@ -593,21 +580,6 @@ dependencies = [
|
|||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c77953e99f01508f89f55c494bfa867171ef3a6c8cea03d26975368f2121a5c1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn 2.0.77",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-gen"
|
||||
version = "0.7.128"
|
||||
|
@ -622,38 +594,41 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cxx-qt"
|
||||
version = "0.6.1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08aa6cda7588b6d17c563b0d2fadc060d4204d04908c0f359ae288857091218d"
|
||||
checksum = "208ad6c4feac92f221fde00796f317b049ba1892b97be0d60ca177d0d3469fc5"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-qt-build",
|
||||
"cxx-qt-macro",
|
||||
"qt-build-utils",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-qt-build"
|
||||
version = "0.6.1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e097b99f49792922a72a8ca35d9391762e48e63363d6998255be1f2ca1edf69"
|
||||
checksum = "15f80e109aa68795486c70c302f6c2d921f00028b3b62038a4601efb5c585c1c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"convert_case",
|
||||
"cxx-gen",
|
||||
"cxx-qt-gen",
|
||||
"cxx-qt-lib-headers",
|
||||
"proc-macro2",
|
||||
"qt-build-utils",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-qt-gen"
|
||||
version = "0.6.1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ede7c73dbfbcc234d8826919e257830c1789db2cac586546a87d2a82e3cbe5d5"
|
||||
checksum = "dc17d95ca9cc60c2f91f804a4e0ba6a3e1b8ed338c207a1bd8d176133e2fd05d"
|
||||
dependencies = [
|
||||
"clang-format",
|
||||
"convert_case",
|
||||
|
@ -665,27 +640,33 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cxx-qt-lib"
|
||||
version = "0.6.1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "002f1a6119bcb7dfec67eb7c0803a7b1d595dc54610559faeac35133f22a5880"
|
||||
checksum = "f116c5d982bbf3be707acf97f566802c30454d52ca319c745ed39a04834e8bc6"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
"cxx-qt-lib-headers",
|
||||
"cxx-qt",
|
||||
"cxx-qt-build",
|
||||
"qt-build-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-qt-lib-headers"
|
||||
version = "0.6.1"
|
||||
name = "cxx-qt-lib-extras"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9abdeab6b77cfc5a53b724f3f62a37bcb5ac1423cccc2dba4c134f4273440b8c"
|
||||
checksum = "bbe1aaed6391a224d746e314104f33b4031138291ebd368170a2109b6008ace2"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-qt",
|
||||
"cxx-qt-build",
|
||||
"cxx-qt-lib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-qt-macro"
|
||||
version = "0.6.1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "699e8a668c03b03419b084960d72eed253632bb16349b33fd0a0c893b61b664c"
|
||||
checksum = "58a4fe02c0604eda28c605792f5ba0d0251b4947f8f0fc43e55b61c06b2b8ec6"
|
||||
dependencies = [
|
||||
"cxx-qt-gen",
|
||||
"proc-macro2",
|
||||
|
@ -1432,9 +1413,9 @@ checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -1490,6 +1471,7 @@ dependencies = [
|
|||
"cxx-qt-lib",
|
||||
"dirs",
|
||||
"fastrand 2.1.1",
|
||||
"lumina_core",
|
||||
"obws",
|
||||
"qt-build-utils",
|
||||
"quote",
|
||||
|
@ -1573,6 +1555,32 @@ version = "0.4.22"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lumina_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"color-eyre",
|
||||
"configparser",
|
||||
"dirs",
|
||||
"fastrand 2.1.1",
|
||||
"obws",
|
||||
"pretty_assertions",
|
||||
"quote",
|
||||
"reqwest",
|
||||
"rfd",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tar",
|
||||
"time",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"youtube_dl",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
|
@ -1582,6 +1590,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "1.0.0-alpha.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21e27d6220ce21f80ce5c4201f23a37c6f1ad037c72c9d1ff215c2919605a5d6"
|
||||
dependencies = [
|
||||
"unicode-id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
|
@ -2092,9 +2109,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "qt-build-utils"
|
||||
version = "0.6.1"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59c828fe2434dad34dd0c30a4ba037509b61dad92a55baf0dc42699e6aa2f10"
|
||||
checksum = "efb239fdd8c036fabb95364320041ef68197cd4ab971bb3b4ca3ea0b7b93d12c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"thiserror",
|
||||
|
@ -2364,12 +2381,6 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.1"
|
||||
|
@ -3212,6 +3223,12 @@ version = "0.3.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-id"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
|
@ -3304,9 +3321,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|||
|
||||
[[package]]
|
||||
name = "versions"
|
||||
version = "5.0.1"
|
||||
version = "6.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd"
|
||||
checksum = "f25d498b63d1fdb376b4250f39ab3a5ee8d103957346abacd911e2d8b612c139"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"nom",
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = ["src/rust/core"]
|
||||
members = [ "smdview/blah","src/rust/core"]
|
||||
|
||||
[package]
|
||||
name = "liblumina"
|
||||
|
@ -21,13 +21,14 @@ path = "src/rust/lib.rs"
|
|||
# path = "src/rust/main.rs"
|
||||
|
||||
[dependencies]
|
||||
lumina_core = { path = "src/rust/core" }
|
||||
configparser = "3.0.2"
|
||||
serde = "1.0.152"
|
||||
serde_derive = "1.0.152"
|
||||
quote = "1.0.27"
|
||||
cxx = "1.0.83"
|
||||
cxx-qt = "0.6.1"
|
||||
cxx-qt-lib = "0.6.1"
|
||||
cxx-qt = "0.7.1"
|
||||
cxx-qt-lib = { version = "0.7.1", features = [ "qt_full" ] }
|
||||
# home = "0.5.4"
|
||||
dirs = "5.0.0"
|
||||
# libsqlite3-sys = { version = ">=0.17.2", features = ["bundled"] }
|
||||
|
@ -50,8 +51,8 @@ color-eyre = "0.6.3"
|
|||
# cxx-qt-build generates C++ code from the `#[cxx_qt::bridge]` module
|
||||
# and compiles it together with the Rust static library
|
||||
[build-dependencies]
|
||||
cxx-qt-build = { version = "0.6.1", features = [ "link_qt_object_files" ] }
|
||||
qt-build-utils = "0.6.1"
|
||||
cxx-qt-build = { version = "0.7.1", features = [ "link_qt_object_files" ] }
|
||||
qt-build-utils = "0.7.1"
|
||||
|
||||
# [dependencies.confy]
|
||||
# features = ["yaml_conf"]
|
||||
|
|
3
TODO.org
3
TODO.org
|
@ -4,7 +4,8 @@
|
|||
:CATEGORY: dev
|
||||
:END:
|
||||
|
||||
* Tasks [63%] [55/86]
|
||||
* Tasks [63%] [55/87]
|
||||
** TODO [#A] REWRITE FOR ALL RUST AND BUILD WITH CARGO
|
||||
** TODO [#A] Plugin architecture with steel or some scheme as an extension language
|
||||
** TODO [#A] Server client architecture
|
||||
** TODO [#A] Organize and layout structure of rust code :maintenance:
|
||||
|
|
88
build.rs
88
build.rs
|
@ -1,3 +1,5 @@
|
|||
use std::{env, path::PathBuf};
|
||||
|
||||
use cxx_qt_build::{CxxQtBuilder, QmlModule};
|
||||
|
||||
fn main() {
|
||||
|
@ -17,6 +19,37 @@ fn main() {
|
|||
.file("src/rust/obs.rs")
|
||||
.build();
|
||||
|
||||
// let mut kde_include_dir = String::from("/usr/include/");
|
||||
// let mut kde_lib_dir = String::from("/usr/lib/x86_64-linux-gnu/");
|
||||
|
||||
// if let Ok(mut include_dir) = env::var("CMAKE_INCLUDE_PATH") {
|
||||
// println!("{}", include_dir);
|
||||
// if let Some(include_dir) =
|
||||
// include_dir.split(":").find(|s| s.contains("ki18n"))
|
||||
// {
|
||||
// kde_include_dir = include_dir.to_owned();
|
||||
// }
|
||||
// } else {
|
||||
// println!(
|
||||
// "cargo:warning=KDE_INCLUDEDIR is not defined, used default value: {}",
|
||||
// kde_include_dir
|
||||
// );
|
||||
// }
|
||||
// if let Ok(lib_dir) = env::var("KDE_LIBDIR") {
|
||||
// kde_lib_dir = lib_dir;
|
||||
// } else {
|
||||
// println!(
|
||||
// "cargo:warning=KDE_LIBDIR is not defined, used default value: {}",
|
||||
// kde_lib_dir
|
||||
// );
|
||||
// }
|
||||
|
||||
// let ki18n_include_path = PathBuf::from(kde_include_dir)
|
||||
// .canonicalize()
|
||||
// .expect("Cannot get canonical path of KDE_INCLUDEDIR")
|
||||
// .join("KF6")
|
||||
// .join("KI18n");
|
||||
|
||||
// CxxQtBuilder::new()
|
||||
// // Link Qt's Network library
|
||||
// // - Qt Core is always linked
|
||||
|
@ -27,13 +60,64 @@ fn main() {
|
|||
// // .qt_module("Kirigami")
|
||||
// // .qt_module("WebEngineQuick")
|
||||
// .qt_module("Network")
|
||||
// // .qt_module("Quick")
|
||||
// // .qt_module("Test")
|
||||
// // .qt_module("WebEngineQuick")
|
||||
// // .qt_module("I18n")
|
||||
// // .qt_module("CoreAddons")
|
||||
// .qml_module(QmlModule {
|
||||
// uri: "com.cochrun.xyz",
|
||||
// rust_files: &["src/rust/settings.rs"],
|
||||
// qml_files: &["src/qml/main.qml"],
|
||||
// rust_files: &[
|
||||
// "src/rust/settings.rs",
|
||||
// "src/rust/service_item_model.rs",
|
||||
// "src/rust/file_helper.rs",
|
||||
// "src/rust/slide_model.rs",
|
||||
// "src/rust/slide_object.rs",
|
||||
// "src/rust/ytdl.rs",
|
||||
// "src/rust/utils.rs",
|
||||
// "src/rust/obs.rs",
|
||||
// "src/rust/video_model.rs",
|
||||
// "src/rust/image_model.rs",
|
||||
// "src/rust/presentation_model.rs",
|
||||
// // "src/rust/songs/song_model.rs",
|
||||
// // "src/rust/songs/song_editor.rs",
|
||||
// ],
|
||||
// qrc_files: &["src/resources.qrc"],
|
||||
// qml_files: &[
|
||||
// "src/qml/main.qml",
|
||||
// "src/qml/presenter/LeftDock.qml",
|
||||
// "src/qml/presenter/ServiceList.qml",
|
||||
// "src/qml/presenter/MainWindow.qml",
|
||||
// "src/qml/presenter/Library.qml",
|
||||
// "src/qml/presenter/LibraryItem.qml",
|
||||
// "src/qml/presenter/Header.qml",
|
||||
// "src/qml/presenter/Actions.qml",
|
||||
// "src/qml/presenter/PanelItem.qml",
|
||||
// "src/qml/presenter/SongEditor.qml",
|
||||
// "src/qml/presenter/VideoEditor.qml",
|
||||
// "src/qml/presenter/ImageEditor.qml",
|
||||
// "src/qml/presenter/PresentationEditor.qml",
|
||||
// "src/qml/presenter/SlideEditor.qml",
|
||||
// "src/qml/presenter/Slide.qml",
|
||||
// "src/qml/presenter/SlidesListView.qml",
|
||||
// "src/qml/presenter/SongEditorSlideList.qml",
|
||||
// "src/qml/presenter/DragHandle.qml",
|
||||
// "src/qml/presenter/Presentation.qml",
|
||||
// "src/qml/presenter/PresentationWindow.qml",
|
||||
// "src/qml/presenter/PreviewSlideListDelegate.qml",
|
||||
// "src/qml/presenter/PreviewSlide.qml",
|
||||
// "src/qml/presenter/Settings.qml",
|
||||
// "src/qml/presenter/RangedSlider.qml",
|
||||
// "src/qml/presenter/NewVideo.qml",
|
||||
// "src/qml/presenter/TextBackground.qml",
|
||||
// "src/qml/presenter/TextBox.qml",
|
||||
// "src/qml/presenter/LoadingSpinner.qml",
|
||||
// ],
|
||||
// ..Default::default()
|
||||
// })
|
||||
// .cc_builder(|cc| {
|
||||
// cc.include("cpp");
|
||||
// cc.include(format!("{}", ki18n_include_path.display()));
|
||||
// })
|
||||
// .build();
|
||||
}
|
||||
|
|
131
flake.lock
generated
131
flake.lock
generated
|
@ -1,15 +1,56 @@
|
|||
{
|
||||
"nodes": {
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753252982,
|
||||
"narHash": "sha256-brrpvP+4GRXLHjvnDr1j1/yA4117hzs6t9IT60JuSI8=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "8546562a84feb5370ce57493277b6f2c3cbdc432",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"naersk",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752475459,
|
||||
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -20,14 +61,15 @@
|
|||
},
|
||||
"naersk": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
"fenix": "fenix_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721727458,
|
||||
"narHash": "sha256-r/xppY958gmZ4oTfLiHN0ZGuQ+RSTijDblVgVLFi1mw=",
|
||||
"lastModified": 1752689277,
|
||||
"narHash": "sha256-uldUBFkZe/E7qbvxa3mH1ItrWZyT6w1dBKJQF/3ZSsc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "naersk",
|
||||
"rev": "3fb418eaf352498f6b6c30592e3beb63df42ef11",
|
||||
"rev": "0e72363d0938b0208d6c646d10649164c43f4d64",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -38,23 +80,43 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 0,
|
||||
"narHash": "sha256-+yj+xgsfZaErbfYM3T+QvEE2hU7UuE+Jf0fJCJ8uPS0=",
|
||||
"path": "/nix/store/6inj491lsap4ia7mmvn2gbh53jb27zq0-source",
|
||||
"type": "path"
|
||||
"lastModified": 1752950548,
|
||||
"narHash": "sha256-NS6BLD0lxOrnCiEOcvQCDVPXafX1/ek1dfJHX1nUIzc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c87b95e25065c028d31a94f06a62927d18763fdf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1725634671,
|
||||
"narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=",
|
||||
"lastModified": 1752077645,
|
||||
"narHash": "sha256-HM791ZQtXV93xtCY+ZxG1REzhQenSQO020cu6rHtAPk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "be9e214982e20b8310878ac2baa063a961c1bdf6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1752950548,
|
||||
"narHash": "sha256-NS6BLD0lxOrnCiEOcvQCDVPXafX1/ek1dfJHX1nUIzc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c",
|
||||
"rev": "c87b95e25065c028d31a94f06a62927d18763fdf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -66,9 +128,44 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1753204114,
|
||||
"narHash": "sha256-xH8EIod+Hwog4P9OwX9hdtk6Nqr54M0tzMI71yGNOYI=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "b40fce3ccdc5f94453c6aca4da8b64174a03a5ad",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1752428706,
|
||||
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
|
180
flake.nix
180
flake.nix
|
@ -6,77 +6,121 @@
|
|||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
naersk.url = "github:nix-community/naersk";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
# nixpkgs.follows = "cargo2nix/nixpkgs";
|
||||
};
|
||||
|
||||
outputs = inputs: with inputs;
|
||||
flake-utils.lib.eachDefaultSystem
|
||||
(system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
# overlays = [cargo2nix.overlays.default];
|
||||
};
|
||||
naersk' = pkgs.callPackage naersk {};
|
||||
# src = ./.;
|
||||
# rustPkgs = pkgs.rustBuilder.makePackageSet {
|
||||
# rustVersion = "1.61.0";
|
||||
# packageFun = import ./Cargo.nix;
|
||||
# };
|
||||
# The workspace defines a development shell with all of the dependencies
|
||||
# and environment settings necessary for a regular `cargo build`.
|
||||
# Passes through all arguments to pkgs.mkShell for adding supplemental
|
||||
# dependencies.
|
||||
# workspaceShell = rustPkgs.workspaceShell {
|
||||
# packages = with pkgs; [
|
||||
# gcc
|
||||
# stdenv
|
||||
# bintools
|
||||
# gnumake
|
||||
# gdb
|
||||
# qtcreator
|
||||
# cmake
|
||||
# extra-cmake-modules
|
||||
# pkg-config
|
||||
# libsForQt5.wrapQtAppsHook
|
||||
# makeWrapper
|
||||
outputs = inputs:
|
||||
with inputs;
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ fenix.overlays.default ];
|
||||
# overlays = [cargo2nix.overlays.default];
|
||||
};
|
||||
naersk' = pkgs.callPackage naersk { };
|
||||
|
||||
# clang-tools
|
||||
# clang
|
||||
# libclang
|
||||
# qt5.qtbase
|
||||
# qt5.qttools
|
||||
# qt5.qtquickcontrols2
|
||||
# qt5.qtx11extras
|
||||
# qt5.qtmultimedia
|
||||
# qt5.qtwayland
|
||||
# qt5.qtwebengine
|
||||
# libsForQt5.kirigami2
|
||||
# libsForQt5.qqc2-desktop-style
|
||||
# libsForQt5.karchive
|
||||
# mpv
|
||||
# ffmpeg_6-full
|
||||
# # Rust tools
|
||||
# clippy
|
||||
# rustc
|
||||
# cargo
|
||||
# rustfmt
|
||||
# rust-analyzer
|
||||
# corrosion
|
||||
# ];
|
||||
# # shellHook = ''
|
||||
# # export PS1="\033[0;31m☠dev-shell☠ $ \033[0m"
|
||||
# # '';
|
||||
# };
|
||||
nbi = with pkgs; [
|
||||
# ffmpeg
|
||||
alejandra
|
||||
(pkgs.fenix.stable.withComponents [
|
||||
"cargo"
|
||||
"clippy"
|
||||
"rust-src"
|
||||
"rustc"
|
||||
"rustfmt"
|
||||
])
|
||||
rust-analyzer
|
||||
];
|
||||
|
||||
in rec
|
||||
{
|
||||
# packages = {
|
||||
# crate = (rustPkgs.workspace.libre-presenter { }).bin;
|
||||
# default = packages.crate;
|
||||
# };
|
||||
devShell = import ./shell.nix { inherit pkgs; };
|
||||
defaultPackage = pkgs.libsForQt5.callPackage ./default.nix { };
|
||||
}
|
||||
);
|
||||
bi = with pkgs; [
|
||||
gcc
|
||||
stdenv
|
||||
gnumake
|
||||
gdb
|
||||
qtcreator
|
||||
cmake
|
||||
kdePackages.extra-cmake-modules
|
||||
pkg-config
|
||||
qt6.wrapQtAppsHook
|
||||
makeWrapper
|
||||
|
||||
openssl.dev
|
||||
openssl.out
|
||||
|
||||
clang-tools
|
||||
clang
|
||||
libclang
|
||||
# libwebp
|
||||
# clang-format
|
||||
qt6.full
|
||||
qt6.qttools
|
||||
qt6.qtbase
|
||||
# qt6.qtquickcontrols2
|
||||
# qt6.qtx11extras
|
||||
qt6.qtmultimedia
|
||||
qt6.qtwayland
|
||||
qt6.qtwebengine
|
||||
qt6.qtimageformats
|
||||
kdePackages.kirigami
|
||||
# kdePackages.kfilemetadata
|
||||
# libsForQt5.breeze-icons
|
||||
# libsForQt5.breeze-qt5
|
||||
kdePackages.qqc2-desktop-style
|
||||
# libsForQt5.kirigami-addons
|
||||
# libsForQt5.ki18n
|
||||
kdePackages.kcoreaddons
|
||||
# libsForQt5.kguiaddons
|
||||
# libsForQt5.kconfig
|
||||
|
||||
# podofo
|
||||
mpv
|
||||
kdePackages.mpvqt
|
||||
ffmpeg-full
|
||||
# yt-dlp
|
||||
|
||||
# Rust tools
|
||||
just
|
||||
clippy
|
||||
rustc
|
||||
cargo
|
||||
rustfmt
|
||||
rust-analyzer
|
||||
sqlx-cli
|
||||
cargo-watch
|
||||
corrosion
|
||||
];
|
||||
|
||||
in rec {
|
||||
# packages = {
|
||||
# crate = (rustPkgs.workspace.libre-presenter { }).bin;
|
||||
# default = packages.crate;
|
||||
# };
|
||||
devShell = pkgs.mkShell {
|
||||
nativeBuildInputs = nbi;
|
||||
buildInputs = bi;
|
||||
|
||||
RUST_BACKTRACE = "1";
|
||||
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
|
||||
CMAKE_C_COMPILER = "${pkgs.gcc}/bin/gcc";
|
||||
CMAKE_CXX_COMPILER = "${pkgs.gcc}/bin/g++";
|
||||
CARGO_PROFILE_RELEASE_BUILD_OVERRIDE_DEBUG = true;
|
||||
# KDE_INCLUDEDIR = "${pkgs.kdePackages.kirigami.dev}/include";
|
||||
# KDE_QMLDIR = "${pkgs.kdePackages.kirigami.dev}/lib/qt-6/qml/org/kde/kirigami/";
|
||||
|
||||
# This creates the proper qt env so that plugins are found right.
|
||||
shellHook = ''
|
||||
setQtEnvironment=$(mktemp --suffix .setQtEnvironment.sh)
|
||||
echo "shellHook: setQtEnvironment = $setQtEnvironment"
|
||||
makeQtWrapper "/bin/sh" "$setQtEnvironment" "''${qtWrapperArgs[@]}"
|
||||
sed "/^exec/d" -i "$setQtEnvironment"
|
||||
source "$setQtEnvironment"
|
||||
'';
|
||||
DATABASE_URL =
|
||||
"sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
|
||||
};
|
||||
# devShell = import ./shell.nix { inherit pkgs; };
|
||||
# defaultPackage = pkgs.libsForQt5.callPackage ./default.nix { };
|
||||
});
|
||||
}
|
||||
|
|
2
justfile
2
justfile
|
@ -15,7 +15,7 @@ test:
|
|||
RUST_LOG=debug cargo test --benches --tests --all-features -- --nocapture
|
||||
|
||||
testcore:
|
||||
RUST_LOG=debug cargo test -p core --benches --tests --all-features -- --nocapture
|
||||
RUST_LOG=debug cargo test -p lumina_core --benches --tests --all-features -- --nocapture
|
||||
|
||||
alias b := build
|
||||
alias r := run
|
||||
|
|
17
smdview/blah/Cargo.toml
Normal file
17
smdview/blah/Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "blah"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
cxx = "1.0.122"
|
||||
cxx-qt = "0.7.1"
|
||||
cxx-qt-lib = { version = "0.7.1", features = [ "qt_full" ] }
|
||||
cxx-qt-lib-extras = "0.7.1"
|
||||
markdown = "=1.0.0-alpha.17"
|
||||
|
||||
[build-dependencies]
|
||||
# The link_qt_object_files feature is required for statically linking Qt 6.
|
||||
cxx-qt-build = { version = "0.7.1", features = [ "link_qt_object_files" ] }
|
||||
qt-build-utils = "0.7.1"
|
||||
|
12
smdview/blah/build.rs
Normal file
12
smdview/blah/build.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
use cxx_qt_build::{CxxQtBuilder, QmlModule};
|
||||
|
||||
fn main() {
|
||||
CxxQtBuilder::new()
|
||||
.qml_module(QmlModule {
|
||||
uri: "org.kde.simplemdviewer",
|
||||
qml_files: &["src/qml/Main.qml"],
|
||||
rust_files: &["src/main.rs"],
|
||||
..Default::default()
|
||||
})
|
||||
.build();
|
||||
}
|
42
smdview/blah/src/main.rs
Normal file
42
smdview/blah/src/main.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
#[cxx_qt::bridge]
|
||||
mod ffi {
|
||||
extern "RustQt" {
|
||||
#[qobject]
|
||||
type DummyQObject = super::DummyRustStruct;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DummyRustStruct;
|
||||
|
||||
use cxx_qt_lib::{
|
||||
QGuiApplication, QQmlApplicationEngine, QQuickStyle, QString,
|
||||
QUrl,
|
||||
};
|
||||
use cxx_qt_lib_extras::QApplication;
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let mut app = QApplication::new();
|
||||
|
||||
// To associate the executable to the installed desktop file
|
||||
QGuiApplication::set_desktop_file_name(&QString::from(
|
||||
"org.kde.simplemdviewer",
|
||||
));
|
||||
|
||||
// To ensure the style is set correctly
|
||||
if env::var("QT_QUICK_CONTROLS_STYLE").is_err() {
|
||||
QQuickStyle::set_style(&QString::from("org.kde.desktop"));
|
||||
}
|
||||
|
||||
let mut engine = QQmlApplicationEngine::new();
|
||||
if let Some(engine) = engine.as_mut() {
|
||||
engine.load(&QUrl::from(
|
||||
"qrc:/qt/qml/org/kde/simplemdviewer/src/qml/Main.qml",
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(app) = app.as_mut() {
|
||||
app.exec();
|
||||
}
|
||||
}
|
71
smdview/blah/src/qml/main.qml
Normal file
71
smdview/blah/src/qml/main.qml
Normal file
|
@ -0,0 +1,71 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Controls
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Kirigami.ApplicationWindow {
|
||||
id: root
|
||||
|
||||
title: "Simple Markdown Viewer in Rust 🦀"
|
||||
|
||||
minimumWidth: Kirigami.Units.gridUnit * 20
|
||||
minimumHeight: Kirigami.Units.gridUnit * 20
|
||||
width: minimumWidth
|
||||
height: minimumHeight
|
||||
|
||||
pageStack.initialPage: initPage
|
||||
|
||||
Component {
|
||||
id: initPage
|
||||
|
||||
Kirigami.Page {
|
||||
title: "Markdown Viewer"
|
||||
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
Controls.TextArea {
|
||||
id: sourceArea
|
||||
|
||||
placeholderText: "Write some Markdown code here"
|
||||
wrapMode: Text.WrapAnywhere
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Controls.Button {
|
||||
text: "Format"
|
||||
|
||||
onClicked: formattedText.text = sourceArea.text
|
||||
}
|
||||
|
||||
Controls.Button {
|
||||
text: "Clear"
|
||||
|
||||
onClicked: {
|
||||
sourceArea.text = ""
|
||||
formattedText.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: formattedText
|
||||
|
||||
textFormat: Text.RichText
|
||||
wrapMode: Text.WordWrap
|
||||
text: sourceArea.text
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
101
src/main.cpp
101
src/main.cpp
|
@ -1,49 +1,49 @@
|
|||
#include <QApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
// #include <QApplication>
|
||||
#include <QtQml/QQmlApplicationEngine>
|
||||
#include <QtCore/qstringliteral.h>
|
||||
#include <QtQml>
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
#include <KLocalizedContext>
|
||||
#include <KLocalizedString>
|
||||
#include <KAboutData>
|
||||
#include <QtQml/QtQml>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QDebug>
|
||||
// #include <K/KLocalizedContext>
|
||||
// #include <KLocalizedString>
|
||||
// #include <KAboutData>
|
||||
#include <iostream>
|
||||
#include <QQmlEngine>
|
||||
#include <QtWebEngineQuick>
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
#include <QOpenGLContext>
|
||||
#include <QGuiApplication>
|
||||
#include <QQuickStyle>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QtQml/QQmlEngine>
|
||||
#include <QtWebEngineQuick/QtWebEngineQuick>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtQuickControls2/QQuickStyle>
|
||||
// #include <QSurfaceFormat>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtQuick/QQuickView>
|
||||
#include <qapplication.h>
|
||||
#include <qcoreapplication.h>
|
||||
#include <qdir.h>
|
||||
#include <qglobal.h>
|
||||
#include <qguiapplication.h>
|
||||
#include <qqml.h>
|
||||
#include <qquickstyle.h>
|
||||
#include <qstringliteral.h>
|
||||
// #include <qapplication.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtQml/qqml.h>
|
||||
#include <QtQuickControls2/qquickstyle.h>
|
||||
#include <QtCore/qstringliteral.h>
|
||||
// #include <MpvAbstractItem>
|
||||
// #include "cpp/mpv/mpvitem.h"
|
||||
// #include "cpp/mpv/mpvproperties.h"
|
||||
|
||||
// RUST
|
||||
#include "cxx-qt-gen/file_helper.cxxqt.h"
|
||||
#include "cxx-qt-gen/slide_object.cxxqt.h"
|
||||
#include "cxx-qt-gen/slide_model.cxxqt.h"
|
||||
#include "cxx-qt-gen/service_item_model.cxxqt.h"
|
||||
#include "cxx-qt-gen/settings.cxxqt.h"
|
||||
#include "cxx-qt-gen/ytdl.cxxqt.h"
|
||||
#include "cxx-qt-gen/presentation_model.cxxqt.h"
|
||||
#include "cxx-qt-gen/song_model.cxxqt.h"
|
||||
#include "cxx-qt-gen/video_model.cxxqt.h"
|
||||
#include "cxx-qt-gen/image_model.cxxqt.h"
|
||||
#include "cxx-qt-gen/utils.cxxqt.h"
|
||||
#include "cxx-qt-gen/song_editor.cxxqt.h"
|
||||
#include "cxx-qt-gen/obs.cxxqt.h"
|
||||
#include <liblumina/src/rust/file_helper.cxxqt.h>
|
||||
#include <liblumina/src/rust/slide_object.cxxqt.h>
|
||||
#include <liblumina/src/rust/slide_model.cxxqt.h>
|
||||
#include <liblumina/src/rust/service_item_model.cxxqt.h>
|
||||
#include <liblumina/src/rust/settings.cxxqt.h>
|
||||
#include <liblumina/src/rust/ytdl.cxxqt.h>
|
||||
#include <liblumina/src/rust/presentation_model.cxxqt.h>
|
||||
#include <liblumina/src/rust/songs/song_model.cxxqt.h>
|
||||
#include <liblumina/src/rust/video_model.cxxqt.h>
|
||||
#include <liblumina/src/rust/image_model.cxxqt.h>
|
||||
#include <liblumina/src/rust/utils.cxxqt.h>
|
||||
#include <liblumina/src/rust/songs/song_editor.cxxqt.h>
|
||||
#include <liblumina/src/rust/obs.cxxqt.h>
|
||||
|
||||
static QWindow *windowFromEngine(QQmlApplicationEngine *engine)
|
||||
{
|
||||
|
@ -60,22 +60,22 @@ int main(int argc, char *argv[])
|
|||
QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("video-display")));
|
||||
QtWebEngineQuick::initialize();
|
||||
QGuiApplication app(argc, argv);
|
||||
KLocalizedString::setApplicationDomain("lumina");
|
||||
KAboutData about;
|
||||
about.setComponentName(QStringLiteral("lumina"));
|
||||
about.setDisplayName(i18n("lumina"));
|
||||
about.setVersion(QByteArray("0.1"));
|
||||
about.setShortDescription(i18n("A churchpresentation app build with KDE tech."));
|
||||
about.setLicense(KAboutLicense::GPL_V3);
|
||||
// KLocalizedString::setApplicationDomain("lumina");
|
||||
// KAboutData about;
|
||||
// about.setComponentName(QStringLiteral("lumina"));
|
||||
// about.setDisplayName(i18n("lumina"));
|
||||
// about.setVersion(QByteArray("0.1"));
|
||||
// about.setShortDescription(i18n("A churchpresentation app build with KDE tech."));
|
||||
// about.setLicense(KAboutLicense::GPL_V3);
|
||||
|
||||
// overwrite default-generated values of organizationDomain & desktopFileName
|
||||
about.setOrganizationDomain("tfcconnection.org");
|
||||
about.setDesktopFileName(QStringLiteral("org.tfcconneciton.lumina"));
|
||||
// about.setOrganizationDomain("tfcconnection.org");
|
||||
// about.setDesktopFileName(QStringLiteral("org.tfcconneciton.lumina"));
|
||||
|
||||
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
|
||||
|
||||
// set the application metadata
|
||||
KAboutData::setApplicationData(about);
|
||||
// KAboutData::setApplicationData(about);
|
||||
QCoreApplication::setOrganizationName(QStringLiteral("lumina"));
|
||||
QCoreApplication::setOrganizationDomain(QStringLiteral("tfcconnection.org"));
|
||||
QCoreApplication::setApplicationName(QStringLiteral("lumina"));
|
||||
|
@ -93,7 +93,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
// qDebug() << QQuickStyle::availableStyles();
|
||||
qDebug() << QIcon::themeName();
|
||||
qDebug() << QApplication::platformName();
|
||||
// qDebug() << QApplication::platformName();
|
||||
|
||||
//Need to instantiate our slide
|
||||
QScopedPointer<SlideModel> slideModel(new SlideModel);
|
||||
|
@ -108,6 +108,7 @@ int main(int argc, char *argv[])
|
|||
settings->setup();
|
||||
|
||||
QQuickView *PresWindow = new QQuickView;
|
||||
PresWindow->setSource(QUrl(QStringLiteral("qrc:qml/presenter/PresentationWindow.qml")));
|
||||
qDebug() << PresWindow;
|
||||
qDebug() << PresWindow->isVisible();
|
||||
|
||||
|
@ -169,9 +170,9 @@ int main(int argc, char *argv[])
|
|||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "SlideModel", slideModel.get());
|
||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "Utils", utils);
|
||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "SlideObject", slideobject.get());
|
||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "PresWindow", PresWindow);
|
||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "RSettings", settings);
|
||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "ObsModel", obsModel.get());
|
||||
qmlRegisterSingletonInstance("org.presenter", 1, 0, "PresWindow", PresWindow);
|
||||
|
||||
// This is the same slideobject, however to enusre that the PresWindow can have it
|
||||
// we need to set it as a separate context so that it can change it's slides too.
|
||||
|
@ -184,7 +185,7 @@ int main(int argc, char *argv[])
|
|||
QQmlApplicationEngine engine;
|
||||
qDebug() << app.allWindows();
|
||||
|
||||
engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
|
||||
// engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
|
||||
engine.load(QUrl(QStringLiteral("qrc:qml/main.qml")));
|
||||
qDebug() << "Engine loaded";
|
||||
|
||||
|
|
|
@ -252,6 +252,7 @@ Item {
|
|||
}
|
||||
|
||||
function isDragFile(item) {
|
||||
console.log(item);
|
||||
console.log(item.toString());
|
||||
var extension = item.toString().split('.').pop();
|
||||
var valid = false;
|
||||
|
|
|
@ -188,6 +188,10 @@ Controls.Page {
|
|||
songModel: songModel
|
||||
}
|
||||
|
||||
Presenter.PresentationWindow {
|
||||
id: presWindow
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ServiceItemModel
|
||||
function onSaveProgressChanged() {
|
||||
|
@ -352,19 +356,20 @@ Controls.Page {
|
|||
function present(present) {
|
||||
if (present)
|
||||
{
|
||||
PresWindow.showFullScreen();
|
||||
PresWindow.setSource("qrc:qml/presenter/PresentationWindow.qml")
|
||||
console.log(PresWindow);
|
||||
/* presWindow.slideObj = SlideObject; */
|
||||
presWindow.showFullScreen();
|
||||
/* presWindow.setSource("qrc:qml/presenter/PresentationWindow.qml") */
|
||||
console.log(presWindow);
|
||||
/* presWinLoader.active = true; */
|
||||
}
|
||||
else {
|
||||
PresWindow.close();
|
||||
presWindow.close();
|
||||
|
||||
/* presWinLoader.active = false; */
|
||||
}
|
||||
}
|
||||
|
||||
function closeAll() { PresWindow.close() }
|
||||
function closeAll() { presWindow.close() }
|
||||
|
||||
function changeVidPos(pos) {
|
||||
presentation.slide.seek(pos);
|
||||
|
|
|
@ -479,6 +479,11 @@ FocusScope {
|
|||
previewSlide.stopVideo()
|
||||
}
|
||||
|
||||
function playVideo() {
|
||||
/* showPassiveNotification("Stopping Video") */
|
||||
previewSlide.playVideo()
|
||||
}
|
||||
|
||||
function nextSlideAction() {
|
||||
keyHandler.forceActiveFocus();
|
||||
SlideModel.next()
|
||||
|
|
|
@ -6,13 +6,13 @@ import org.kde.kirigami 2.13 as Kirigami
|
|||
import "./" as Presenter
|
||||
import org.presenter 1.0
|
||||
|
||||
Item {
|
||||
Window {
|
||||
id: presentationWindow
|
||||
|
||||
property Item slide: presentationSlide
|
||||
/* property var slideObj */
|
||||
/* property var SlideObject: SlideObject; */
|
||||
property var pWin
|
||||
anchors.fill: parent
|
||||
/* anchors.fill: parent */
|
||||
|
||||
/* title: "presentation-window" */
|
||||
/* height: maximumHeight */
|
||||
|
@ -25,7 +25,7 @@ Item {
|
|||
|
||||
/* onClosing: { */
|
||||
/* presentationSlide.stopVideo(); */
|
||||
/* SlideObj.pause(); */
|
||||
/* SlideObject.pause(); */
|
||||
/* presentationSlide.stopAudio(); */
|
||||
/* presenting = false; */
|
||||
/* } */
|
||||
|
@ -34,7 +34,7 @@ Item {
|
|||
target: PresWindow
|
||||
function onClosing() {
|
||||
presentationSlide.stopVideo();
|
||||
SlideObj.pause();
|
||||
SlideObject.pause();
|
||||
presentationSlide.stopAudio();
|
||||
presenting = false;
|
||||
}
|
||||
|
@ -48,25 +48,25 @@ Item {
|
|||
Presenter.Slide {
|
||||
id: presentationSlide
|
||||
anchors.fill: parent
|
||||
imageSource: SlideObj.html ? "" : SlideObj.imageBackground
|
||||
webSource: SlideObj.html ? SlideObj.imageBackground : ""
|
||||
htmlVisible: SlideObj.html
|
||||
videoSource: presentationWindow.visible ? SlideObj.videoBackground : ""
|
||||
audioSource: SlideObj.audio
|
||||
text: SlideObj.text
|
||||
chosenFont: SlideObj.font
|
||||
textSize: SlideObj.fontSize
|
||||
pdfIndex: SlideObj.slideIndex
|
||||
itemType: SlideObj.ty
|
||||
vidLoop: SlideObj.looping
|
||||
vidStartTime: SlideObj.videoStartTime
|
||||
vidEndTime: SlideObj.videoEndTime
|
||||
imageSource: SlideObject.html ? "" : SlideObject.imageBackground
|
||||
webSource: SlideObject.html ? SlideObject.imageBackground : ""
|
||||
htmlVisible: SlideObject.html
|
||||
videoSource: presentationWindow.visible ? SlideObject.videoBackground : ""
|
||||
audioSource: SlideObject.audio
|
||||
text: SlideObject.text
|
||||
chosenFont: SlideObject.font
|
||||
textSize: SlideObject.fontSize
|
||||
pdfIndex: SlideObject.slideIndex
|
||||
itemType: SlideObject.ty
|
||||
vidLoop: SlideObject.looping
|
||||
vidStartTime: SlideObject.videoStartTime
|
||||
vidEndTime: SlideObject.videoEndTime
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SlideObj
|
||||
target: SlideObject
|
||||
function onVideoBackgroundChanged() {
|
||||
if (SlideObj.videoBackground === "")
|
||||
if (SlideObject.videoBackground === "")
|
||||
stopVideo();
|
||||
else {
|
||||
loadVideo();
|
||||
|
@ -74,12 +74,12 @@ Item {
|
|||
}
|
||||
}
|
||||
function onIsPlayingChanged() {
|
||||
if(SlideObj.isPlaying)
|
||||
if(SlideObject.isPlaying)
|
||||
presentationSlide.playVideo();
|
||||
pauseVideo();
|
||||
}
|
||||
function onLoopingChanged() {
|
||||
if(SlideObj.looping)
|
||||
if(SlideObject.looping)
|
||||
presentationSlide.loopVideo();
|
||||
}
|
||||
function onAudioChanged() {
|
||||
|
|
|
@ -21,6 +21,7 @@ Kirigami.OverlaySheet {
|
|||
|
||||
Kirigami.FormLayout {
|
||||
implicitHeight: Kirigami.Units.gridUnit * 30
|
||||
implicitWidth: Kirigami.Units.gridUnit * 30
|
||||
Controls.ComboBox {
|
||||
id: screenSelectionField
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Presentation Screen:")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "lumina-core"
|
||||
name = "lumina_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = [
|
||||
|
|
|
@ -1,82 +1,133 @@
|
|||
use crate::{
|
||||
images::{get_image_from_db, Image},
|
||||
kinds::ServiceItemKind,
|
||||
model::get_db,
|
||||
presentations::{
|
||||
get_presentation_from_db, PresKind, Presentation,
|
||||
},
|
||||
service_items::ServiceItem,
|
||||
slides::Background,
|
||||
songs::{get_song_from_db, Song},
|
||||
videos::{get_video_from_db, Video},
|
||||
};
|
||||
use color_eyre::eyre::{eyre, Context, Result};
|
||||
use serde_json::Value;
|
||||
use sqlx::{query, query_as, FromRow, SqliteConnection};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
iter,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tar::{Archive, Builder};
|
||||
use tracing::error;
|
||||
use zstd::Encoder;
|
||||
use std::{fs::{self, File}, future::Future, iter, path::{Path, PathBuf}};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use serde_json::Value;
|
||||
use sqlx::{query, query_as, FromRow, SqliteConnection};
|
||||
use crate::{images::{get_image_from_db, Image}, kinds::ServiceItemKind, model::get_db, presentations::{get_presentation_from_db, PresKind, Presentation}, service_items::ServiceItem, slides::Background, songs::{get_song_from_db, Song}, videos::{get_video_from_db, Video}};
|
||||
|
||||
pub async fn save(list: Vec<ServiceItem>, path: impl AsRef<Path>) -> Result<()> {
|
||||
pub async fn save(
|
||||
list: Vec<ServiceItem>,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
let save_file = File::create(path)?;
|
||||
let mut db = get_db().await;
|
||||
let json = process_service_items(&list, &mut db).await?;
|
||||
let archive = store_service_items(&list, &mut db, &save_file, &json).await?;
|
||||
let archive =
|
||||
store_service_items(&list, &mut db, &save_file, &json)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn store_service_items(items: &Vec<ServiceItem>, db: &mut SqliteConnection, save_file: &File, json: &Value) -> Result<()> {
|
||||
async fn store_service_items(
|
||||
items: &Vec<ServiceItem>,
|
||||
db: &mut SqliteConnection,
|
||||
save_file: &File,
|
||||
json: &Value,
|
||||
) -> Result<()> {
|
||||
let encoder = Encoder::new(save_file, 3).unwrap();
|
||||
let mut tar = Builder::new(encoder);
|
||||
let mut temp_dir = dirs::data_dir().unwrap();
|
||||
temp_dir.push("lumina");
|
||||
let mut s: String =
|
||||
iter::repeat_with(fastrand::alphanumeric)
|
||||
.take(5)
|
||||
.collect();
|
||||
iter::repeat_with(fastrand::alphanumeric).take(5).collect();
|
||||
s.insert_str(0, "temp_");
|
||||
temp_dir.push(s);
|
||||
fs::create_dir_all(&temp_dir)?;
|
||||
let service_file = temp_dir.join("serviceitems.json");
|
||||
fs::File::create(&service_file)?;
|
||||
match fs::File::options().read(true).write(true).open(service_file) {
|
||||
match fs::File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(service_file)
|
||||
{
|
||||
Ok(f) => {
|
||||
serde_json::to_writer_pretty(f, json)?;
|
||||
},
|
||||
Err(e) => error!("There were problems making a file i guess: {e}"),
|
||||
}
|
||||
Err(e) => {
|
||||
error!("There were problems making a file i guess: {e}")
|
||||
}
|
||||
};
|
||||
for item in items {
|
||||
let background;
|
||||
let audio: Option<PathBuf>;
|
||||
match item.kind {
|
||||
ServiceItemKind::Song => {
|
||||
let song = get_song_from_db(item.database_id, db).await?;
|
||||
let song =
|
||||
get_song_from_db(item.database_id, db).await?;
|
||||
background = song.background;
|
||||
audio = song.audio;
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Image => {
|
||||
let image = get_image_from_db(item.database_id, db).await?;
|
||||
let image =
|
||||
get_image_from_db(item.database_id, db).await?;
|
||||
background = Some(Background::try_from(image.path)?);
|
||||
audio = None;
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Video => {
|
||||
let video = get_video_from_db(item.database_id, db).await?;
|
||||
let video =
|
||||
get_video_from_db(item.database_id, db).await?;
|
||||
background = Some(Background::try_from(video.path)?);
|
||||
audio = None;
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Presentation(_) => {
|
||||
let presentation = get_presentation_from_db(item.database_id, db).await?;
|
||||
background = Some(Background::try_from(presentation.path)?);
|
||||
let presentation =
|
||||
get_presentation_from_db(item.database_id, db)
|
||||
.await?;
|
||||
background =
|
||||
Some(Background::try_from(presentation.path)?);
|
||||
audio = None;
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Content => {
|
||||
todo!()
|
||||
},
|
||||
}
|
||||
};
|
||||
if let Some(file) = audio {
|
||||
let audio_file = temp_dir.join(file.file_name().expect("Audio file couldn't be added to temp_dir"));
|
||||
match fs::File::create(&audio_file) {
|
||||
Ok(_) => Ok(fs::copy(file, &audio_file)?),
|
||||
Err(e) => Err(eyre!("Couldn't create audio file: {e}")),
|
||||
}?;
|
||||
let audio_file =
|
||||
temp_dir.join(file.file_name().expect(
|
||||
"Audio file couldn't be added to temp_dir",
|
||||
));
|
||||
if let Ok(file) = file.strip_prefix("file://") {
|
||||
fs::File::create(&audio_file)
|
||||
.wrap_err("Couldn't create audio file")?;
|
||||
fs::copy(file, audio_file).wrap_err("Audio file could not be copied, the source file doesn't exist not be found");
|
||||
} else {
|
||||
fs::File::create(&audio_file)
|
||||
.wrap_err("Couldn't create audio file")?;
|
||||
fs::copy(file, audio_file).wrap_err("Audio file could not be copied, the source file doesn't exist not be found");
|
||||
}
|
||||
};
|
||||
if let Some(file) = background {
|
||||
let background_file = temp_dir.join(file.path.file_name().expect("Background file couldn't be added to temp_dir"));
|
||||
match fs::File::create(&background_file) {
|
||||
Ok(_) => Ok(fs::copy(file.path, &background_file)?),
|
||||
Err(e) => Err(eyre!("Couldn't create background file: {e}")),
|
||||
}?;
|
||||
let background_file =
|
||||
temp_dir.join(file.path.file_name().expect(
|
||||
"Background file couldn't be added to temp_dir",
|
||||
));
|
||||
if let Ok(file) = file.path.strip_prefix("file://") {
|
||||
fs::File::create(&background_file)
|
||||
.wrap_err("Couldn't create background file")?;
|
||||
fs::copy(file, background_file).wrap_err("Background file could not be copied, the source file doesn't exist not be found");
|
||||
} else {
|
||||
fs::File::create(&background_file)
|
||||
.wrap_err("Couldn't create background file")?;
|
||||
fs::copy(file.path, background_file).wrap_err("Background file could not be copied, the source file doesn't exist not be found");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -86,66 +137,96 @@ async fn clear_temp_dir(temp_dir: &Path) -> Result<()> {
|
|||
todo!()
|
||||
}
|
||||
|
||||
async fn process_service_items(items: &Vec<ServiceItem>, db: &mut SqliteConnection) -> Result<Value> {
|
||||
async fn process_service_items(
|
||||
items: &Vec<ServiceItem>,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Value> {
|
||||
let mut values: Vec<Value> = vec![];
|
||||
for item in items {
|
||||
match item.kind {
|
||||
ServiceItemKind::Song => {
|
||||
let value = process_song(item.database_id, db).await?;
|
||||
let value =
|
||||
process_song(item.database_id, db).await?;
|
||||
values.push(value);
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Image => {
|
||||
let value = process_image(item.database_id, db).await?;
|
||||
let value =
|
||||
process_image(item.database_id, db).await?;
|
||||
values.push(value);
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Video => {
|
||||
let value = process_video(item.database_id, db).await?;
|
||||
let value =
|
||||
process_video(item.database_id, db).await?;
|
||||
values.push(value);
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Presentation(_) => {
|
||||
let value = process_presentation(item.database_id, db).await?;
|
||||
let value =
|
||||
process_presentation(item.database_id, db)
|
||||
.await?;
|
||||
values.push(value);
|
||||
},
|
||||
}
|
||||
ServiceItemKind::Content => {
|
||||
todo!()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
let json = Value::from(values);
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
async fn process_song(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
|
||||
async fn process_song(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Value> {
|
||||
let song = get_song_from_db(database_id, db).await?;
|
||||
let song_json = serde_json::to_value(&song)?;
|
||||
let kind_json = serde_json::to_value(ServiceItemKind::Song)?;
|
||||
let json = serde_json::json!({"item": song_json, "kind": kind_json});
|
||||
let json =
|
||||
serde_json::json!({"item": song_json, "kind": kind_json});
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
async fn process_image(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
|
||||
async fn process_image(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Value> {
|
||||
let image = get_image_from_db(database_id, db).await?;
|
||||
let image_json = serde_json::to_value(&image)?;
|
||||
let kind_json = serde_json::to_value(ServiceItemKind::Image)?;
|
||||
let json = serde_json::json!({"item": image_json, "kind": kind_json});
|
||||
let json =
|
||||
serde_json::json!({"item": image_json, "kind": kind_json});
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
async fn process_video(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
|
||||
async fn process_video(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Value> {
|
||||
let video = get_video_from_db(database_id, db).await?;
|
||||
let video_json = serde_json::to_value(&video)?;
|
||||
let kind_json = serde_json::to_value(ServiceItemKind::Video)?;
|
||||
let json = serde_json::json!({"item": video_json, "kind": kind_json});
|
||||
let json =
|
||||
serde_json::json!({"item": video_json, "kind": kind_json});
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
async fn process_presentation(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
|
||||
let presentation = get_presentation_from_db(database_id, db).await?;
|
||||
async fn process_presentation(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Value> {
|
||||
let presentation =
|
||||
get_presentation_from_db(database_id, db).await?;
|
||||
let presentation_json = serde_json::to_value(&presentation)?;
|
||||
let kind_json = match presentation.kind {
|
||||
PresKind::Html => serde_json::to_value(ServiceItemKind::Presentation(PresKind::Html))?,
|
||||
PresKind::Pdf => serde_json::to_value(ServiceItemKind::Presentation(PresKind::Pdf))?,
|
||||
PresKind::Generic => serde_json::to_value(ServiceItemKind::Presentation(PresKind::Generic))?,
|
||||
PresKind::Html => serde_json::to_value(
|
||||
ServiceItemKind::Presentation(PresKind::Html),
|
||||
)?,
|
||||
PresKind::Pdf => serde_json::to_value(
|
||||
ServiceItemKind::Presentation(PresKind::Pdf),
|
||||
)?,
|
||||
PresKind::Generic => serde_json::to_value(
|
||||
ServiceItemKind::Presentation(PresKind::Generic),
|
||||
)?,
|
||||
};
|
||||
let json = serde_json::json!({"item": presentation_json, "kind": kind_json});
|
||||
Ok(json)
|
||||
|
@ -155,11 +236,11 @@ async fn process_presentation(database_id: i32, db: &mut SqliteConnection) -> Re
|
|||
mod test {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use fs::canonicalize;
|
||||
use sqlx::Connection;
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
use tracing::debug;
|
||||
use super::*;
|
||||
use fs::canonicalize;
|
||||
use pretty_assertions::assert_eq;
|
||||
use sqlx::Connection;
|
||||
use tracing::debug;
|
||||
|
||||
async fn get_db() -> SqliteConnection {
|
||||
let mut data = dirs::data_local_dir().unwrap();
|
||||
|
@ -167,9 +248,7 @@ mod test {
|
|||
data.push("library-db.sqlite3");
|
||||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
|
@ -239,7 +318,8 @@ mod test {
|
|||
async fn test_process_presentation() {
|
||||
let mut db = get_db().await;
|
||||
let result = process_presentation(54, &mut db).await;
|
||||
let json_presentation_file = PathBuf::from("./test/test_presentation.json");
|
||||
let json_presentation_file =
|
||||
PathBuf::from("./test/test_presentation.json");
|
||||
if let Ok(path) = canonicalize(json_presentation_file) {
|
||||
debug!(file = ?&path);
|
||||
if let Ok(s) = fs::read_to_string(path) {
|
||||
|
@ -252,7 +332,9 @@ mod test {
|
|||
panic!("String wasn't read from file");
|
||||
}
|
||||
} else {
|
||||
panic!("Cannot find absolute path to test_presentation.json");
|
||||
panic!(
|
||||
"Cannot find absolute path to test_presentation.json"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,7 +363,8 @@ mod test {
|
|||
async fn test_service_items() {
|
||||
let mut db = get_db().await;
|
||||
let items = get_items();
|
||||
let json_item_file = PathBuf::from("./test/test_service_items.json");
|
||||
let json_item_file =
|
||||
PathBuf::from("./test/test_service_items.json");
|
||||
let result = process_service_items(&items, &mut db).await;
|
||||
if let Ok(path) = canonicalize(json_item_file) {
|
||||
if let Ok(s) = fs::read_to_string(path) {
|
||||
|
@ -305,16 +388,23 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn test_store() {
|
||||
let path = PathBuf::from("/home/chris/dev/lumina/src/rust/core/test.pres");
|
||||
let save_file = match File::create(path) {
|
||||
let path = PathBuf::from(
|
||||
"/home/chris/dev/lumina/src/rust/core/test.pres",
|
||||
);
|
||||
let save_file = match File::create(path) {
|
||||
Ok(f) => f,
|
||||
Err(e) => panic!("Couldn't create save_file: {e}"),
|
||||
};
|
||||
let mut db = get_db().await;
|
||||
let list = get_items();
|
||||
if let Ok(json) = process_service_items(&list, &mut db).await {
|
||||
if let Ok(json) = process_service_items(&list, &mut db).await
|
||||
{
|
||||
println!("{:?}", json);
|
||||
match store_service_items(&list, &mut db, &save_file, &json).await {
|
||||
match store_service_items(
|
||||
&list, &mut db, &save_file, &json,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => assert!(true),
|
||||
Err(e) => panic!("There was an error: {e}"),
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ use sqlx::{query_as, SqliteConnection};
|
|||
use std::path::PathBuf;
|
||||
use tracing::error;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Image {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
|
@ -16,7 +18,7 @@ impl Model<Image> {
|
|||
pub fn load_from_db(&mut self) {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Image, r#"SELECT title as "title!", filePath as "path!", id as "id: i32" from images"#).fetch_all(&mut self.db).await;
|
||||
let result = query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images"#).fetch_all(&mut self.db).await;
|
||||
match result {
|
||||
Ok(v) => {
|
||||
for image in v.into_iter() {
|
||||
|
@ -29,9 +31,11 @@ impl Model<Image> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn get_image_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Image> {
|
||||
Ok(query_as!(Image, r#"SELECT title as "title!", filePath as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await?)
|
||||
pub async fn get_image_from_db(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Image> {
|
||||
Ok(query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -67,7 +71,10 @@ mod test {
|
|||
let new_image = test_image("A newer image".into());
|
||||
match result {
|
||||
Ok(_) => {
|
||||
assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap());
|
||||
assert_eq!(
|
||||
&image,
|
||||
image_model.find(|i| i.id == 0).unwrap()
|
||||
);
|
||||
assert_ne!(
|
||||
&new_image,
|
||||
image_model.find(|i| i.id == 0).unwrap()
|
||||
|
|
|
@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::presentations::PresKind;
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum ServiceItemKind {
|
||||
#[default]
|
||||
Song,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod file;
|
||||
pub mod images;
|
||||
pub mod kinds;
|
||||
pub mod model;
|
||||
|
@ -6,4 +7,3 @@ pub mod service_items;
|
|||
pub mod slides;
|
||||
pub mod songs;
|
||||
pub mod videos;
|
||||
pub mod file;
|
||||
|
|
1
src/rust/core/mod.rs
Normal file
1
src/rust/core/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
mod service_items;
|
|
@ -36,8 +36,7 @@ impl<T> Model<T> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_item(&self, index: i32) -> Option<&T>
|
||||
{
|
||||
pub fn get_item(&self, index: i32) -> Option<&T> {
|
||||
self.items.get(index as usize)
|
||||
}
|
||||
|
||||
|
@ -60,10 +59,8 @@ impl<T> Default for Model<T> {
|
|||
items: vec![],
|
||||
db: {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
get_db().await
|
||||
})
|
||||
}
|
||||
rt.block_on(async { get_db().await })
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,9 +71,7 @@ pub async fn get_db() -> SqliteConnection {
|
|||
data.push("library-db.sqlite3");
|
||||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
}
|
||||
|
||||
pub trait Modeling {
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
use std::path::PathBuf;
|
||||
use color_eyre::eyre::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection};
|
||||
use sqlx::{
|
||||
prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use tracing::error;
|
||||
|
||||
use crate::model::Model;
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum PresKind {
|
||||
Html,
|
||||
#[default]
|
||||
|
@ -14,7 +18,9 @@ pub enum PresKind {
|
|||
Generic,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Presentation {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
|
@ -57,7 +63,7 @@ impl Model<Presentation> {
|
|||
pub fn load_from_db(&mut self) {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations"#).fetch_all(&mut self.db).await;
|
||||
let result = query!(r#"SELECT id as "id: i32", title, file_path as "path", html from presentations"#).fetch_all(&mut self.db).await;
|
||||
match result {
|
||||
Ok(v) => {
|
||||
for presentation in v.into_iter() {
|
||||
|
@ -79,8 +85,11 @@ impl Model<Presentation> {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn get_presentation_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Presentation> {
|
||||
let row = query(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations where id = $1"#).bind(database_id).fetch_one(db).await?;
|
||||
pub async fn get_presentation_from_db(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Presentation> {
|
||||
let row = query(r#"SELECT id as "id: i32", title, file_path as "path", html from presentations where id = $1"#).bind(database_id).fetch_one(db).await?;
|
||||
Ok(Presentation::from_row(&row)?)
|
||||
}
|
||||
|
||||
|
@ -111,7 +120,9 @@ mod test {
|
|||
let mut presentation_model: Model<Presentation> =
|
||||
Model::default();
|
||||
presentation_model.load_from_db();
|
||||
if let Some(presentation) = presentation_model.find(|p| p.id == 54) {
|
||||
if let Some(presentation) =
|
||||
presentation_model.find(|p| p.id == 54)
|
||||
{
|
||||
let test_presentation = test_presentation();
|
||||
assert_eq!(&test_presentation, presentation);
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,7 @@ pub struct ServiceItem {
|
|||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
struct ServiceItemModel {
|
||||
pub struct ServiceItemModel {
|
||||
items: Vec<ServiceItem>,
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,9 @@ impl From<&Image> for ServiceItem {
|
|||
impl From<&Presentation> for ServiceItem {
|
||||
fn from(presentation: &Presentation) -> Self {
|
||||
Self {
|
||||
kind: ServiceItemKind::Presentation(presentation.kind.clone()),
|
||||
kind: ServiceItemKind::Presentation(
|
||||
presentation.kind.clone(),
|
||||
),
|
||||
database_id: presentation.id,
|
||||
..Default::default()
|
||||
}
|
||||
|
@ -60,7 +62,10 @@ impl From<&Presentation> for ServiceItem {
|
|||
}
|
||||
|
||||
impl ServiceItemModel {
|
||||
fn add_item(&mut self, item: impl Into<ServiceItem>) -> Result<()> {
|
||||
fn add_item(
|
||||
&mut self,
|
||||
item: impl Into<ServiceItem>,
|
||||
) -> Result<()> {
|
||||
let service_item: ServiceItem = item.into();
|
||||
self.items.push(service_item);
|
||||
Ok(())
|
||||
|
@ -94,7 +99,6 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
pub fn test_service_item() {
|
||||
let song = test_song();
|
||||
|
@ -104,10 +108,16 @@ mod test {
|
|||
let mut service_model = ServiceItemModel::default();
|
||||
match service_model.add_item(&song) {
|
||||
Ok(_) => {
|
||||
assert_eq!(ServiceItemKind::Song, service_model.items[0].kind);
|
||||
assert_eq!(ServiceItemKind::Presentation(PresKind::Html), pres_item.kind);
|
||||
assert_eq!(
|
||||
ServiceItemKind::Song,
|
||||
service_model.items[0].kind
|
||||
);
|
||||
assert_eq!(
|
||||
ServiceItemKind::Presentation(PresKind::Html),
|
||||
pres_item.kind
|
||||
);
|
||||
assert_eq!(service_item, service_model.items[0]);
|
||||
},
|
||||
}
|
||||
Err(e) => panic!("Problem adding item: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use std::{error::Error, fmt::Display, path::{Path, PathBuf}};
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -10,7 +14,9 @@ use crate::{
|
|||
presentations::Presentation, songs::Song, videos::Video,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum TextAlignment {
|
||||
TopLeft,
|
||||
TopCenter,
|
||||
|
@ -24,7 +30,9 @@ pub enum TextAlignment {
|
|||
BottomRight,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Background {
|
||||
pub path: PathBuf,
|
||||
pub kind: BackgroundKind,
|
||||
|
@ -36,7 +44,7 @@ impl TryFrom<String> for Background {
|
|||
let value = value.trim_start_matches("file://");
|
||||
let path = PathBuf::from(value);
|
||||
if !path.exists() {
|
||||
return Err(ParseError::DoesNotExist)
|
||||
return Err(ParseError::DoesNotExist);
|
||||
}
|
||||
let extension = value.rsplit_once('.').unwrap_or_default();
|
||||
match extension.1 {
|
||||
|
@ -106,11 +114,15 @@ impl DatabaseError for ParseError {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn as_error_mut(&mut self) -> &mut (dyn Error + Send + Sync + 'static) {
|
||||
fn as_error_mut(
|
||||
&mut self,
|
||||
) -> &mut (dyn Error + Send + Sync + 'static) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn into_error(self: Box<Self>) -> Box<dyn Error + Send + Sync + 'static> {
|
||||
fn into_error(
|
||||
self: Box<Self>,
|
||||
) -> Box<dyn Error + Send + Sync + 'static> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -128,15 +140,15 @@ impl Display for ParseError {
|
|||
Self::NonBackgroundFile => {
|
||||
"The file is not a recognized image or video type"
|
||||
}
|
||||
Self::DoesNotExist => {
|
||||
"This file doesn't exist"
|
||||
}
|
||||
Self::DoesNotExist => "This file doesn't exist",
|
||||
};
|
||||
write!(f, "Error: {message}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum BackgroundKind {
|
||||
#[default]
|
||||
Image,
|
||||
|
|
|
@ -2,7 +2,10 @@ use std::{collections::HashMap, path::PathBuf};
|
|||
|
||||
use color_eyre::eyre::{eyre, Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection};
|
||||
use sqlx::{
|
||||
query, query_as, sqlite::SqliteRow, FromRow, Row,
|
||||
SqliteConnection,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::{
|
||||
|
@ -10,7 +13,9 @@ use crate::{
|
|||
slides::{Background, TextAlignment},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Song {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
|
@ -56,17 +61,24 @@ impl FromRow<'_, SqliteRow> for Song {
|
|||
text_alignment: Some({
|
||||
let horizontal_alignment: String = row.try_get(3)?;
|
||||
let vertical_alignment: String = row.try_get(4)?;
|
||||
match (horizontal_alignment.to_lowercase().as_str(), vertical_alignment.to_lowercase().as_str()) {
|
||||
match (
|
||||
horizontal_alignment.to_lowercase().as_str(),
|
||||
vertical_alignment.to_lowercase().as_str(),
|
||||
) {
|
||||
("left", "top") => TextAlignment::TopLeft,
|
||||
("left", "center") => TextAlignment::MiddleLeft,
|
||||
("left", "bottom") => TextAlignment::BottomLeft,
|
||||
("center", "top") => TextAlignment::TopCenter,
|
||||
("center", "center") => TextAlignment::MiddleCenter,
|
||||
("center", "bottom") => TextAlignment::BottomCenter,
|
||||
("center", "center") => {
|
||||
TextAlignment::MiddleCenter
|
||||
}
|
||||
("center", "bottom") => {
|
||||
TextAlignment::BottomCenter
|
||||
}
|
||||
("right", "top") => TextAlignment::TopRight,
|
||||
("right", "center") => TextAlignment::MiddleRight,
|
||||
("right", "bottom") => TextAlignment::BottomRight,
|
||||
_ => TextAlignment::MiddleCenter
|
||||
_ => TextAlignment::MiddleCenter,
|
||||
}
|
||||
}),
|
||||
font: row.try_get(6)?,
|
||||
|
@ -75,19 +87,20 @@ impl FromRow<'_, SqliteRow> for Song {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result<Song> {
|
||||
let row = query(r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await?;
|
||||
pub async fn get_song_from_db(
|
||||
index: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Song> {
|
||||
let row = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await?;
|
||||
Ok(Song::from_row(&row)?)
|
||||
}
|
||||
|
||||
|
||||
impl Model<Song> {
|
||||
pub fn load_from_db(&mut self) {
|
||||
// static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query(r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.db).await;
|
||||
let result = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.db).await;
|
||||
match result {
|
||||
Ok(s) => {
|
||||
for song in s.into_iter() {
|
||||
|
|
0
src/rust/core/test.pres
Normal file
0
src/rust/core/test.pres
Normal file
|
@ -5,7 +5,9 @@ use sqlx::{query_as, SqliteConnection};
|
|||
use std::path::PathBuf;
|
||||
use tracing::error;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Video {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
|
@ -19,7 +21,7 @@ impl Model<Video> {
|
|||
pub fn load_from_db(&mut self) {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Video, r#"SELECT title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!", id as "id: i32" from videos"#).fetch_all(&mut self.db).await;
|
||||
let result = query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos"#).fetch_all(&mut self.db).await;
|
||||
match result {
|
||||
Ok(v) => {
|
||||
for video in v.into_iter() {
|
||||
|
@ -32,12 +34,13 @@ impl Model<Video> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn get_video_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Video> {
|
||||
Ok(query_as!(Video, r#"SELECT title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await?)
|
||||
pub async fn get_video_from_db(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Video> {
|
||||
Ok(query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await?)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -71,7 +74,10 @@ mod test {
|
|||
let new_video = test_video("A newer video".into());
|
||||
match result {
|
||||
Ok(_) => {
|
||||
assert_eq!(&video, video_model.find(|v| v.id == 0).unwrap());
|
||||
assert_eq!(
|
||||
&video,
|
||||
video_model.find(|v| v.id == 0).unwrap()
|
||||
);
|
||||
assert_ne!(
|
||||
&new_video,
|
||||
video_model.find(|v| v.id == 0).unwrap()
|
||||
|
|
|
@ -10,6 +10,9 @@ mod file_helper {
|
|||
// include!("cxx-qt-lib/qvariant.h");
|
||||
// type QVariant = cxx_qt_lib::QVariant;
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
|
@ -96,7 +99,9 @@ impl file_helper::FileHelper {
|
|||
QUrl::from(string.as_str())
|
||||
}
|
||||
} else {
|
||||
error!("There was an error, is xdg-desktop-portals correctly setup?");
|
||||
error!(
|
||||
"There was an error, is xdg-desktop-portals correctly setup?"
|
||||
);
|
||||
QUrl::default()
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +150,9 @@ impl file_helper::FileHelper {
|
|||
QUrl::from(string.as_str())
|
||||
}
|
||||
} else {
|
||||
error!("Couldn't load file, is xdg-desktop-portals correctly setup?");
|
||||
error!(
|
||||
"Couldn't load file, is xdg-desktop-portals correctly setup?"
|
||||
);
|
||||
QUrl::default()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pub mod image_model {
|
||||
unsafe extern "C++" {
|
||||
include!(< QAbstractListModel >);
|
||||
type QAbstractListModel;
|
||||
include!("cxx-qt-lib/qhash.h");
|
||||
type QHash_i32_QByteArray =
|
||||
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
|
||||
|
@ -31,15 +32,18 @@ pub mod image_model {
|
|||
Title,
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[base = "QAbstractListModel"]
|
||||
#[base = QAbstractListModel]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, count)]
|
||||
type ImageModel = super::ImageModelRust;
|
||||
|
||||
#[inherit]
|
||||
#[qsignal]
|
||||
#[cxx_name = "dataChanged"]
|
||||
fn data_changed(
|
||||
self: Pin<&mut ImageModel>,
|
||||
top_left: &QModelIndex,
|
||||
|
@ -81,8 +85,11 @@ pub mod image_model {
|
|||
|
||||
impl cxx_qt::Threading for ImageModel {}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[inherit]
|
||||
#[cxx_name = "beginInsertRows"]
|
||||
unsafe fn begin_insert_rows(
|
||||
self: Pin<&mut ImageModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -91,9 +98,11 @@ pub mod image_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endInsertRows"]
|
||||
unsafe fn end_insert_rows(self: Pin<&mut ImageModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginRemoveRows"]
|
||||
unsafe fn begin_remove_rows(
|
||||
self: Pin<&mut ImageModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -102,6 +111,7 @@ pub mod image_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginMoveRows"]
|
||||
unsafe fn begin_move_rows(
|
||||
self: Pin<&mut ImageModel>,
|
||||
source_parent: &QModelIndex,
|
||||
|
@ -112,18 +122,23 @@ pub mod image_model {
|
|||
) -> bool;
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endMoveRows"]
|
||||
unsafe fn end_move_rows(self: Pin<&mut ImageModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endRemoveRows"]
|
||||
unsafe fn end_remove_rows(self: Pin<&mut ImageModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginResetModel"]
|
||||
unsafe fn begin_reset_model(self: Pin<&mut ImageModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endResetModel"]
|
||||
unsafe fn end_reset_model(self: Pin<&mut ImageModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "canFetchMore"]
|
||||
fn can_fetch_more(
|
||||
self: &ImageModel,
|
||||
parent: &QModelIndex,
|
||||
|
@ -147,18 +162,20 @@ pub mod image_model {
|
|||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "roleNames"]
|
||||
fn role_names(self: &ImageModel) -> QHash_i32_QByteArray;
|
||||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "rowCount"]
|
||||
fn row_count(self: &ImageModel, _parent: &QModelIndex)
|
||||
-> i32;
|
||||
-> i32;
|
||||
}
|
||||
}
|
||||
|
||||
use cxx_qt::CxxQtType;
|
||||
use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant};
|
||||
use sqlx::{query, query_as, Connection, SqliteConnection};
|
||||
use sqlx::{Connection, SqliteConnection, query, query_as};
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use tracing::{debug, error};
|
||||
|
@ -181,7 +198,7 @@ pub struct ImageModelRust {
|
|||
highest_id: i32,
|
||||
images: Vec<Image>,
|
||||
inner_images: Vec<Image>,
|
||||
db: SqliteConnection
|
||||
db: SqliteConnection,
|
||||
}
|
||||
|
||||
impl Default for ImageModelRust {
|
||||
|
@ -199,9 +216,11 @@ impl Default for ImageModelRust {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,11 +234,13 @@ pub fn get_image(index: i32) -> color_eyre::Result<Image> {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
};
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", filePath as "path!" from images where id = ?"#, index).fetch_one(&mut db).await?;
|
||||
let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", file_path as "path!" from images where id = ?"#, index).fetch_one(&mut db).await?;
|
||||
Ok(result)
|
||||
})
|
||||
}
|
||||
|
@ -236,7 +257,7 @@ impl image_model::ImageModel {
|
|||
pub fn setup(mut self: Pin<&mut Self>) {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", filePath as "path!" from images"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", file_path as "path!" from images"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
match result {
|
||||
Ok(i) => i.into_iter().for_each(|i| self.as_mut().add_image(i)),
|
||||
Err(e) => error!("There was an error in converting songs: {e}"),
|
||||
|
@ -251,7 +272,10 @@ impl image_model::ImageModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
rt.block_on(async {
|
||||
let result = query!("delete from images where id = ?", index).execute(&mut self.as_mut().rust_mut().db).await;
|
||||
let result =
|
||||
query!("delete from images where id = ?", index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
unsafe {
|
||||
|
@ -308,7 +332,7 @@ impl image_model::ImageModel {
|
|||
rt.block_on(async {
|
||||
let image_title = image_title.to_string();
|
||||
let image_path = image_path.to_string();
|
||||
let result = query!(r#"INSERT into images (id, title, filePath) VALUES (?, ?, ?)"#,
|
||||
let result = query!(r#"INSERT into images (id, title, file_path) VALUES (?, ?, ?)"#,
|
||||
image_id,
|
||||
image_title,
|
||||
image_path)
|
||||
|
@ -367,9 +391,13 @@ impl image_model::ImageModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let title = updated_title.to_string();
|
||||
let result = query!("UPDATE images SET title = ? where id = ?", title, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE images SET title = ? where id = ?",
|
||||
title,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for image in self
|
||||
|
@ -380,9 +408,11 @@ impl image_model::ImageModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
image.title = title.clone();
|
||||
debug!(title = image.title,
|
||||
title = title,
|
||||
"updated image title");
|
||||
debug!(
|
||||
title = image.title,
|
||||
title = title,
|
||||
"updated image title"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -394,7 +424,7 @@ impl image_model::ImageModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -414,9 +444,13 @@ impl image_model::ImageModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let updated_path = updated_path.to_string();
|
||||
let result = query!("UPDATE images SET filePath = ? where id = ?", updated_path, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE images SET file_path = ? where id = ?",
|
||||
updated_path,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for image in self
|
||||
|
@ -427,9 +461,11 @@ impl image_model::ImageModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
image.path = updated_path.clone();
|
||||
debug!(title = image.title,
|
||||
path = updated_path,
|
||||
"updated image path");
|
||||
debug!(
|
||||
title = image.title,
|
||||
path = updated_path,
|
||||
"updated image path"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -441,7 +477,7 @@ impl image_model::ImageModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
|
|
@ -8,10 +8,9 @@ pub mod service_item_model;
|
|||
pub mod settings;
|
||||
pub mod slide_model;
|
||||
pub mod slide_object;
|
||||
pub mod slide_types;
|
||||
pub mod songs;
|
||||
pub mod utils;
|
||||
pub mod video_model;
|
||||
pub mod ytdl;
|
||||
pub mod slide_types;
|
||||
// pub mod core;
|
||||
// mod video_thumbnail;
|
||||
|
|
|
@ -4,8 +4,20 @@ pub mod settings;
|
|||
fn main() {
|
||||
let mut app = QGuiApplication::new();
|
||||
let mut engine = QQmlApplicationEngine::new();
|
||||
let mut kde_qml_dir =
|
||||
String::from("/usr/lib/x86_64-linux-gnu/qt6/qml/");
|
||||
|
||||
if let Ok(qml_dir) = env::var("NIXPKGS_QT6_QML_IMPORT_PATH") {
|
||||
kde_qml_dir = qml_dir;
|
||||
} else {
|
||||
println!(
|
||||
"cargo:warning=KDE_QMLDIR is not defined, used default value: {}",
|
||||
kde_qml_dir
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(engine) = engine.as_mut() {
|
||||
engine.add_import_path(&QString::from(kde_qml_dir.as_str()));
|
||||
engine.load(&QUrl::from(
|
||||
"qrc:/qt/qml/com/cochrun/xyz/qml/main.qml",
|
||||
));
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use core::fmt;
|
||||
use cxx_qt::CxxQtType;
|
||||
use cxx_qt_lib::{QString, QStringList};
|
||||
use obws::responses::scenes::{CurrentProgramScene, Scenes};
|
||||
use obws::Client;
|
||||
|
||||
use obws::responses::scenes::{CurrentProgramScene, Scenes};
|
||||
|
||||
use std::{error::Error, pin::Pin};
|
||||
use tracing::{debug, error};
|
||||
|
@ -22,7 +21,10 @@ impl fmt::Debug for Obs {
|
|||
f.debug_struct("Client")
|
||||
.field("scenes", &self.scenes)
|
||||
.field("client", &self.client.is_some())
|
||||
.field("current_program_scene", &self.current_program_scene)
|
||||
.field(
|
||||
"current_program_scene",
|
||||
&self.current_program_scene,
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -37,8 +39,6 @@ impl Clone for Obs {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl Obs {
|
||||
pub async fn new() -> Result<Self, Box<dyn Error>> {
|
||||
let client =
|
||||
|
@ -112,7 +112,7 @@ impl Obs {
|
|||
fn make_client() -> Client {
|
||||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
let future = Client::connect("localhost", 4455, Some(""));
|
||||
|
||||
|
||||
runtime.block_on(future).unwrap()
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,8 @@ mod obs {
|
|||
type QList_QString = cxx_qt_lib::QList<QString>;
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
|
@ -218,7 +220,7 @@ impl obs::ObsModel {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
pub fn test_obs_setting_scene() {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pub mod presentation_model {
|
||||
unsafe extern "C++" {
|
||||
include!(< QAbstractListModel >);
|
||||
type QAbstractListModel;
|
||||
include!("cxx-qt-lib/qhash.h");
|
||||
type QHash_i32_QByteArray =
|
||||
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
|
||||
|
@ -33,15 +34,18 @@ pub mod presentation_model {
|
|||
PageCount,
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[base = "QAbstractListModel"]
|
||||
#[base = QAbstractListModel]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, count)]
|
||||
type PresentationModel = super::PresentationModelRust;
|
||||
|
||||
#[inherit]
|
||||
#[qsignal]
|
||||
#[cxx_name = "dataChanged"]
|
||||
fn data_changed(
|
||||
self: Pin<&mut PresentationModel>,
|
||||
top_left: &QModelIndex,
|
||||
|
@ -99,8 +103,11 @@ pub mod presentation_model {
|
|||
|
||||
impl cxx_qt::Threading for PresentationModel {}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[inherit]
|
||||
#[cxx_name = "beginInsertRows"]
|
||||
unsafe fn begin_insert_rows(
|
||||
self: Pin<&mut PresentationModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -109,9 +116,11 @@ pub mod presentation_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endInsertRows"]
|
||||
unsafe fn end_insert_rows(self: Pin<&mut PresentationModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginRemoveRows"]
|
||||
unsafe fn begin_remove_rows(
|
||||
self: Pin<&mut PresentationModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -120,6 +129,7 @@ pub mod presentation_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginMoveRows"]
|
||||
unsafe fn begin_move_rows(
|
||||
self: Pin<&mut PresentationModel>,
|
||||
source_parent: &QModelIndex,
|
||||
|
@ -130,20 +140,25 @@ pub mod presentation_model {
|
|||
) -> bool;
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endMoveRows"]
|
||||
unsafe fn end_move_rows(self: Pin<&mut PresentationModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endRemoveRows"]
|
||||
unsafe fn end_remove_rows(self: Pin<&mut PresentationModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginResetModel"]
|
||||
unsafe fn begin_reset_model(
|
||||
self: Pin<&mut PresentationModel>,
|
||||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endResetModel"]
|
||||
unsafe fn end_reset_model(self: Pin<&mut PresentationModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "canFetchMore"]
|
||||
fn can_fetch_more(
|
||||
self: &PresentationModel,
|
||||
parent: &QModelIndex,
|
||||
|
@ -167,12 +182,14 @@ pub mod presentation_model {
|
|||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "roleNames"]
|
||||
fn role_names(
|
||||
self: &PresentationModel,
|
||||
) -> QHash_i32_QByteArray;
|
||||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "rowCount"]
|
||||
fn row_count(
|
||||
self: &PresentationModel,
|
||||
_parent: &QModelIndex,
|
||||
|
@ -184,7 +201,7 @@ use crate::presentation_model::presentation_model::QMap_QString_QVariant;
|
|||
use crate::reveal_js;
|
||||
use cxx_qt::CxxQtType;
|
||||
use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant};
|
||||
use sqlx::{query, query_as, Connection, SqliteConnection};
|
||||
use sqlx::{Connection, SqliteConnection, query, query_as};
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use tracing::{debug, error};
|
||||
|
@ -208,7 +225,7 @@ pub struct PresentationModelRust {
|
|||
highest_id: i32,
|
||||
presentations: Vec<Presentation>,
|
||||
inner_presentations: Vec<Presentation>,
|
||||
db: SqliteConnection
|
||||
db: SqliteConnection,
|
||||
}
|
||||
|
||||
impl Default for PresentationModelRust {
|
||||
|
@ -226,14 +243,18 @@ impl Default for PresentationModelRust {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_presentation(index: i32) -> color_eyre::Result<Presentation> {
|
||||
pub fn get_presentation(
|
||||
index: i32,
|
||||
) -> color_eyre::Result<Presentation> {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let mut db = {
|
||||
let mut data = dirs::data_local_dir().unwrap();
|
||||
|
@ -242,11 +263,13 @@ pub fn get_presentation(index: i32) -> color_eyre::Result<Presentation> {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
};
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", html as "html!", pageCount as "page_count!: i32" from presentations where id = ?"#, index).fetch_one(&mut db).await?;
|
||||
let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", html as "html!", pageCount as "page_count!: i32" from presentations where id = ?"#, index).fetch_one(&mut db).await?;
|
||||
Ok(result)
|
||||
})
|
||||
}
|
||||
|
@ -263,7 +286,7 @@ impl presentation_model::PresentationModel {
|
|||
pub fn setup(mut self: Pin<&mut Self>) {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", html as "html!", pageCount as "page_count!: i32" from presentations"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", html as "html!", pageCount as "page_count!: i32" from presentations"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
match result {
|
||||
Ok(p) => p.into_iter().for_each(|p| self.as_mut().add_presentation(p)),
|
||||
Err(e) => error!("There was an error in converting songs: {e}"),
|
||||
|
@ -278,7 +301,12 @@ impl presentation_model::PresentationModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
rt.block_on(async {
|
||||
let result = query!("delete from presentations where id = ?", index).execute(&mut self.as_mut().rust_mut().db).await;
|
||||
let result = query!(
|
||||
"delete from presentations where id = ?",
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
unsafe {
|
||||
|
@ -365,7 +393,7 @@ impl presentation_model::PresentationModel {
|
|||
rt.block_on(async {
|
||||
let presentation_title = presentation_title.to_string();
|
||||
let presentation_path = presentation_path.to_string();
|
||||
let result = query!(r#"INSERT into presentations (id, title, filePath, html, pageCount) VALUES (?, ?, ?, ?, ?)"#,
|
||||
let result = query!(r#"INSERT into presentations (id, title, file_path, html, pageCount) VALUES (?, ?, ?, ?, ?)"#,
|
||||
presentation_id,
|
||||
presentation_title,
|
||||
presentation_path,
|
||||
|
@ -503,9 +531,13 @@ impl presentation_model::PresentationModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let title = updated_title.to_string();
|
||||
let result = query!("UPDATE presentations SET title = ? where id = ?", title, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE presentations SET title = ? where id = ?",
|
||||
title,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for presentation in self
|
||||
|
@ -516,9 +548,11 @@ impl presentation_model::PresentationModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
presentation.title = title.clone();
|
||||
debug!(title = presentation.title,
|
||||
title = title,
|
||||
"updated presentation title");
|
||||
debug!(
|
||||
title = presentation.title,
|
||||
title = title,
|
||||
"updated presentation title"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -530,7 +564,7 @@ impl presentation_model::PresentationModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -549,9 +583,13 @@ impl presentation_model::PresentationModel {
|
|||
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE presentations SET pageCount = ? where id = ?", updated_page_count, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE presentations SET pageCount = ? where id = ?",
|
||||
updated_page_count,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for presentation in self
|
||||
|
@ -561,10 +599,13 @@ impl presentation_model::PresentationModel {
|
|||
.iter_mut()
|
||||
.filter(|x| x.id == index)
|
||||
{
|
||||
presentation.page_count = updated_page_count.clone();
|
||||
debug!(title = presentation.title,
|
||||
page_count = updated_page_count,
|
||||
"updated presentation page_count");
|
||||
presentation.page_count =
|
||||
updated_page_count.clone();
|
||||
debug!(
|
||||
title = presentation.title,
|
||||
page_count = updated_page_count,
|
||||
"updated presentation page_count"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -576,7 +617,7 @@ impl presentation_model::PresentationModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
mod service_item_model {
|
||||
unsafe extern "C++" {
|
||||
include!(< QAbstractListModel >);
|
||||
type QAbstractListModel;
|
||||
include!("cxx-qt-lib/qhash.h");
|
||||
type QHash_i32_QByteArray =
|
||||
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
|
||||
|
@ -43,9 +44,11 @@ mod service_item_model {
|
|||
Id,
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[base = "QAbstractListModel"]
|
||||
#[base = QAbstractListModel]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, count)]
|
||||
#[qproperty(f32, save_progress)]
|
||||
|
@ -54,6 +57,7 @@ mod service_item_model {
|
|||
|
||||
#[inherit]
|
||||
#[qsignal]
|
||||
#[cxx_name = "dataChanged"]
|
||||
fn data_changed(
|
||||
self: Pin<&mut ServiceItemModel>,
|
||||
top_left: &QModelIndex,
|
||||
|
@ -182,17 +186,20 @@ mod service_item_model {
|
|||
|
||||
#[qinvokable]
|
||||
fn save(self: Pin<&mut ServiceItemModel>, file: QUrl)
|
||||
-> bool;
|
||||
-> bool;
|
||||
|
||||
#[qinvokable]
|
||||
fn load(self: Pin<&mut ServiceItemModel>, file: QUrl)
|
||||
-> bool;
|
||||
-> bool;
|
||||
}
|
||||
|
||||
impl cxx_qt::Threading for ServiceItemModel {}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[inherit]
|
||||
#[cxx_name = "beginInsertRows"]
|
||||
unsafe fn begin_insert_rows(
|
||||
self: Pin<&mut ServiceItemModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -201,9 +208,11 @@ mod service_item_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endInsertRows"]
|
||||
unsafe fn end_insert_rows(self: Pin<&mut ServiceItemModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginRemoveRows"]
|
||||
unsafe fn begin_remove_rows(
|
||||
self: Pin<&mut ServiceItemModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -212,6 +221,7 @@ mod service_item_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginMoveRows"]
|
||||
unsafe fn begin_move_rows(
|
||||
self: Pin<&mut ServiceItemModel>,
|
||||
source_parent: &QModelIndex,
|
||||
|
@ -222,18 +232,23 @@ mod service_item_model {
|
|||
) -> bool;
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endMoveRows"]
|
||||
unsafe fn end_move_rows(self: Pin<&mut ServiceItemModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endRemoveRows"]
|
||||
unsafe fn end_remove_rows(self: Pin<&mut ServiceItemModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginResetModel"]
|
||||
unsafe fn begin_reset_model(self: Pin<&mut ServiceItemModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endResetModel"]
|
||||
unsafe fn end_reset_model(self: Pin<&mut ServiceItemModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "canFetchMore"]
|
||||
fn can_fetch_more(
|
||||
self: &ServiceItemModel,
|
||||
parent: &QModelIndex,
|
||||
|
@ -257,12 +272,14 @@ mod service_item_model {
|
|||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "roleNames"]
|
||||
fn role_names(
|
||||
self: &ServiceItemModel,
|
||||
) -> QHash_i32_QByteArray;
|
||||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "rowCount"]
|
||||
fn row_count(
|
||||
self: &ServiceItemModel,
|
||||
_parent: &QModelIndex,
|
||||
|
@ -271,15 +288,21 @@ mod service_item_model {
|
|||
}
|
||||
}
|
||||
|
||||
use self::service_item_model::{
|
||||
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
|
||||
ServiceRoles,
|
||||
};
|
||||
use crate::service_item_model::service_item_model::QList_QString;
|
||||
use crate::songs::song_model::{get_song, Song};
|
||||
use crate::slide_types::SlideType;
|
||||
use crate::songs::song_model::{Song, get_song};
|
||||
use crate::{image_model, presentation_model, video_model};
|
||||
use cxx_qt::{CxxQtType, Threading};
|
||||
use cxx_qt_lib::{
|
||||
QByteArray, QModelIndex, QString, QStringList, QUrl, QVariant,
|
||||
};
|
||||
use dirs;
|
||||
use serde_json::{json, Value};
|
||||
// use lumina_core::service_items::ServiceItem as SI;
|
||||
use serde_json::{Value, json};
|
||||
use std::iter;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin;
|
||||
|
@ -288,12 +311,6 @@ use std::{fs, println};
|
|||
use tar::{Archive, Builder};
|
||||
use tracing::{debug, error};
|
||||
use zstd::{Decoder, Encoder};
|
||||
use self::service_item_model::{
|
||||
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
|
||||
ServiceRoles,
|
||||
};
|
||||
use crate::slide_types::SlideType;
|
||||
use lumina_core::service_items::ServiceItem as SI;
|
||||
|
||||
use super::service_item_model::service_item_model::ServiceItemModel;
|
||||
|
||||
|
@ -377,7 +394,9 @@ impl service_item_model::ServiceItemModel {
|
|||
pub fn remove_items(mut self: Pin<&mut Self>) {
|
||||
let mut indices = vec![];
|
||||
let mut items = self.service_items.clone();
|
||||
for (index, _item) in items.iter_mut().enumerate().filter(|(_y, x)| x.selected) {
|
||||
for (index, _item) in
|
||||
items.iter_mut().enumerate().filter(|(_y, x)| x.selected)
|
||||
{
|
||||
let index = index as i32;
|
||||
indices.push(index);
|
||||
}
|
||||
|
@ -436,7 +455,10 @@ impl service_item_model::ServiceItemModel {
|
|||
self.as_mut().end_insert_rows();
|
||||
}
|
||||
debug!("ADDING: {:?}", &service_item);
|
||||
self.as_mut().item_added(&service_item.database_id.unwrap_or_default(), &QString::from(&service_item.ty.to_string()));
|
||||
self.as_mut().item_added(
|
||||
&service_item.database_id.unwrap_or_default(),
|
||||
&QString::from(&service_item.ty.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn insert_item(
|
||||
|
@ -475,7 +497,11 @@ impl service_item_model::ServiceItemModel {
|
|||
self.as_mut().end_insert_rows();
|
||||
}
|
||||
debug!("ADDING: {:?}", &service_item);
|
||||
self.as_mut().item_inserted(&index, &service_item.database_id.unwrap_or_default(), &QString::from(&service_item.ty.to_string()));
|
||||
self.as_mut().item_inserted(
|
||||
&index,
|
||||
&service_item.database_id.unwrap_or_default(),
|
||||
&QString::from(&service_item.ty.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn get_item(
|
||||
|
@ -876,8 +902,7 @@ impl service_item_model::ServiceItemModel {
|
|||
Some(name) => {
|
||||
println!("audio: {:?}", &name);
|
||||
if name.to_str().unwrap() != "temp" {
|
||||
flat_audio =
|
||||
name.to_str().unwrap()
|
||||
flat_audio = name.to_str().unwrap()
|
||||
} else {
|
||||
flat_audio = "";
|
||||
}
|
||||
|
@ -961,12 +986,18 @@ impl service_item_model::ServiceItemModel {
|
|||
debug!(time = ?now.elapsed(), "file written");
|
||||
std::thread::spawn(move || {
|
||||
debug!(time = ?now.elapsed(), "idk");
|
||||
let dir = fs::read_dir(&temp_dir).expect("idk");
|
||||
let dir = fs::read_dir(&temp_dir)
|
||||
.expect("idk");
|
||||
for (index, file) in dir.enumerate() {
|
||||
if let Ok(file) = file {
|
||||
let file_name = file.file_name();
|
||||
let file_name =
|
||||
file.file_name();
|
||||
debug!(?file, ?file_name);
|
||||
let mut file = std::fs::File::open(file.path()).expect("missing file");
|
||||
let mut file =
|
||||
std::fs::File::open(
|
||||
file.path(),
|
||||
)
|
||||
.expect("missing file");
|
||||
tar.append_file(file_name, &mut file).expect("Error in moving file to tar");
|
||||
thread.queue(move |mut service| {
|
||||
service
|
||||
|
@ -977,10 +1008,11 @@ impl service_item_model::ServiceItemModel {
|
|||
)
|
||||
}).expect("Problem queuing on cxx thread");
|
||||
}
|
||||
|
||||
}
|
||||
if let Ok(encoder) = tar.into_inner() {
|
||||
if let Ok(done) = encoder.finish() {
|
||||
if let Ok(encoder) = tar.into_inner()
|
||||
{
|
||||
if let Ok(done) = encoder.finish()
|
||||
{
|
||||
debug!(time = ?now.elapsed(), ?done, "tar finished");
|
||||
thread.queue(move |mut service| {
|
||||
service.as_mut().set_save_progress(100.0);
|
||||
|
@ -1000,9 +1032,7 @@ impl service_item_model::ServiceItemModel {
|
|||
}
|
||||
} else {
|
||||
fs::remove_dir_all(&temp_dir)
|
||||
.expect(
|
||||
"error in removal",
|
||||
);
|
||||
.expect("error in removal");
|
||||
false
|
||||
}
|
||||
});
|
||||
|
@ -1058,7 +1088,9 @@ impl service_item_model::ServiceItemModel {
|
|||
if !file_path.exists() {
|
||||
match file.unpack_in(&datadir) {
|
||||
Ok(_t) => (),
|
||||
Err(e) => error!("Error unpacking archive: {}", e),
|
||||
Err(e) => {
|
||||
error!("Error unpacking archive: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1280,7 +1312,9 @@ impl service_item_model::ServiceItemModel {
|
|||
..Default::default()
|
||||
};
|
||||
self.as_mut().add_service_item(&service_item);
|
||||
error!("Loaded service item with generic type since it was an unknown type.");
|
||||
error!(
|
||||
"Loaded service item with generic type since it was an unknown type."
|
||||
);
|
||||
// // files implement the Read trait
|
||||
}
|
||||
}
|
||||
|
@ -1341,7 +1375,9 @@ impl service_item_model::ServiceItemModel {
|
|||
let mut vector_roles = QVector_i32::default();
|
||||
vector_roles.append(self.as_ref().get_role(role));
|
||||
if let Some(index) =
|
||||
self.as_ref().service_items.iter().position(|x| x.database_id.unwrap_or_default() == item_id)
|
||||
self.as_ref().service_items.iter().position(|x| {
|
||||
x.database_id.unwrap_or_default() == item_id
|
||||
})
|
||||
{
|
||||
let model_index = self.as_ref().index(
|
||||
index as i32,
|
||||
|
@ -1355,7 +1391,6 @@ impl service_item_model::ServiceItemModel {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn load_last_saved(self: Pin<&mut Self>) -> bool {
|
||||
todo!();
|
||||
// Don't actually need
|
||||
|
@ -1394,9 +1429,9 @@ impl service_item_model::ServiceItemModel {
|
|||
ServiceRoles::Name => {
|
||||
QVariant::from(&service_item.name)
|
||||
}
|
||||
ServiceRoles::Type => {
|
||||
QVariant::from(&QString::from(&service_item.ty.clone().to_string()))
|
||||
}
|
||||
ServiceRoles::Type => QVariant::from(&QString::from(
|
||||
&service_item.ty.clone().to_string(),
|
||||
)),
|
||||
ServiceRoles::Audio => {
|
||||
QVariant::from(&service_item.audio)
|
||||
}
|
||||
|
@ -1433,9 +1468,9 @@ impl service_item_model::ServiceItemModel {
|
|||
ServiceRoles::VideoEndTime => {
|
||||
QVariant::from(&service_item.video_end_time)
|
||||
}
|
||||
ServiceRoles::Id => {
|
||||
QVariant::from(&service_item.database_id.unwrap_or_default())
|
||||
}
|
||||
ServiceRoles::Id => QVariant::from(
|
||||
&service_item.database_id.unwrap_or_default(),
|
||||
),
|
||||
_ => QVariant::default(),
|
||||
};
|
||||
}
|
||||
|
@ -1503,22 +1538,21 @@ impl service_item_model::ServiceItemModel {
|
|||
ServiceRoles::VideoEndTime.repr,
|
||||
QByteArray::from("videoEndTime"),
|
||||
);
|
||||
roles.insert(
|
||||
ServiceRoles::Id.repr,
|
||||
QByteArray::from("id"),
|
||||
);
|
||||
roles.insert(ServiceRoles::Id.repr, QByteArray::from("id"));
|
||||
roles
|
||||
}
|
||||
|
||||
pub fn row_count(&self, _parent: &QModelIndex) -> i32 {
|
||||
|
||||
// println!("row count is {cnt}");
|
||||
self.service_items.len() as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl ServiceItemModelRust {
|
||||
pub fn save(_model: Pin<&mut ServiceItemModel>, _file: QUrl) -> bool {
|
||||
pub fn save(
|
||||
_model: Pin<&mut ServiceItemModel>,
|
||||
_file: QUrl,
|
||||
) -> bool {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ mod settings {
|
|||
type QUrl = cxx_qt_lib::QUrl;
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pub mod slide_model {
|
||||
unsafe extern "C++" {
|
||||
include!(< QAbstractListModel >);
|
||||
type QAbstractListModel;
|
||||
include!("cxx-qt-lib/qhash.h");
|
||||
type QHash_i32_QByteArray =
|
||||
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
|
||||
|
@ -18,18 +19,23 @@ pub mod slide_model {
|
|||
type QVector_i32 = cxx_qt_lib::QVector<i32>;
|
||||
include!("cxx-qt-lib/qlist.h");
|
||||
type QList_QString = cxx_qt_lib::QList<QString>;
|
||||
include!("cxx-qt-gen/slide_object.cxxqt.h");
|
||||
type SlideObject = crate::slide_object::slide_object::SlideObject;
|
||||
include!("cxx-qt-gen/song_model.cxxqt.h");
|
||||
type SongModel = crate::songs::song_model::song_model::SongModel;
|
||||
include!("cxx-qt-gen/video_model.cxxqt.h");
|
||||
include!("liblumina/src/rust/slide_object.cxxqt.h");
|
||||
type SlideObject = crate::slide_object::qobject::SlideObject;
|
||||
include!("liblumina/src/rust/songs/song_model.cxxqt.h");
|
||||
type SongModel =
|
||||
crate::songs::song_model::song_model::SongModel;
|
||||
include!("liblumina/src/rust/video_model.cxxqt.h");
|
||||
type VideoModel = crate::video_model::video_model::VideoModel;
|
||||
include!("cxx-qt-gen/image_model.cxxqt.h");
|
||||
include!("liblumina/src/rust/image_model.cxxqt.h");
|
||||
type ImageModel = crate::image_model::image_model::ImageModel;
|
||||
include!("cxx-qt-gen/presentation_model.cxxqt.h");
|
||||
include!("liblumina/src/rust/presentation_model.cxxqt.h");
|
||||
type PresentationModel = crate::presentation_model::presentation_model::PresentationModel;
|
||||
}
|
||||
|
||||
// extern "C++" {
|
||||
// type SlideObject = crate::slide_object::qobject::SlideObject;
|
||||
// }
|
||||
|
||||
#[qenum(SlideModel)]
|
||||
enum SlideRoles {
|
||||
Ty,
|
||||
|
@ -54,9 +60,11 @@ pub mod slide_model {
|
|||
ObsScene,
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[base = "QAbstractListModel"]
|
||||
#[base = QAbstractListModel]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, count)]
|
||||
#[qproperty(*mut SlideObject, slide_object)]
|
||||
|
@ -68,6 +76,7 @@ pub mod slide_model {
|
|||
|
||||
#[inherit]
|
||||
#[qsignal]
|
||||
#[cxx_name = "dataChanged"]
|
||||
fn data_changed(
|
||||
self: Pin<&mut SlideModel>,
|
||||
top_left: &QModelIndex,
|
||||
|
@ -151,8 +160,11 @@ pub mod slide_model {
|
|||
|
||||
impl cxx_qt::Threading for SlideModel {}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[inherit]
|
||||
#[cxx_name = "beginInsertRows"]
|
||||
unsafe fn begin_insert_rows(
|
||||
self: Pin<&mut SlideModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -161,9 +173,11 @@ pub mod slide_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endInsertRows"]
|
||||
unsafe fn end_insert_rows(self: Pin<&mut SlideModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginRemoveRows"]
|
||||
unsafe fn begin_remove_rows(
|
||||
self: Pin<&mut SlideModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -172,15 +186,19 @@ pub mod slide_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endRemoveRows"]
|
||||
unsafe fn end_remove_rows(self: Pin<&mut SlideModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginResetModel"]
|
||||
unsafe fn begin_reset_model(self: Pin<&mut SlideModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endResetModel"]
|
||||
unsafe fn end_reset_model(self: Pin<&mut SlideModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginMoveRows"]
|
||||
unsafe fn begin_move_rows(
|
||||
self: Pin<&mut SlideModel>,
|
||||
source_parent: &QModelIndex,
|
||||
|
@ -191,9 +209,11 @@ pub mod slide_model {
|
|||
) -> bool;
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endMoveRows"]
|
||||
unsafe fn end_move_rows(self: Pin<&mut SlideModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "canFetchMore"]
|
||||
fn can_fetch_more(
|
||||
self: &SlideModel,
|
||||
parent: &QModelIndex,
|
||||
|
@ -217,38 +237,43 @@ pub mod slide_model {
|
|||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "roleNames"]
|
||||
fn role_names(self: &SlideModel) -> QHash_i32_QByteArray;
|
||||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "rowCount"]
|
||||
fn row_count(self: &SlideModel, _parent: &QModelIndex)
|
||||
-> i32;
|
||||
-> i32;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
use crate::image_model::image_model::ImageModel;
|
||||
use crate::image_model::{self, Image, ImageModelRust};
|
||||
use crate::obs::Obs;
|
||||
use crate::presentation_model::presentation_model::PresentationModel;
|
||||
use crate::presentation_model::{self, Presentation, PresentationModelRust};
|
||||
use crate::presentation_model::{
|
||||
self, Presentation, PresentationModelRust,
|
||||
};
|
||||
use crate::slide_model::slide_model::QList_QString;
|
||||
use crate::songs::song_model::song_model::{self, SongModel};
|
||||
use crate::songs::song_model::{get_song, Song, SongModelRust};
|
||||
use crate::songs::song_model::{Song, SongModelRust, get_song};
|
||||
use crate::video_model::video_model::VideoModel;
|
||||
use crate::video_model::{self, Video, VideoModelRust};
|
||||
use crate::{ffmpeg, slide_types::SlideType};
|
||||
use crate::obs::Obs;
|
||||
use crate::slide_model::slide_model::QList_QString;
|
||||
use color_eyre::eyre::Result;
|
||||
use color_eyre::Section;
|
||||
use color_eyre::eyre::Result;
|
||||
use cxx_qt::{CxxQtType, Threading};
|
||||
use cxx_qt_lib::{
|
||||
CaseSensitivity, QByteArray, QList, QModelIndex, QString, QStringList, QVariant
|
||||
CaseSensitivity, QByteArray, QList, QModelIndex, QString,
|
||||
QStringList, QVariant,
|
||||
};
|
||||
use slide_model::SlideObject;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display};
|
||||
use std::fmt::Display;
|
||||
use std::{path::PathBuf, pin::Pin};
|
||||
use tracing::{debug, error};
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
use self::slide_model::{
|
||||
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
|
||||
|
@ -319,7 +344,9 @@ impl Display for ParseSlideError {
|
|||
f: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result {
|
||||
let message = match self {
|
||||
Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'",
|
||||
Self::UnknownType => {
|
||||
"The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'"
|
||||
}
|
||||
};
|
||||
write!(f, "Error: {message}")
|
||||
}
|
||||
|
@ -336,45 +363,40 @@ impl Slide {
|
|||
fn slides_from_song(song: Song) -> Result<Vec<Self>> {
|
||||
let list = song.get_lyric_list();
|
||||
let total = list.len();
|
||||
let mut vector: Vec<Slide> = vec![];
|
||||
list.iter().map(|t| t.to_string()).enumerate()
|
||||
.for_each(|(i, s)| {
|
||||
if song.background_type == "image" {
|
||||
vector.push(
|
||||
Self {
|
||||
text: s,
|
||||
ty: SlideType::Song,
|
||||
audio: song.audio.clone(),
|
||||
image_background: song.background.clone(),
|
||||
video_background: "".to_owned(),
|
||||
htext_alignment: song.horizontal_text_alignment.clone(),
|
||||
vtext_alignment: song.vertical_text_alignment.clone(),
|
||||
font: song.font.clone(),
|
||||
font_size: song.font_size,
|
||||
slide_count: total as i32,
|
||||
slide_index: i as i32,
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
} else {
|
||||
vector.push(
|
||||
Self {
|
||||
text: s,
|
||||
ty: SlideType::Song,
|
||||
audio: song.audio.clone(),
|
||||
image_background: "".to_owned(),
|
||||
video_background: song.background.clone(),
|
||||
htext_alignment: song.horizontal_text_alignment.clone(),
|
||||
vtext_alignment: song.vertical_text_alignment.clone(),
|
||||
font: song.font.clone(),
|
||||
font_size: song.font_size,
|
||||
slide_count: total as i32,
|
||||
slide_index: i as i32,
|
||||
..Default::default()
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
let vector = list
|
||||
.iter()
|
||||
.map(|t| {
|
||||
let s = t.to_string();
|
||||
warn!(s);
|
||||
s
|
||||
})
|
||||
.enumerate()
|
||||
.map(|(i, s)| Self {
|
||||
text: s,
|
||||
ty: SlideType::Song,
|
||||
audio: song.audio.clone(),
|
||||
image_background: if song.background_type == "image" {
|
||||
song.background.clone()
|
||||
} else {
|
||||
"".into()
|
||||
},
|
||||
video_background: if song.background_type == "video" {
|
||||
song.background.clone()
|
||||
} else {
|
||||
"".to_owned()
|
||||
},
|
||||
htext_alignment: song
|
||||
.horizontal_text_alignment
|
||||
.clone(),
|
||||
vtext_alignment: song.vertical_text_alignment.clone(),
|
||||
font: song.font.clone(),
|
||||
font_size: song.font_size,
|
||||
slide_count: total as i32,
|
||||
slide_index: i as i32,
|
||||
..Default::default()
|
||||
})
|
||||
.collect();
|
||||
warn!(?vector);
|
||||
Ok(vector)
|
||||
}
|
||||
|
||||
|
@ -395,7 +417,9 @@ impl Slide {
|
|||
})
|
||||
}
|
||||
|
||||
fn slides_from_presentation(presentation: Presentation) -> Result<Vec<Self>> {
|
||||
fn slides_from_presentation(
|
||||
presentation: Presentation,
|
||||
) -> Result<Vec<Self>> {
|
||||
let total = presentation.page_count;
|
||||
let mut slides: Vec<Slide> = vec![];
|
||||
for i in 0..total {
|
||||
|
@ -406,7 +430,7 @@ impl Slide {
|
|||
image_background: presentation.path.clone(),
|
||||
..Default::default()
|
||||
})
|
||||
};
|
||||
}
|
||||
Ok(slides)
|
||||
}
|
||||
}
|
||||
|
@ -456,9 +480,12 @@ impl slide_model::SlideModel {
|
|||
index: i32,
|
||||
) -> bool {
|
||||
let mut vector_roles = QVector_i32::default();
|
||||
vector_roles.append(self.get_role(SlideRoles::VideoThumbnail));
|
||||
vector_roles.append(self.get_role(SlideRoles::VideoBackground));
|
||||
vector_roles.append(self.get_role(SlideRoles::ImageBackground));
|
||||
vector_roles
|
||||
.append(self.get_role(SlideRoles::VideoThumbnail));
|
||||
vector_roles
|
||||
.append(self.get_role(SlideRoles::VideoBackground));
|
||||
vector_roles
|
||||
.append(self.get_role(SlideRoles::ImageBackground));
|
||||
let rc = self.as_ref().count() - 1;
|
||||
let tl = self.as_ref().index(0, 0, &QModelIndex::default());
|
||||
let br = self.as_ref().index(rc, 0, &QModelIndex::default());
|
||||
|
@ -470,7 +497,11 @@ impl slide_model::SlideModel {
|
|||
let path =
|
||||
PathBuf::from(slide.video_background.to_string());
|
||||
let screenshot = ffmpeg::bg_path_from_video(&path);
|
||||
let mut screenshot_string = screenshot.clone().into_os_string().into_string().unwrap_or_default();
|
||||
let mut screenshot_string = screenshot
|
||||
.clone()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap_or_default();
|
||||
screenshot_string.insert_str(0, "file://");
|
||||
slide.video_thumbnail = screenshot_string;
|
||||
std::thread::spawn(move || {
|
||||
|
@ -483,7 +514,7 @@ impl slide_model::SlideModel {
|
|||
"Error making video background"
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
match thread.queue(move |mut slide_model| {
|
||||
slide_model.as_mut().data_changed(
|
||||
&tl,
|
||||
|
@ -616,37 +647,56 @@ impl slide_model::SlideModel {
|
|||
SlideType::Song => {
|
||||
let song = get_song(item_model_id)?;
|
||||
let slides = Slide::slides_from_song(song)?;
|
||||
slides.iter().for_each(|slide| self.as_mut().insert_slide(slide, index));
|
||||
slides.iter().enumerate().for_each(|(i, slide)| {
|
||||
self.as_mut()
|
||||
.insert_slide(slide, index + i as i32)
|
||||
});
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
SlideType::Video => {
|
||||
let video = video_model::get_video(item_model_id)?;
|
||||
self.insert_slide(&Slide::slide_from_video(video)?, index);
|
||||
self.insert_slide(
|
||||
&Slide::slide_from_video(video)?,
|
||||
index,
|
||||
);
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
SlideType::Image => {
|
||||
let result = image_model::get_image(item_model_id);
|
||||
match result {
|
||||
Ok(image) => self.insert_slide(&Slide::slide_from_image(image)?, index),
|
||||
Ok(image) => self.insert_slide(
|
||||
&Slide::slide_from_image(image)?,
|
||||
index,
|
||||
),
|
||||
Err(e) => {
|
||||
e.with_note(|| {
|
||||
format!("This might fail if we are loading the items from a file")
|
||||
});
|
||||
let mut slide = Slide::default();
|
||||
slide.image_background = "qrc:/assets/black.jpg".to_owned();
|
||||
slide.image_background =
|
||||
"qrc:/assets/black.jpg".to_owned();
|
||||
self.insert_slide(&slide, index);
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
SlideType::Content => {
|
||||
todo!();
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
SlideType::Presentation(_) => {
|
||||
let presentation = presentation_model::get_presentation(item_model_id)?;
|
||||
let slides = Slide::slides_from_presentation(presentation)?;
|
||||
slides.iter().for_each(|slide| self.as_mut().insert_slide(slide, slide.slide_index + index));
|
||||
let presentation =
|
||||
presentation_model::get_presentation(
|
||||
item_model_id,
|
||||
)?;
|
||||
let slides =
|
||||
Slide::slides_from_presentation(presentation)?;
|
||||
slides.iter().for_each(|slide| {
|
||||
self.as_mut().insert_slide(
|
||||
slide,
|
||||
slide.slide_index + index,
|
||||
)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -656,7 +706,7 @@ impl slide_model::SlideModel {
|
|||
self: Pin<&mut Self>,
|
||||
item_model_id: i32,
|
||||
kind: &QString,
|
||||
) -> Result<()>{
|
||||
) -> Result<()> {
|
||||
let index = self.count;
|
||||
self.insert_item_from_service(index, item_model_id, kind)
|
||||
}
|
||||
|
@ -692,7 +742,8 @@ impl slide_model::SlideModel {
|
|||
|
||||
if let Some((i, slide)) = slides_iter
|
||||
.clone()
|
||||
.enumerate().find(|slide| slide.1.service_item_id == source_index)
|
||||
.enumerate()
|
||||
.find(|slide| slide.1.service_item_id == source_index)
|
||||
{
|
||||
debug!(index = i, ?slide);
|
||||
first_slide = i as i32;
|
||||
|
@ -705,11 +756,8 @@ impl slide_model::SlideModel {
|
|||
|
||||
// lets get the dest_slide and count
|
||||
if move_down {
|
||||
if let Some((i, slide)) = slides_iter
|
||||
.clone()
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find(|slide| {
|
||||
if let Some((i, slide)) =
|
||||
slides_iter.clone().enumerate().rev().find(|slide| {
|
||||
slide.1.service_item_id == destination_index
|
||||
})
|
||||
{
|
||||
|
@ -724,9 +772,8 @@ impl slide_model::SlideModel {
|
|||
dest_slide, dest_count
|
||||
);
|
||||
}
|
||||
} else if let Some((i, slide)) = slides_iter
|
||||
.enumerate()
|
||||
.find(|slide| {
|
||||
} else if let Some((i, slide)) =
|
||||
slides_iter.enumerate().find(|slide| {
|
||||
slide.1.service_item_id == destination_index
|
||||
})
|
||||
{
|
||||
|
@ -773,7 +820,9 @@ impl slide_model::SlideModel {
|
|||
// Change the service_item_id of the moved slide
|
||||
if count > 1 {
|
||||
if move_down {
|
||||
debug!("While moving down, change service items id of moved slide");
|
||||
debug!(
|
||||
"While moving down, change service items id of moved slide"
|
||||
);
|
||||
for (i, _slide) in slides_iter
|
||||
.clone()
|
||||
.enumerate()
|
||||
|
@ -791,13 +840,16 @@ impl slide_model::SlideModel {
|
|||
debug!(
|
||||
?slide,
|
||||
"rust: these ones right here officer. from {:?} to {:?}",
|
||||
slide.service_item_id, destination_index
|
||||
slide.service_item_id,
|
||||
destination_index
|
||||
);
|
||||
slide.service_item_id = destination_index;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("While moving up, change service items id of moved slide");
|
||||
debug!(
|
||||
"While moving up, change service items id of moved slide"
|
||||
);
|
||||
for (i, _slide) in slides_iter
|
||||
.clone()
|
||||
.enumerate()
|
||||
|
@ -810,7 +862,8 @@ impl slide_model::SlideModel {
|
|||
debug!(
|
||||
?slide,
|
||||
"rust: these ones right here officer. from {:?} to {:?}",
|
||||
slide.service_item_id, destination_index
|
||||
slide.service_item_id,
|
||||
destination_index
|
||||
);
|
||||
slide.service_item_id = destination_index;
|
||||
}
|
||||
|
@ -882,7 +935,9 @@ impl slide_model::SlideModel {
|
|||
// self.as_mut().end_reset_model();
|
||||
// }
|
||||
|
||||
debug!("rust-move: {first_slide} to {dest_slide} with {count} slides");
|
||||
debug!(
|
||||
"rust-move: {first_slide} to {dest_slide} with {count} slides"
|
||||
);
|
||||
}
|
||||
|
||||
fn move_items(
|
||||
|
@ -1001,7 +1056,8 @@ impl slide_model::SlideModel {
|
|||
debug!(service_item = index, "Getting slide from this item");
|
||||
let mut id = 0;
|
||||
if let Some((i, slide)) = slides_iter
|
||||
.enumerate().find(|(_i, slide)| slide.service_item_id == index)
|
||||
.enumerate()
|
||||
.find(|(_i, slide)| slide.service_item_id == index)
|
||||
{
|
||||
debug!(slide_id = i, ?slide);
|
||||
id = i as i32;
|
||||
|
@ -1105,7 +1161,6 @@ impl slide_model::SlideModel {
|
|||
(0, QModelIndex::default(), vector_roles)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// QAbstractListModel implementation
|
||||
|
@ -1114,22 +1169,30 @@ impl slide_model::SlideModel {
|
|||
let role = SlideRoles { repr: role };
|
||||
if let Some(slide) = self.slides.get(index.row() as usize) {
|
||||
return match role {
|
||||
SlideRoles::Ty => QVariant::from(&QString::from(&slide.ty.to_string())),
|
||||
SlideRoles::Text => QVariant::from(&QString::from(&slide.text)),
|
||||
SlideRoles::Audio => QVariant::from(&QString::from(&slide.audio)),
|
||||
SlideRoles::ImageBackground => {
|
||||
QVariant::from(&QString::from(&slide.image_background))
|
||||
SlideRoles::Ty => QVariant::from(&QString::from(
|
||||
&slide.ty.to_string(),
|
||||
)),
|
||||
SlideRoles::Text => {
|
||||
QVariant::from(&QString::from(&slide.text))
|
||||
}
|
||||
SlideRoles::VideoBackground => {
|
||||
QVariant::from(&QString::from(&slide.video_background))
|
||||
SlideRoles::Audio => {
|
||||
QVariant::from(&QString::from(&slide.audio))
|
||||
}
|
||||
SlideRoles::HTextAlignment => {
|
||||
QVariant::from(&QString::from(&slide.htext_alignment))
|
||||
SlideRoles::ImageBackground => QVariant::from(
|
||||
&QString::from(&slide.image_background),
|
||||
),
|
||||
SlideRoles::VideoBackground => QVariant::from(
|
||||
&QString::from(&slide.video_background),
|
||||
),
|
||||
SlideRoles::HTextAlignment => QVariant::from(
|
||||
&QString::from(&slide.htext_alignment),
|
||||
),
|
||||
SlideRoles::VTextAlignment => QVariant::from(
|
||||
&QString::from(&slide.vtext_alignment),
|
||||
),
|
||||
SlideRoles::Font => {
|
||||
QVariant::from(&QString::from(&slide.font))
|
||||
}
|
||||
SlideRoles::VTextAlignment => {
|
||||
QVariant::from(&QString::from(&slide.vtext_alignment))
|
||||
}
|
||||
SlideRoles::Font => QVariant::from(&QString::from(&slide.font)),
|
||||
SlideRoles::FontSize => {
|
||||
QVariant::from(&slide.font_size)
|
||||
}
|
||||
|
@ -1147,9 +1210,9 @@ impl slide_model::SlideModel {
|
|||
QVariant::from(&slide.selected)
|
||||
}
|
||||
SlideRoles::Looping => QVariant::from(&slide.looping),
|
||||
SlideRoles::VideoThumbnail => {
|
||||
QVariant::from(&QString::from(&slide.video_thumbnail))
|
||||
}
|
||||
SlideRoles::VideoThumbnail => QVariant::from(
|
||||
&QString::from(&slide.video_thumbnail),
|
||||
),
|
||||
SlideRoles::VideoStartTime => {
|
||||
QVariant::from(&slide.video_start_time)
|
||||
}
|
||||
|
@ -1256,7 +1319,8 @@ impl slide_model::SlideModel {
|
|||
fn extract_string(item: &QMap_QString_QVariant, key: &str) -> String {
|
||||
item.get(&QString::from(key))
|
||||
.unwrap_or(QVariant::from(&QString::default()))
|
||||
.value_or_default::<QString>().to_string()
|
||||
.value_or_default::<QString>()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn extract_value(item: &QMap_QString_QVariant, key: &str) -> i32 {
|
||||
|
@ -1277,12 +1341,11 @@ fn extract_bool(item: &QMap_QString_QVariant, key: &str) -> bool {
|
|||
.value_or_default::<bool>()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod test {
|
||||
|
||||
#[test]
|
||||
pub fn test_obs_setting_scene() {
|
||||
assert_eq!(true, true)
|
||||
}
|
||||
}
|
||||
// #[test]
|
||||
// pub fn test_obs_setting_scene() {
|
||||
// assert_eq!(true, true)
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#[cxx_qt::bridge]
|
||||
pub mod slide_object {
|
||||
pub mod qobject {
|
||||
unsafe extern "C++" {
|
||||
include!("cxx-qt-lib/qstring.h");
|
||||
type QString = cxx_qt_lib::QString;
|
||||
|
@ -10,7 +10,31 @@ pub mod slide_object {
|
|||
// type SlideModel = crate::slide_model::slide_model::SlideModel;
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, slide_index)]
|
||||
#[qproperty(i32, slide_size)]
|
||||
#[qproperty(i32, inner_slide_index)]
|
||||
#[qproperty(bool, is_playing)]
|
||||
#[qproperty(bool, looping)]
|
||||
#[qproperty(QString, text)]
|
||||
#[qproperty(QString, ty)]
|
||||
#[qproperty(QString, audio)]
|
||||
#[qproperty(QString, image_background)]
|
||||
#[qproperty(QString, video_background)]
|
||||
#[qproperty(bool, html)]
|
||||
#[qproperty(QString, vtext_alignment)]
|
||||
#[qproperty(QString, htext_alignment)]
|
||||
#[qproperty(QString, font)]
|
||||
#[qproperty(i32, font_size)]
|
||||
#[qproperty(f32, video_start_time)]
|
||||
#[qproperty(f32, video_end_time)]
|
||||
// #[qproperty(*mut SlideModel, slide_model)]
|
||||
type SlideObject = super::SlideObjectRust;
|
||||
|
||||
#[qsignal]
|
||||
fn playing_changed(
|
||||
self: Pin<&mut SlideObject>,
|
||||
|
@ -35,28 +59,6 @@ pub mod slide_object {
|
|||
#[qsignal]
|
||||
fn reveal_prev(self: Pin<&mut SlideObject>);
|
||||
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, slide_index)]
|
||||
#[qproperty(i32, slide_size)]
|
||||
#[qproperty(i32, inner_slide_index)]
|
||||
#[qproperty(bool, is_playing)]
|
||||
#[qproperty(bool, looping)]
|
||||
#[qproperty(QString, text)]
|
||||
#[qproperty(QString, ty)]
|
||||
#[qproperty(QString, audio)]
|
||||
#[qproperty(QString, image_background)]
|
||||
#[qproperty(QString, video_background)]
|
||||
#[qproperty(bool, html)]
|
||||
#[qproperty(QString, vtext_alignment)]
|
||||
#[qproperty(QString, htext_alignment)]
|
||||
#[qproperty(QString, font)]
|
||||
#[qproperty(i32, font_size)]
|
||||
#[qproperty(f32, video_start_time)]
|
||||
#[qproperty(f32, video_end_time)]
|
||||
// #[qproperty(*mut SlideModel, slide_model)]
|
||||
type SlideObject = super::SlideObjectRust;
|
||||
|
||||
#[qinvokable]
|
||||
fn change_slide(
|
||||
self: Pin<&mut SlideObject>,
|
||||
|
@ -89,10 +91,11 @@ use cxx_qt_lib::{CaseSensitivity, QString, QVariant};
|
|||
use tracing::{debug, error};
|
||||
|
||||
use crate::{
|
||||
slide_model::{slide_model, Slide}, slide_types::SlideType
|
||||
slide_model::{Slide, slide_model},
|
||||
slide_types::SlideType,
|
||||
};
|
||||
|
||||
use self::slide_object::QMap_QString_QVariant;
|
||||
use self::qobject::QMap_QString_QVariant;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SlideObjectRust {
|
||||
|
@ -141,7 +144,7 @@ impl Default for SlideObjectRust {
|
|||
}
|
||||
}
|
||||
|
||||
impl slide_object::SlideObject {
|
||||
impl qobject::SlideObject {
|
||||
pub fn change_slide(
|
||||
mut self: Pin<&mut Self>,
|
||||
item: QMap_QString_QVariant,
|
||||
|
@ -484,10 +487,18 @@ impl slide_object::SlideObject {
|
|||
self.as_mut().set_text(QString::from(&slide.text));
|
||||
self.as_mut().set_ty(QString::from(&slide.ty.to_string()));
|
||||
self.as_mut().set_audio(QString::from(&slide.audio));
|
||||
self.as_mut().set_image_background(QString::from(&slide.image_background));
|
||||
self.as_mut().set_video_background(QString::from(&slide.video_background));
|
||||
self.as_mut().set_vtext_alignment(QString::from(&slide.vtext_alignment));
|
||||
self.as_mut().set_htext_alignment(QString::from(&slide.htext_alignment));
|
||||
self.as_mut().set_image_background(QString::from(
|
||||
&slide.image_background,
|
||||
));
|
||||
self.as_mut().set_video_background(QString::from(
|
||||
&slide.video_background,
|
||||
));
|
||||
self.as_mut().set_vtext_alignment(QString::from(
|
||||
&slide.vtext_alignment,
|
||||
));
|
||||
self.as_mut().set_htext_alignment(QString::from(
|
||||
&slide.htext_alignment,
|
||||
));
|
||||
self.as_mut().set_font(QString::from(&slide.font));
|
||||
self.as_mut().set_font_size(slide.font_size);
|
||||
self.as_mut().set_video_start_time(slide.video_start_time);
|
||||
|
|
|
@ -15,11 +15,13 @@ pub mod song_editor {
|
|||
include!("cxx-qt-lib/qlist.h");
|
||||
type QList_QString = cxx_qt_lib::QList<QString>;
|
||||
|
||||
include!("cxx-qt-gen/song_model.cxxqt.h");
|
||||
include!("liblumina/src/rust/songs/song_model.cxxqt.h");
|
||||
type SongModel =
|
||||
crate::songs::song_model::song_model::SongModel;
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pub mod song_model {
|
||||
unsafe extern "C++" {
|
||||
include!(< QAbstractListModel >);
|
||||
type QAbstractListModel;
|
||||
include!("cxx-qt-lib/qhash.h");
|
||||
type QHash_i32_QByteArray =
|
||||
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
|
||||
|
@ -39,15 +40,18 @@ pub mod song_model {
|
|||
FontSize,
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[base = "QAbstractListModel"]
|
||||
#[base = QAbstractListModel]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, count)]
|
||||
type SongModel = super::SongModelRust;
|
||||
|
||||
#[inherit]
|
||||
#[qsignal]
|
||||
#[cxx_name = "dataChanged"]
|
||||
fn data_changed(
|
||||
self: Pin<&mut SongModel>,
|
||||
top_left: &QModelIndex,
|
||||
|
@ -75,7 +79,7 @@ pub mod song_model {
|
|||
fn setup(self: Pin<&mut SongModel>);
|
||||
#[qinvokable]
|
||||
fn remove_item(self: Pin<&mut SongModel>, index: i32)
|
||||
-> bool;
|
||||
-> bool;
|
||||
#[qinvokable]
|
||||
fn new_song(self: Pin<&mut SongModel>) -> bool;
|
||||
#[qinvokable]
|
||||
|
@ -166,8 +170,11 @@ pub mod song_model {
|
|||
|
||||
impl cxx_qt::Threading for SongModel {}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[inherit]
|
||||
#[cxx_name = "beginInsertRows"]
|
||||
unsafe fn begin_insert_rows(
|
||||
self: Pin<&mut SongModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -176,9 +183,11 @@ pub mod song_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endInsertRows"]
|
||||
unsafe fn end_insert_rows(self: Pin<&mut SongModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginRemoveRows"]
|
||||
unsafe fn begin_remove_rows(
|
||||
self: Pin<&mut SongModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -187,6 +196,7 @@ pub mod song_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginMoveRows"]
|
||||
unsafe fn begin_move_rows(
|
||||
self: Pin<&mut SongModel>,
|
||||
source_parent: &QModelIndex,
|
||||
|
@ -197,18 +207,23 @@ pub mod song_model {
|
|||
) -> bool;
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endMoveRows"]
|
||||
unsafe fn end_move_rows(self: Pin<&mut SongModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endRemoveRows"]
|
||||
unsafe fn end_remove_rows(self: Pin<&mut SongModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginResetModel"]
|
||||
unsafe fn begin_reset_model(self: Pin<&mut SongModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endResetModel"]
|
||||
unsafe fn end_reset_model(self: Pin<&mut SongModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "canFetchMore"]
|
||||
fn can_fetch_more(
|
||||
self: &SongModel,
|
||||
parent: &QModelIndex,
|
||||
|
@ -232,24 +247,26 @@ pub mod song_model {
|
|||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "roleNames"]
|
||||
fn role_names(self: &SongModel) -> QHash_i32_QByteArray;
|
||||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "rowCount"]
|
||||
fn row_count(self: &SongModel, _parent: &QModelIndex) -> i32;
|
||||
}
|
||||
}
|
||||
|
||||
use crate::songs::song_editor::song_editor::QList_QString;
|
||||
use color_eyre::Result;
|
||||
use cxx_qt::{CxxQtType, Threading};
|
||||
use cxx_qt_lib::{
|
||||
QByteArray, QModelIndex, QString, QStringList, QVariant,
|
||||
};
|
||||
use sqlx::{query, query_as, Connection, SqliteConnection};
|
||||
use sqlx::{Connection, SqliteConnection, query, query_as};
|
||||
use std::collections::HashMap;
|
||||
use std::pin::Pin;
|
||||
use tracing::{debug, error};
|
||||
use color_eyre::Result;
|
||||
|
||||
use self::song_model::{
|
||||
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
|
||||
|
@ -288,90 +305,86 @@ impl Default for Song {
|
|||
impl Song {
|
||||
pub fn get_lyric_list(&self) -> QList_QString {
|
||||
let mut lyric_list = QList_QString::default();
|
||||
if self.lyrics.is_empty() {
|
||||
return QList_QString::default();
|
||||
}
|
||||
let raw_lyrics = self.lyrics.clone();
|
||||
println!("raw-lyrics: {:?}", raw_lyrics);
|
||||
let vorder: Vec<&str> =
|
||||
self.verse_order.split(' ').collect();
|
||||
let keywords = vec![
|
||||
"Verse 1", "Verse 2", "Verse 3", "Verse 4",
|
||||
"Verse 5", "Verse 6", "Verse 7", "Verse 8",
|
||||
"Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4",
|
||||
"Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4",
|
||||
"Intro 1", "Intro 2", "Ending 1", "Ending 2",
|
||||
"Other 1", "Other 2", "Other 3", "Other 4",
|
||||
];
|
||||
let _first_item = true;
|
||||
if self.lyrics.is_empty() {
|
||||
return QList_QString::default();
|
||||
}
|
||||
let raw_lyrics = self.lyrics.clone();
|
||||
println!("raw-lyrics: {:?}", raw_lyrics);
|
||||
let vorder: Vec<&str> = self.verse_order.split(' ').collect();
|
||||
let keywords = vec![
|
||||
"Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5",
|
||||
"Verse 6", "Verse 7", "Verse 8", "Chorus 1", "Chorus 2",
|
||||
"Chorus 3", "Chorus 4", "Bridge 1", "Bridge 2",
|
||||
"Bridge 3", "Bridge 4", "Intro 1", "Intro 2", "Ending 1",
|
||||
"Ending 2", "Other 1", "Other 2", "Other 3", "Other 4",
|
||||
];
|
||||
let _first_item = true;
|
||||
|
||||
let mut lyric_map = HashMap::new();
|
||||
let mut verse_title = String::from("");
|
||||
let mut lyric = String::from("");
|
||||
for (i, line) in raw_lyrics.split('\n').enumerate() {
|
||||
if keywords.contains(&line) {
|
||||
if i != 0 {
|
||||
// println!("{verse_title}");
|
||||
// println!("{lyric}");
|
||||
lyric_map.insert(verse_title, lyric);
|
||||
lyric = String::from("");
|
||||
verse_title = line.to_string();
|
||||
// println!("{line}");
|
||||
// println!("\n");
|
||||
} else {
|
||||
verse_title = line.to_string();
|
||||
// println!("{line}");
|
||||
// println!("\n");
|
||||
}
|
||||
let mut lyric_map = HashMap::new();
|
||||
let mut verse_title = String::from("");
|
||||
let mut lyric = String::from("");
|
||||
for (i, line) in raw_lyrics.split('\n').enumerate() {
|
||||
if keywords.contains(&line) {
|
||||
if i != 0 {
|
||||
// println!("{verse_title}");
|
||||
// println!("{lyric}");
|
||||
lyric_map.insert(verse_title, lyric);
|
||||
lyric = String::from("");
|
||||
verse_title = line.to_string();
|
||||
// println!("{line}");
|
||||
// println!("\n");
|
||||
} else {
|
||||
lyric.push_str(line);
|
||||
lyric.push('\n');
|
||||
verse_title = line.to_string();
|
||||
// println!("{line}");
|
||||
// println!("\n");
|
||||
}
|
||||
} else {
|
||||
lyric.push_str(line);
|
||||
lyric.push('\n');
|
||||
}
|
||||
}
|
||||
lyric_map.insert(verse_title, lyric);
|
||||
// println!("da-map: {:?}", lyric_map);
|
||||
|
||||
for verse in vorder {
|
||||
let mut verse_name = "";
|
||||
// debug!(verse = verse);
|
||||
for word in keywords.clone() {
|
||||
let end_verse = verse.get(1..2).unwrap_or_default();
|
||||
let beg_verse = verse.get(0..1).unwrap_or_default();
|
||||
// println!(
|
||||
// "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}",
|
||||
// verse, beg_verse, end_verse, word
|
||||
// );
|
||||
if word.starts_with(beg_verse)
|
||||
&& word.ends_with(end_verse)
|
||||
{
|
||||
verse_name = word;
|
||||
// println!("TITLE: {verse_name}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
lyric_map.insert(verse_title, lyric);
|
||||
// println!("da-map: {:?}", lyric_map);
|
||||
|
||||
for verse in vorder {
|
||||
let mut verse_name = "";
|
||||
// debug!(verse = verse);
|
||||
for word in keywords.clone() {
|
||||
let end_verse =
|
||||
verse.get(1..2).unwrap_or_default();
|
||||
let beg_verse =
|
||||
verse.get(0..1).unwrap_or_default();
|
||||
// println!(
|
||||
// "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}",
|
||||
// verse, beg_verse, end_verse, word
|
||||
// );
|
||||
if word.starts_with(beg_verse)
|
||||
&& word.ends_with(end_verse)
|
||||
{
|
||||
verse_name = word;
|
||||
// println!("TITLE: {verse_name}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(lyric) = lyric_map.get(verse_name) {
|
||||
if lyric.contains("\n\n") {
|
||||
let split_lyrics: Vec<&str> =
|
||||
lyric.split("\n\n").collect();
|
||||
for lyric in split_lyrics {
|
||||
if lyric.is_empty() {
|
||||
continue;
|
||||
}
|
||||
lyric_list.append(QString::from(lyric));
|
||||
if let Some(lyric) = lyric_map.get(verse_name) {
|
||||
if lyric.contains("\n\n") {
|
||||
let split_lyrics: Vec<&str> =
|
||||
lyric.split("\n\n").collect();
|
||||
for lyric in split_lyrics {
|
||||
if lyric.is_empty() {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
lyric_list.append(QString::from(lyric));
|
||||
}
|
||||
lyric_list.append(QString::from(lyric));
|
||||
} else {
|
||||
println!("NOT WORKING!");
|
||||
};
|
||||
}
|
||||
for lyric in lyric_list.iter() {
|
||||
// println!("da-list: {:?}", lyric);
|
||||
debug!(lyric = ?lyric)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
lyric_list.append(QString::from(lyric));
|
||||
} else {
|
||||
println!("NOT WORKING!");
|
||||
};
|
||||
}
|
||||
for lyric in lyric_list.iter() {
|
||||
// println!("da-list: {:?}", lyric);
|
||||
debug!(lyric = ?lyric)
|
||||
}
|
||||
lyric_list
|
||||
}
|
||||
}
|
||||
|
@ -400,9 +413,11 @@ impl Default for SongModelRust {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -416,12 +431,14 @@ pub fn get_song(id: i32) -> Result<Song> {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
};
|
||||
debug!("getting song with id: {id}");
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Song, r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = ?"#, id).fetch_one(&mut db).await?;
|
||||
let result = query_as!(Song, r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#, id).fetch_one(&mut db).await?;
|
||||
debug!(?result);
|
||||
Ok(result)
|
||||
})
|
||||
|
@ -440,7 +457,7 @@ impl song_model::SongModel {
|
|||
static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Song, r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
let result = query_as!(Song, r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
match result {
|
||||
Ok(s) => s.into_iter().for_each(|s| self.as_mut().add_song(s)),
|
||||
Err(e) => error!("There was an error in converting songs: {e}"),
|
||||
|
@ -453,7 +470,13 @@ impl song_model::SongModel {
|
|||
return false;
|
||||
}
|
||||
|
||||
let song_id = self.as_mut().rust_mut().songs.get(index as usize).unwrap().id;
|
||||
let song_id = self
|
||||
.as_mut()
|
||||
.rust_mut()
|
||||
.songs
|
||||
.get(index as usize)
|
||||
.unwrap()
|
||||
.id;
|
||||
let thread = self.qt_thread();
|
||||
let db = &mut self.as_mut().rust_mut().db;
|
||||
|
||||
|
@ -504,7 +527,7 @@ impl song_model::SongModel {
|
|||
};
|
||||
|
||||
rt.block_on(async {
|
||||
let result = query!(r#"INSERT into songs (vorder, fontSize, backgroundType, horizontalTextAlignment, verticalTextAlignment, title, font, background, lyrics, ccli, author, audio, id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#,
|
||||
let result = query!(r#"INSERT into songs (verse_order, font_size, background_type, horizontal_text_alignment, vertical_text_alignment, title, font, background, lyrics, ccli, author, audio, id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#,
|
||||
song.verse_order,
|
||||
song.font_size,
|
||||
song.background_type,
|
||||
|
@ -519,7 +542,7 @@ impl song_model::SongModel {
|
|||
song.audio,
|
||||
song.id)
|
||||
.fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
|
||||
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
self.as_mut().add_song(song);
|
||||
|
@ -586,16 +609,23 @@ impl song_model::SongModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
let db_string = updated_title.clone().to_string();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET title = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE songs SET title = ? where id = ?",
|
||||
db_string,
|
||||
song_id
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
if let Some(song) =
|
||||
self.as_mut().rust_mut().songs.get_mut(index)
|
||||
{
|
||||
debug!(?song, title = updated_title.to_string());
|
||||
debug!(
|
||||
?song,
|
||||
title = updated_title.to_string()
|
||||
);
|
||||
song.title = updated_title.to_string();
|
||||
self.as_mut().data_changed(
|
||||
&model_index,
|
||||
|
@ -608,9 +638,11 @@ impl song_model::SongModel {
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("There was an error updating title in db: {e}");
|
||||
error!(
|
||||
"There was an error updating title in db: {e}"
|
||||
);
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -714,9 +746,13 @@ impl song_model::SongModel {
|
|||
let db_string = updated_audio.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET audio = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE songs SET audio = ? where id = ?",
|
||||
db_string,
|
||||
song_id
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
|
@ -739,9 +775,11 @@ impl song_model::SongModel {
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("There was an error updating audio in db: {e}");
|
||||
error!(
|
||||
"There was an error updating audio in db: {e}"
|
||||
);
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -758,9 +796,13 @@ impl song_model::SongModel {
|
|||
let db_string = updated_ccli.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET ccli = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE songs SET ccli = ? where id = ?",
|
||||
db_string,
|
||||
song_id
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
|
@ -783,9 +825,11 @@ impl song_model::SongModel {
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("There was an error updating ccli in db: {e}");
|
||||
error!(
|
||||
"There was an error updating ccli in db: {e}"
|
||||
);
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -802,7 +846,7 @@ impl song_model::SongModel {
|
|||
let db_string = updated_verse_order.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET vorder = ? where id = ?", db_string, song_id)
|
||||
let result = query!("UPDATE songs SET verse_order = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
|
@ -891,7 +935,7 @@ impl song_model::SongModel {
|
|||
let db_string = updated_background_type.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET backgroundType = ? where id = ?", db_string, song_id)
|
||||
let result = query!("UPDATE songs SET background_type = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
|
@ -933,10 +977,11 @@ impl song_model::SongModel {
|
|||
.as_mut()
|
||||
.get_indices(song_id, SongRoles::HorizontalTextAlignment);
|
||||
|
||||
let db_string = updated_horizontal_text_alignment.clone().to_string();
|
||||
let db_string =
|
||||
updated_horizontal_text_alignment.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET horizontalTextAlignment = ? where id = ?", db_string, song_id)
|
||||
let result = query!("UPDATE songs SET horizontal_text_alignment = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
|
@ -978,10 +1023,11 @@ impl song_model::SongModel {
|
|||
.as_mut()
|
||||
.get_indices(song_id, SongRoles::VerticalTextAlignment);
|
||||
|
||||
let db_string = updated_vertical_text_alignment.clone().to_string();
|
||||
let db_string =
|
||||
updated_vertical_text_alignment.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET verticalTextAlignment = ? where id = ?", db_string, song_id)
|
||||
let result = query!("UPDATE songs SET vertical_text_alignment = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
|
@ -1025,9 +1071,13 @@ impl song_model::SongModel {
|
|||
let db_string = updated_font.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET font = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE songs SET font = ? where id = ?",
|
||||
db_string,
|
||||
song_id
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
|
@ -1050,9 +1100,11 @@ impl song_model::SongModel {
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("There was an error updating font in db: {e}");
|
||||
error!(
|
||||
"There was an error updating font in db: {e}"
|
||||
);
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -1069,7 +1121,7 @@ impl song_model::SongModel {
|
|||
let db_string = updated_font_size.clone().to_string();
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE songs SET fontSize = ? where id = ?", db_string, song_id)
|
||||
let result = query!("UPDATE songs SET font_size = ? where id = ?", db_string, song_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
pub mod video_model {
|
||||
unsafe extern "C++" {
|
||||
include!(< QAbstractListModel >);
|
||||
type QAbstractListModel;
|
||||
include!("cxx-qt-lib/qhash.h");
|
||||
type QHash_i32_QByteArray =
|
||||
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
|
||||
|
@ -34,15 +35,18 @@ pub mod video_model {
|
|||
Looping,
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[base = "QAbstractListModel"]
|
||||
#[base = QAbstractListModel]
|
||||
#[qml_element]
|
||||
#[qproperty(i32, count)]
|
||||
type VideoModel = super::VideoModelRust;
|
||||
|
||||
#[inherit]
|
||||
#[qsignal]
|
||||
#[cxx_name = "dataChanged"]
|
||||
fn data_changed(
|
||||
self: Pin<&mut VideoModel>,
|
||||
top_left: &QModelIndex,
|
||||
|
@ -102,8 +106,11 @@ pub mod video_model {
|
|||
|
||||
impl cxx_qt::Threading for VideoModel {}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[inherit]
|
||||
#[cxx_name = "beginInsertRows"]
|
||||
unsafe fn begin_insert_rows(
|
||||
self: Pin<&mut VideoModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -112,9 +119,11 @@ pub mod video_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endInsertRows"]
|
||||
unsafe fn end_insert_rows(self: Pin<&mut VideoModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginRemoveRows"]
|
||||
unsafe fn begin_remove_rows(
|
||||
self: Pin<&mut VideoModel>,
|
||||
parent: &QModelIndex,
|
||||
|
@ -123,6 +132,7 @@ pub mod video_model {
|
|||
);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginMoveRows"]
|
||||
unsafe fn begin_move_rows(
|
||||
self: Pin<&mut VideoModel>,
|
||||
source_parent: &QModelIndex,
|
||||
|
@ -133,18 +143,23 @@ pub mod video_model {
|
|||
) -> bool;
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endMoveRows"]
|
||||
unsafe fn end_move_rows(self: Pin<&mut VideoModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endRemoveRows"]
|
||||
unsafe fn end_remove_rows(self: Pin<&mut VideoModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "beginResetModel"]
|
||||
unsafe fn begin_reset_model(self: Pin<&mut VideoModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "endResetModel"]
|
||||
unsafe fn end_reset_model(self: Pin<&mut VideoModel>);
|
||||
|
||||
#[inherit]
|
||||
#[cxx_name = "canFetchMore"]
|
||||
fn can_fetch_more(
|
||||
self: &VideoModel,
|
||||
parent: &QModelIndex,
|
||||
|
@ -168,19 +183,22 @@ pub mod video_model {
|
|||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "roleNames"]
|
||||
fn role_names(self: &VideoModel) -> QHash_i32_QByteArray;
|
||||
|
||||
#[qinvokable]
|
||||
#[cxx_override]
|
||||
#[cxx_name = "rowCount"]
|
||||
fn row_count(self: &VideoModel, _parent: &QModelIndex)
|
||||
-> i32;
|
||||
-> i32;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
use color_eyre::eyre::Error;
|
||||
use cxx_qt::{CxxQtType, Threading};
|
||||
use cxx_qt_lib::{QByteArray, QModelIndex, QString, QUrl, QVariant};
|
||||
use sqlx::{query, query_as, Connection, SqliteConnection};
|
||||
use sqlx::{Connection, SqliteConnection, query, query_as};
|
||||
use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use tracing::{debug, error};
|
||||
|
@ -224,9 +242,11 @@ impl Default for VideoModelRust {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,12 +260,20 @@ pub fn get_video(index: i32) -> color_eyre::Result<Video> {
|
|||
let mut db_url = String::from("sqlite://");
|
||||
db_url.push_str(data.to_str().unwrap());
|
||||
rt.block_on(async {
|
||||
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||
SqliteConnection::connect(&db_url)
|
||||
.await
|
||||
.expect("problems")
|
||||
})
|
||||
};
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!" from videos where id = ?"#, index).fetch_one(&mut db).await?;
|
||||
Ok(result)
|
||||
let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!" from videos where id = ?"#, index).fetch_one(&mut db).await;
|
||||
match result {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
error!(?e);
|
||||
Err(color_eyre::Report::from(e))
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -261,7 +289,7 @@ impl video_model::VideoModel {
|
|||
pub fn setup(mut self: Pin<&mut Self>) {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!" from videos"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!" from videos"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
|
||||
match result {
|
||||
Ok(v) => v.into_iter().for_each(|v| self.as_mut().add_video(v)),
|
||||
Err(e) => error!("There was an error in converting songs: {e}"),
|
||||
|
@ -277,7 +305,10 @@ impl video_model::VideoModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
rt.block_on(async {
|
||||
let result = query!("delete from videos where id = ?", video_id).execute(&mut self.as_mut().rust_mut().db).await;
|
||||
let result =
|
||||
query!("delete from videos where id = ?", video_id)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
unsafe {
|
||||
|
@ -334,7 +365,7 @@ impl video_model::VideoModel {
|
|||
rt.block_on(async {
|
||||
let video_title = video_title.to_string();
|
||||
let video_path = video_path.to_string();
|
||||
let result = query!(r#"INSERT into videos (id, title, filePath, startTime, endTime, loop) VALUES (?, ?, ?, ?, ?, ?)"#,
|
||||
let result = query!(r#"INSERT into videos (id, title, file_path, start_time, end_time, loop) VALUES (?, ?, ?, ?, ?, ?)"#,
|
||||
video_id,
|
||||
video_title,
|
||||
video_path,
|
||||
|
@ -435,9 +466,13 @@ impl video_model::VideoModel {
|
|||
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE videos SET loop = ? where id = ?", loop_value, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE videos SET loop = ? where id = ?",
|
||||
loop_value,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for video in self
|
||||
|
@ -448,9 +483,11 @@ impl video_model::VideoModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
video.looping = loop_value;
|
||||
debug!(title = video.title,
|
||||
looping = loop_value,
|
||||
"updated video loop");
|
||||
debug!(
|
||||
title = video.title,
|
||||
looping = loop_value,
|
||||
"updated video loop"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -462,7 +499,7 @@ impl video_model::VideoModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -481,9 +518,13 @@ impl video_model::VideoModel {
|
|||
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE videos SET endTime = ? where id = ?", updated_end_time, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE videos SET end_time = ? where id = ?",
|
||||
updated_end_time,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for video in self
|
||||
|
@ -494,9 +535,11 @@ impl video_model::VideoModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
video.end_time = updated_end_time;
|
||||
debug!(title = video.title,
|
||||
end_time = updated_end_time,
|
||||
"updated video end_time");
|
||||
debug!(
|
||||
title = video.title,
|
||||
end_time = updated_end_time,
|
||||
"updated video end_time"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -508,7 +551,7 @@ impl video_model::VideoModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -527,9 +570,13 @@ impl video_model::VideoModel {
|
|||
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let result = query!("UPDATE videos SET startTime = ? where id = ?", updated_start_time, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE videos SET start_time = ? where id = ?",
|
||||
updated_start_time,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for video in self
|
||||
|
@ -540,9 +587,11 @@ impl video_model::VideoModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
video.start_time = updated_start_time;
|
||||
debug!(title = video.title,
|
||||
start_time = updated_start_time,
|
||||
"updated video start_time");
|
||||
debug!(
|
||||
title = video.title,
|
||||
start_time = updated_start_time,
|
||||
"updated video start_time"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -554,7 +603,7 @@ impl video_model::VideoModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -574,9 +623,13 @@ impl video_model::VideoModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let title = updated_title.to_string();
|
||||
let result = query!("UPDATE videos SET title = ? where id = ?", title, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE videos SET title = ? where id = ?",
|
||||
title,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for video in self
|
||||
|
@ -587,9 +640,11 @@ impl video_model::VideoModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
video.title = title.clone();
|
||||
debug!(title = video.title,
|
||||
title = title,
|
||||
"updated video title");
|
||||
debug!(
|
||||
title = video.title,
|
||||
title = title,
|
||||
"updated video title"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -601,7 +656,7 @@ impl video_model::VideoModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
@ -620,9 +675,13 @@ impl video_model::VideoModel {
|
|||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(async {
|
||||
let updated_path = updated_path.to_string();
|
||||
let result = query!("UPDATE videos SET filePath = ? where id = ?", updated_path, index)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
let result = query!(
|
||||
"UPDATE videos SET file_path = ? where id = ?",
|
||||
updated_path,
|
||||
index
|
||||
)
|
||||
.execute(&mut self.as_mut().rust_mut().db)
|
||||
.await;
|
||||
match result {
|
||||
Ok(_i) => {
|
||||
for video in self
|
||||
|
@ -633,9 +692,11 @@ impl video_model::VideoModel {
|
|||
.filter(|x| x.id == index)
|
||||
{
|
||||
video.path = updated_path.clone();
|
||||
debug!(title = video.title,
|
||||
path = updated_path,
|
||||
"updated video path");
|
||||
debug!(
|
||||
title = video.title,
|
||||
path = updated_path,
|
||||
"updated video path"
|
||||
);
|
||||
}
|
||||
self.as_mut().data_changed(
|
||||
model_index,
|
||||
|
@ -647,7 +708,7 @@ impl video_model::VideoModel {
|
|||
Err(e) => {
|
||||
error!("Error connecting to db: {e}");
|
||||
false
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
|
|
|
@ -7,6 +7,8 @@ mod ytdl {
|
|||
type QString = cxx_qt_lib::QString;
|
||||
}
|
||||
|
||||
#[auto_cxx_name]
|
||||
#[auto_rust_name]
|
||||
unsafe extern "RustQt" {
|
||||
#[qobject]
|
||||
#[qml_element]
|
||||
|
@ -67,14 +69,10 @@ impl ytdl::Ytdl {
|
|||
.run()
|
||||
.unwrap();
|
||||
let output = ytdl.into_single_video().unwrap();
|
||||
debug!(
|
||||
output.title,
|
||||
output.thumbnail, output.url
|
||||
);
|
||||
debug!(output.title, output.thumbnail, output.url);
|
||||
let title = QString::from(&output.title);
|
||||
let thumbnail = QUrl::from(
|
||||
&output.thumbnail.unwrap_or_default(),
|
||||
);
|
||||
let thumbnail =
|
||||
QUrl::from(&output.thumbnail.unwrap_or_default());
|
||||
let mut file = String::from(output_dirs);
|
||||
file.push('/');
|
||||
file.push_str(&output.title);
|
||||
|
@ -86,12 +84,8 @@ impl ytdl::Ytdl {
|
|||
qobject_ytdl.as_mut().set_loaded(true);
|
||||
qobject_ytdl.as_mut().set_loading(false);
|
||||
qobject_ytdl.as_mut().set_title(title);
|
||||
qobject_ytdl
|
||||
.as_mut()
|
||||
.set_thumbnail(thumbnail);
|
||||
qobject_ytdl
|
||||
.as_mut()
|
||||
.set_file(QUrl::from(&file));
|
||||
qobject_ytdl.as_mut().set_thumbnail(thumbnail);
|
||||
qobject_ytdl.as_mut().set_file(QUrl::from(&file));
|
||||
})
|
||||
});
|
||||
true
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue