Compare commits

..

No commits in common. "b56425c671a08783084d46a7beaccfd01cd6454a" and "c40a4b3fe1257a17cb4d46e5fb7f7e9ab1df24a4" have entirely different histories.

45 changed files with 819 additions and 1711 deletions

View file

@ -30,10 +30,7 @@ include(ECMPoQmTools)
kde_enable_exceptions() kde_enable_exceptions()
set(CXXQT_QTCOMPONENTS Core Gui Qml QuickControls2 QuickTest Test) find_package(Qt6 ${QT_MIN_VERSION} REQUIRED NO_MODULE COMPONENTS Core Core5Compat Quick Test Gui Qml QuickControls2 Widgets Sql QmlImportScanner WebEngineQuick)
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(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Kirigami CoreAddons I18n)
# find_package(KF6FileMetaData ${KF6_MIN_VERSION}) # find_package(KF6FileMetaData ${KF6_MIN_VERSION})
@ -60,70 +57,45 @@ set_package_properties(Ytdlp PROPERTIES TYPE RUNTIME)
# execute_process(COMMAND ${XDG-DESKTOP-MENU_EXECUTABLE} install --novender librepresenter.desktop) # execute_process(COMMAND ${XDG-DESKTOP-MENU_EXECUTABLE} install --novender librepresenter.desktop)
get_target_property(QMAKE Qt::qmake IMPORTED_LOCATION) get_target_property(QMAKE Qt::qmake IMPORTED_LOCATION)
find_package(CxxQt QUIET) find_package(Corrosion QUIET)
if(NOT CxxQt_FOUND) if(NOT Corrosion_FOUND)
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
CxxQt Corrosion
GIT_REPOSITORY https://github.com/kdab/cxx-qt-cmake.git GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.7.0 GIT_TAG v0.3.0
) )
FetchContent_MakeAvailable(CxxQt) FetchContent_MakeAvailable(Corrosion)
endif() endif()
# find_package(Corrosion QUIET) add_subdirectory(src)
# 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) 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 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 # 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 # generated headers so CMake can find them. To do this, tell Corrosion
# to set the CXXQT_EXPORT_DIR environment variable when calling `cargo build`. # to set the CXXQT_EXPORT_DIR environment variable when calling `cargo build`.
# Also, set the QMAKE environment variable to ensure the Rust library uses # Also, set the QMAKE environment variable to ensure the Rust library uses
# the same installation of Qt as CMake. # the same installation of Qt as CMake.
# set(CXXQT_EXPORT_DIR "${CMAKE_CURRENT_BINARY_DIR}/cxxqt") set(CXXQT_EXPORT_DIR "${CMAKE_CURRENT_BINARY_DIR}/cxxqt")
# corrosion_set_env_vars(${CRATE} corrosion_set_env_vars(${CRATE}
# "CXXQT_EXPORT_DIR=${CXXQT_EXPORT_DIR}" "CXXQT_EXPORT_DIR=${CXXQT_EXPORT_DIR}"
# "QMAKE=${QMAKE}" "QMAKE=${QMAKE}"
# ) )
add_subdirectory(src) add_library(${APP_NAME}_lib INTERFACE)
# Include the headers generated by the Rust library's build script. Each # Include the headers generated by the Rust library's build script. Each
# crate gets its own subdirectory under CXXQT_EXPORT_DIR. This allows you # crate gets its own subdirectory under CXXQT_EXPORT_DIR. This allows you
# to include headers generated by multiple crates without risk of one crate # to include headers generated by multiple crates without risk of one crate
# overwriting another's files. # overwriting another's files.
target_include_directories(liblumina INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}") target_include_directories(${APP_NAME}_lib INTERFACE "${CXXQT_EXPORT_DIR}/${CRATE}")
# Link the Rust INTERFACE library target to Qt. Do this on the library target # 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 # 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. # executable which link the Rust library, for example tests, will also link Qt.
target_link_libraries(liblumina INTERFACE target_link_libraries(${APP_NAME}_lib INTERFACE
"$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-static>" "$<LINK_LIBRARY:WHOLE_ARCHIVE,${CRATE}-static>"
Qt6::Quick Qt6::Quick
Qt6::Qml Qt6::Qml
@ -132,7 +104,6 @@ target_link_libraries(liblumina INTERFACE
Qt6::Widgets Qt6::Widgets
Qt6::Sql Qt6::Sql
Qt6::WebEngineQuick Qt6::WebEngineQuick
Qt6::Multimedia
KF6::Kirigami KF6::Kirigami
KF6::I18n KF6::I18n
KF6::CoreAddons KF6::CoreAddons
@ -143,9 +114,8 @@ target_link_libraries(liblumina INTERFACE
crypto crypto
) )
# Link to the Rust library # Link to the Rust library
target_link_libraries(${APP_NAME} PRIVATE liblumina) target_link_libraries(${APP_NAME} PRIVATE ${APP_NAME}_lib)
# If we are using a statically linked Qt then we need to import any qml plugins # If we are using a statically linked Qt then we need to import any qml plugins
qt_import_qml_plugins(${APP_NAME}) qt_import_qml_plugins(${APP_NAME})

159
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
@ -338,19 +338,6 @@ dependencies = [
"serde", "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]] [[package]]
name = "block" name = "block"
version = "0.1.6" version = "0.1.6"
@ -503,6 +490,32 @@ dependencies = [
"unicode-segmentation", "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]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.4" version = "0.9.4"
@ -580,6 +593,21 @@ dependencies = [
"link-cplusplus", "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]] [[package]]
name = "cxx-gen" name = "cxx-gen"
version = "0.7.128" version = "0.7.128"
@ -594,41 +622,38 @@ dependencies = [
[[package]] [[package]]
name = "cxx-qt" name = "cxx-qt"
version = "0.7.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "208ad6c4feac92f221fde00796f317b049ba1892b97be0d60ca177d0d3469fc5" checksum = "08aa6cda7588b6d17c563b0d2fadc060d4204d04908c0f359ae288857091218d"
dependencies = [ dependencies = [
"cxx", "cxx",
"cxx-qt-build",
"cxx-qt-macro", "cxx-qt-macro",
"qt-build-utils",
"static_assertions", "static_assertions",
"thiserror",
] ]
[[package]] [[package]]
name = "cxx-qt-build" name = "cxx-qt-build"
version = "0.7.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f80e109aa68795486c70c302f6c2d921f00028b3b62038a4601efb5c585c1c" checksum = "9e097b99f49792922a72a8ca35d9391762e48e63363d6998255be1f2ca1edf69"
dependencies = [ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
"convert_case",
"cxx-gen", "cxx-gen",
"cxx-qt-gen", "cxx-qt-gen",
"cxx-qt-lib-headers",
"proc-macro2", "proc-macro2",
"qt-build-utils", "qt-build-utils",
"quote", "quote",
"serde",
"serde_json",
"version_check", "version_check",
] ]
[[package]] [[package]]
name = "cxx-qt-gen" name = "cxx-qt-gen"
version = "0.7.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc17d95ca9cc60c2f91f804a4e0ba6a3e1b8ed338c207a1bd8d176133e2fd05d" checksum = "ede7c73dbfbcc234d8826919e257830c1789db2cac586546a87d2a82e3cbe5d5"
dependencies = [ dependencies = [
"clang-format", "clang-format",
"convert_case", "convert_case",
@ -640,33 +665,27 @@ dependencies = [
[[package]] [[package]]
name = "cxx-qt-lib" name = "cxx-qt-lib"
version = "0.7.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f116c5d982bbf3be707acf97f566802c30454d52ca319c745ed39a04834e8bc6" checksum = "002f1a6119bcb7dfec67eb7c0803a7b1d595dc54610559faeac35133f22a5880"
dependencies = [ dependencies = [
"cxx", "cxx",
"cxx-qt", "cxx-build",
"cxx-qt-build", "cxx-qt-lib-headers",
"qt-build-utils", "qt-build-utils",
] ]
[[package]] [[package]]
name = "cxx-qt-lib-extras" name = "cxx-qt-lib-headers"
version = "0.7.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe1aaed6391a224d746e314104f33b4031138291ebd368170a2109b6008ace2" checksum = "9abdeab6b77cfc5a53b724f3f62a37bcb5ac1423cccc2dba4c134f4273440b8c"
dependencies = [
"cxx",
"cxx-qt",
"cxx-qt-build",
"cxx-qt-lib",
]
[[package]] [[package]]
name = "cxx-qt-macro" name = "cxx-qt-macro"
version = "0.7.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58a4fe02c0604eda28c605792f5ba0d0251b4947f8f0fc43e55b61c06b2b8ec6" checksum = "699e8a668c03b03419b084960d72eed253632bb16349b33fd0a0c893b61b664c"
dependencies = [ dependencies = [
"cxx-qt-gen", "cxx-qt-gen",
"proc-macro2", "proc-macro2",
@ -1413,9 +1432,9 @@ checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.13.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [ dependencies = [
"either", "either",
] ]
@ -1471,7 +1490,6 @@ dependencies = [
"cxx-qt-lib", "cxx-qt-lib",
"dirs", "dirs",
"fastrand 2.1.1", "fastrand 2.1.1",
"lumina_core",
"obws", "obws",
"qt-build-utils", "qt-build-utils",
"quote", "quote",
@ -1555,32 +1573,6 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 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]] [[package]]
name = "malloc_buf" name = "malloc_buf"
version = "0.0.6" version = "0.0.6"
@ -1590,15 +1582,6 @@ dependencies = [
"libc", "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]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -2109,9 +2092,9 @@ dependencies = [
[[package]] [[package]]
name = "qt-build-utils" name = "qt-build-utils"
version = "0.7.1" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efb239fdd8c036fabb95364320041ef68197cd4ab971bb3b4ca3ea0b7b93d12c" checksum = "d59c828fe2434dad34dd0c30a4ba037509b61dad92a55baf0dc42699e6aa2f10"
dependencies = [ dependencies = [
"cc", "cc",
"thiserror", "thiserror",
@ -2381,6 +2364,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scratch"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.11.1" version = "2.11.1"
@ -3223,12 +3212,6 @@ version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-id"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.12"
@ -3321,9 +3304,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "versions" name = "versions"
version = "6.3.2" version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25d498b63d1fdb376b4250f39ab3a5ee8d103957346abacd911e2d8b612c139" checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd"
dependencies = [ dependencies = [
"itertools", "itertools",
"nom", "nom",

View file

@ -1,5 +1,5 @@
[workspace] [workspace]
members = [ "smdview/blah","src/rust/core"] members = ["src/rust/core"]
[package] [package]
name = "liblumina" name = "liblumina"
@ -21,14 +21,13 @@ path = "src/rust/lib.rs"
# path = "src/rust/main.rs" # path = "src/rust/main.rs"
[dependencies] [dependencies]
lumina_core = { path = "src/rust/core" }
configparser = "3.0.2" configparser = "3.0.2"
serde = "1.0.152" serde = "1.0.152"
serde_derive = "1.0.152" serde_derive = "1.0.152"
quote = "1.0.27" quote = "1.0.27"
cxx = "1.0.83" cxx = "1.0.83"
cxx-qt = "0.7.1" cxx-qt = "0.6.1"
cxx-qt-lib = { version = "0.7.1", features = [ "qt_full" ] } cxx-qt-lib = "0.6.1"
# home = "0.5.4" # home = "0.5.4"
dirs = "5.0.0" dirs = "5.0.0"
# libsqlite3-sys = { version = ">=0.17.2", features = ["bundled"] } # libsqlite3-sys = { version = ">=0.17.2", features = ["bundled"] }
@ -51,8 +50,8 @@ color-eyre = "0.6.3"
# cxx-qt-build generates C++ code from the `#[cxx_qt::bridge]` module # cxx-qt-build generates C++ code from the `#[cxx_qt::bridge]` module
# and compiles it together with the Rust static library # and compiles it together with the Rust static library
[build-dependencies] [build-dependencies]
cxx-qt-build = { version = "0.7.1", features = [ "link_qt_object_files" ] } cxx-qt-build = { version = "0.6.1", features = [ "link_qt_object_files" ] }
qt-build-utils = "0.7.1" qt-build-utils = "0.6.1"
# [dependencies.confy] # [dependencies.confy]
# features = ["yaml_conf"] # features = ["yaml_conf"]

View file

@ -4,8 +4,7 @@
:CATEGORY: dev :CATEGORY: dev
:END: :END:
* Tasks [63%] [55/87] * Tasks [63%] [55/86]
** 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] Plugin architecture with steel or some scheme as an extension language
** TODO [#A] Server client architecture ** TODO [#A] Server client architecture
** TODO [#A] Organize and layout structure of rust code :maintenance: ** TODO [#A] Organize and layout structure of rust code :maintenance:

View file

@ -1,5 +1,3 @@
use std::{env, path::PathBuf};
use cxx_qt_build::{CxxQtBuilder, QmlModule}; use cxx_qt_build::{CxxQtBuilder, QmlModule};
fn main() { fn main() {
@ -19,37 +17,6 @@ fn main() {
.file("src/rust/obs.rs") .file("src/rust/obs.rs")
.build(); .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() // CxxQtBuilder::new()
// // Link Qt's Network library // // Link Qt's Network library
// // - Qt Core is always linked // // - Qt Core is always linked
@ -60,64 +27,13 @@ fn main() {
// // .qt_module("Kirigami") // // .qt_module("Kirigami")
// // .qt_module("WebEngineQuick") // // .qt_module("WebEngineQuick")
// .qt_module("Network") // .qt_module("Network")
// // .qt_module("Quick")
// // .qt_module("Test")
// // .qt_module("WebEngineQuick")
// // .qt_module("I18n") // // .qt_module("I18n")
// // .qt_module("CoreAddons") // // .qt_module("CoreAddons")
// .qml_module(QmlModule { // .qml_module(QmlModule {
// uri: "com.cochrun.xyz", // uri: "com.cochrun.xyz",
// rust_files: &[ // rust_files: &["src/rust/settings.rs"],
// "src/rust/settings.rs", // qml_files: &["src/qml/main.qml"],
// "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() // ..Default::default()
// }) // })
// .cc_builder(|cc| {
// cc.include("cpp");
// cc.include(format!("{}", ki18n_include_path.display()));
// })
// .build(); // .build();
} }

131
flake.lock generated
View file

@ -1,56 +1,15 @@
{ {
"nodes": { "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": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1710146030,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -61,15 +20,14 @@
}, },
"naersk": { "naersk": {
"inputs": { "inputs": {
"fenix": "fenix_2", "nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1752689277, "lastModified": 1721727458,
"narHash": "sha256-uldUBFkZe/E7qbvxa3mH1ItrWZyT6w1dBKJQF/3ZSsc=", "narHash": "sha256-r/xppY958gmZ4oTfLiHN0ZGuQ+RSTijDblVgVLFi1mw=",
"owner": "nix-community", "owner": "nix-community",
"repo": "naersk", "repo": "naersk",
"rev": "0e72363d0938b0208d6c646d10649164c43f4d64", "rev": "3fb418eaf352498f6b6c30592e3beb63df42ef11",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -80,43 +38,23 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1752950548, "lastModified": 0,
"narHash": "sha256-NS6BLD0lxOrnCiEOcvQCDVPXafX1/ek1dfJHX1nUIzc=", "narHash": "sha256-+yj+xgsfZaErbfYM3T+QvEE2hU7UuE+Jf0fJCJ8uPS0=",
"owner": "nixos", "path": "/nix/store/6inj491lsap4ia7mmvn2gbh53jb27zq0-source",
"repo": "nixpkgs", "type": "path"
"rev": "c87b95e25065c028d31a94f06a62927d18763fdf",
"type": "github"
}, },
"original": { "original": {
"owner": "nixos", "id": "nixpkgs",
"ref": "nixos-unstable", "type": "indirect"
"repo": "nixpkgs",
"type": "github"
} }
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1752077645, "lastModified": 1725634671,
"narHash": "sha256-HM791ZQtXV93xtCY+ZxG1REzhQenSQO020cu6rHtAPk=", "narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=",
"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", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c87b95e25065c028d31a94f06a62927d18763fdf", "rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -128,44 +66,9 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"fenix": "fenix",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"naersk": "naersk", "naersk": "naersk",
"nixpkgs": "nixpkgs_3" "nixpkgs": "nixpkgs_2"
}
},
"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": { "systems": {

162
flake.nix
View file

@ -6,121 +6,77 @@
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
naersk.url = "github:nix-community/naersk"; naersk.url = "github:nix-community/naersk";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
fenix.url = "github:nix-community/fenix";
# nixpkgs.follows = "cargo2nix/nixpkgs"; # nixpkgs.follows = "cargo2nix/nixpkgs";
}; };
outputs = inputs: outputs = inputs: with inputs;
with inputs; flake-utils.lib.eachDefaultSystem
flake-utils.lib.eachDefaultSystem (system: (system:
let let
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
overlays = [ fenix.overlays.default ];
# overlays = [cargo2nix.overlays.default]; # overlays = [cargo2nix.overlays.default];
}; };
naersk' = pkgs.callPackage naersk { }; 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
nbi = with pkgs; [ # clang-tools
# ffmpeg # clang
alejandra # libclang
(pkgs.fenix.stable.withComponents [ # qt5.qtbase
"cargo" # qt5.qttools
"clippy" # qt5.qtquickcontrols2
"rust-src" # qt5.qtx11extras
"rustc" # qt5.qtmultimedia
"rustfmt" # qt5.qtwayland
]) # qt5.qtwebengine
rust-analyzer # 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"
# # '';
# };
bi = with pkgs; [ in rec
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 = { # packages = {
# crate = (rustPkgs.workspace.libre-presenter { }).bin; # crate = (rustPkgs.workspace.libre-presenter { }).bin;
# default = packages.crate; # default = packages.crate;
# }; # };
devShell = pkgs.mkShell { devShell = import ./shell.nix { inherit pkgs; };
nativeBuildInputs = nbi; defaultPackage = pkgs.libsForQt5.callPackage ./default.nix { };
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 { };
});
} }

View file

@ -15,7 +15,7 @@ test:
RUST_LOG=debug cargo test --benches --tests --all-features -- --nocapture RUST_LOG=debug cargo test --benches --tests --all-features -- --nocapture
testcore: testcore:
RUST_LOG=debug cargo test -p lumina_core --benches --tests --all-features -- --nocapture RUST_LOG=debug cargo test -p core --benches --tests --all-features -- --nocapture
alias b := build alias b := build
alias r := run alias r := run

View file

@ -1,17 +0,0 @@
[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"

View file

@ -1,12 +0,0 @@
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();
}

View file

@ -1,42 +0,0 @@
#[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();
}
}

View file

@ -1,71 +0,0 @@
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
}
}
}
}
}

View file

@ -1,49 +1,49 @@
// #include <QApplication> #include <QApplication>
#include <QtQml/QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QtCore/qstringliteral.h> #include <QtCore/qstringliteral.h>
#include <QtQml/QtQml> #include <QtQml>
#include <QtCore/QUrl> #include <QUrl>
#include <QtCore/QDebug> #include <QDebug>
// #include <K/KLocalizedContext> #include <KLocalizedContext>
// #include <KLocalizedString> #include <KLocalizedString>
// #include <KAboutData> #include <KAboutData>
#include <iostream> #include <iostream>
#include <QtQml/QQmlEngine> #include <QQmlEngine>
#include <QtWebEngineQuick/QtWebEngineQuick> #include <QtWebEngineQuick>
#include <QtCore/QObject> #include <QObject>
#include <QtCore/QtGlobal> #include <QtGlobal>
#include <QtGui/QOpenGLContext> #include <QOpenGLContext>
#include <QtGui/QGuiApplication> #include <QGuiApplication>
#include <QtQuickControls2/QQuickStyle> #include <QQuickStyle>
// #include <QSurfaceFormat> #include <QSurfaceFormat>
#include <QtQuick/QQuickWindow> #include <QtQuick/QQuickWindow>
#include <QtQuick/QQuickView> #include <QtQuick/QQuickView>
// #include <qapplication.h> #include <qapplication.h>
#include <QtCore/qcoreapplication.h> #include <qcoreapplication.h>
#include <QtCore/qdir.h> #include <qdir.h>
#include <QtCore/qglobal.h> #include <qglobal.h>
#include <QtGui/qguiapplication.h> #include <qguiapplication.h>
#include <QtQml/qqml.h> #include <qqml.h>
#include <QtQuickControls2/qquickstyle.h> #include <qquickstyle.h>
#include <QtCore/qstringliteral.h> #include <qstringliteral.h>
// #include <MpvAbstractItem> // #include <MpvAbstractItem>
// #include "cpp/mpv/mpvitem.h" // #include "cpp/mpv/mpvitem.h"
// #include "cpp/mpv/mpvproperties.h" // #include "cpp/mpv/mpvproperties.h"
// RUST // RUST
#include <liblumina/src/rust/file_helper.cxxqt.h> #include "cxx-qt-gen/file_helper.cxxqt.h"
#include <liblumina/src/rust/slide_object.cxxqt.h> #include "cxx-qt-gen/slide_object.cxxqt.h"
#include <liblumina/src/rust/slide_model.cxxqt.h> #include "cxx-qt-gen/slide_model.cxxqt.h"
#include <liblumina/src/rust/service_item_model.cxxqt.h> #include "cxx-qt-gen/service_item_model.cxxqt.h"
#include <liblumina/src/rust/settings.cxxqt.h> #include "cxx-qt-gen/settings.cxxqt.h"
#include <liblumina/src/rust/ytdl.cxxqt.h> #include "cxx-qt-gen/ytdl.cxxqt.h"
#include <liblumina/src/rust/presentation_model.cxxqt.h> #include "cxx-qt-gen/presentation_model.cxxqt.h"
#include <liblumina/src/rust/songs/song_model.cxxqt.h> #include "cxx-qt-gen/song_model.cxxqt.h"
#include <liblumina/src/rust/video_model.cxxqt.h> #include "cxx-qt-gen/video_model.cxxqt.h"
#include <liblumina/src/rust/image_model.cxxqt.h> #include "cxx-qt-gen/image_model.cxxqt.h"
#include <liblumina/src/rust/utils.cxxqt.h> #include "cxx-qt-gen/utils.cxxqt.h"
#include <liblumina/src/rust/songs/song_editor.cxxqt.h> #include "cxx-qt-gen/song_editor.cxxqt.h"
#include <liblumina/src/rust/obs.cxxqt.h> #include "cxx-qt-gen/obs.cxxqt.h"
static QWindow *windowFromEngine(QQmlApplicationEngine *engine) static QWindow *windowFromEngine(QQmlApplicationEngine *engine)
{ {
@ -60,22 +60,22 @@ int main(int argc, char *argv[])
QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("video-display"))); QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("video-display")));
QtWebEngineQuick::initialize(); QtWebEngineQuick::initialize();
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
// KLocalizedString::setApplicationDomain("lumina"); KLocalizedString::setApplicationDomain("lumina");
// KAboutData about; KAboutData about;
// about.setComponentName(QStringLiteral("lumina")); about.setComponentName(QStringLiteral("lumina"));
// about.setDisplayName(i18n("lumina")); about.setDisplayName(i18n("lumina"));
// about.setVersion(QByteArray("0.1")); about.setVersion(QByteArray("0.1"));
// about.setShortDescription(i18n("A churchpresentation app build with KDE tech.")); about.setShortDescription(i18n("A churchpresentation app build with KDE tech."));
// about.setLicense(KAboutLicense::GPL_V3); about.setLicense(KAboutLicense::GPL_V3);
// overwrite default-generated values of organizationDomain & desktopFileName // overwrite default-generated values of organizationDomain & desktopFileName
// about.setOrganizationDomain("tfcconnection.org"); about.setOrganizationDomain("tfcconnection.org");
// about.setDesktopFileName(QStringLiteral("org.tfcconneciton.lumina")); about.setDesktopFileName(QStringLiteral("org.tfcconneciton.lumina"));
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
// set the application metadata // set the application metadata
// KAboutData::setApplicationData(about); KAboutData::setApplicationData(about);
QCoreApplication::setOrganizationName(QStringLiteral("lumina")); QCoreApplication::setOrganizationName(QStringLiteral("lumina"));
QCoreApplication::setOrganizationDomain(QStringLiteral("tfcconnection.org")); QCoreApplication::setOrganizationDomain(QStringLiteral("tfcconnection.org"));
QCoreApplication::setApplicationName(QStringLiteral("lumina")); QCoreApplication::setApplicationName(QStringLiteral("lumina"));
@ -93,7 +93,7 @@ int main(int argc, char *argv[])
// qDebug() << QQuickStyle::availableStyles(); // qDebug() << QQuickStyle::availableStyles();
qDebug() << QIcon::themeName(); qDebug() << QIcon::themeName();
// qDebug() << QApplication::platformName(); qDebug() << QApplication::platformName();
//Need to instantiate our slide //Need to instantiate our slide
QScopedPointer<SlideModel> slideModel(new SlideModel); QScopedPointer<SlideModel> slideModel(new SlideModel);
@ -108,7 +108,6 @@ int main(int argc, char *argv[])
settings->setup(); settings->setup();
QQuickView *PresWindow = new QQuickView; QQuickView *PresWindow = new QQuickView;
PresWindow->setSource(QUrl(QStringLiteral("qrc:qml/presenter/PresentationWindow.qml")));
qDebug() << PresWindow; qDebug() << PresWindow;
qDebug() << PresWindow->isVisible(); qDebug() << PresWindow->isVisible();
@ -170,9 +169,9 @@ int main(int argc, char *argv[])
qmlRegisterSingletonInstance("org.presenter", 1, 0, "SlideModel", slideModel.get()); qmlRegisterSingletonInstance("org.presenter", 1, 0, "SlideModel", slideModel.get());
qmlRegisterSingletonInstance("org.presenter", 1, 0, "Utils", utils); qmlRegisterSingletonInstance("org.presenter", 1, 0, "Utils", utils);
qmlRegisterSingletonInstance("org.presenter", 1, 0, "SlideObject", slideobject.get()); 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, "RSettings", settings);
qmlRegisterSingletonInstance("org.presenter", 1, 0, "ObsModel", obsModel.get()); 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 // 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. // we need to set it as a separate context so that it can change it's slides too.
@ -185,7 +184,7 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
qDebug() << app.allWindows(); qDebug() << app.allWindows();
// engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
engine.load(QUrl(QStringLiteral("qrc:qml/main.qml"))); engine.load(QUrl(QStringLiteral("qrc:qml/main.qml")));
qDebug() << "Engine loaded"; qDebug() << "Engine loaded";

View file

@ -252,7 +252,6 @@ Item {
} }
function isDragFile(item) { function isDragFile(item) {
console.log(item);
console.log(item.toString()); console.log(item.toString());
var extension = item.toString().split('.').pop(); var extension = item.toString().split('.').pop();
var valid = false; var valid = false;

View file

@ -188,10 +188,6 @@ Controls.Page {
songModel: songModel songModel: songModel
} }
Presenter.PresentationWindow {
id: presWindow
}
Connections { Connections {
target: ServiceItemModel target: ServiceItemModel
function onSaveProgressChanged() { function onSaveProgressChanged() {
@ -356,20 +352,19 @@ Controls.Page {
function present(present) { function present(present) {
if (present) if (present)
{ {
/* presWindow.slideObj = SlideObject; */ PresWindow.showFullScreen();
presWindow.showFullScreen(); PresWindow.setSource("qrc:qml/presenter/PresentationWindow.qml")
/* presWindow.setSource("qrc:qml/presenter/PresentationWindow.qml") */ console.log(PresWindow);
console.log(presWindow);
/* presWinLoader.active = true; */ /* presWinLoader.active = true; */
} }
else { else {
presWindow.close(); PresWindow.close();
/* presWinLoader.active = false; */ /* presWinLoader.active = false; */
} }
} }
function closeAll() { presWindow.close() } function closeAll() { PresWindow.close() }
function changeVidPos(pos) { function changeVidPos(pos) {
presentation.slide.seek(pos); presentation.slide.seek(pos);

View file

@ -479,11 +479,6 @@ FocusScope {
previewSlide.stopVideo() previewSlide.stopVideo()
} }
function playVideo() {
/* showPassiveNotification("Stopping Video") */
previewSlide.playVideo()
}
function nextSlideAction() { function nextSlideAction() {
keyHandler.forceActiveFocus(); keyHandler.forceActiveFocus();
SlideModel.next() SlideModel.next()

View file

@ -6,13 +6,13 @@ import org.kde.kirigami 2.13 as Kirigami
import "./" as Presenter import "./" as Presenter
import org.presenter 1.0 import org.presenter 1.0
Window { Item {
id: presentationWindow id: presentationWindow
property Item slide: presentationSlide property Item slide: presentationSlide
/* property var SlideObject: SlideObject; */ /* property var slideObj */
property var pWin property var pWin
/* anchors.fill: parent */ anchors.fill: parent
/* title: "presentation-window" */ /* title: "presentation-window" */
/* height: maximumHeight */ /* height: maximumHeight */
@ -25,7 +25,7 @@ Window {
/* onClosing: { */ /* onClosing: { */
/* presentationSlide.stopVideo(); */ /* presentationSlide.stopVideo(); */
/* SlideObject.pause(); */ /* SlideObj.pause(); */
/* presentationSlide.stopAudio(); */ /* presentationSlide.stopAudio(); */
/* presenting = false; */ /* presenting = false; */
/* } */ /* } */
@ -34,7 +34,7 @@ Window {
target: PresWindow target: PresWindow
function onClosing() { function onClosing() {
presentationSlide.stopVideo(); presentationSlide.stopVideo();
SlideObject.pause(); SlideObj.pause();
presentationSlide.stopAudio(); presentationSlide.stopAudio();
presenting = false; presenting = false;
} }
@ -48,25 +48,25 @@ Window {
Presenter.Slide { Presenter.Slide {
id: presentationSlide id: presentationSlide
anchors.fill: parent anchors.fill: parent
imageSource: SlideObject.html ? "" : SlideObject.imageBackground imageSource: SlideObj.html ? "" : SlideObj.imageBackground
webSource: SlideObject.html ? SlideObject.imageBackground : "" webSource: SlideObj.html ? SlideObj.imageBackground : ""
htmlVisible: SlideObject.html htmlVisible: SlideObj.html
videoSource: presentationWindow.visible ? SlideObject.videoBackground : "" videoSource: presentationWindow.visible ? SlideObj.videoBackground : ""
audioSource: SlideObject.audio audioSource: SlideObj.audio
text: SlideObject.text text: SlideObj.text
chosenFont: SlideObject.font chosenFont: SlideObj.font
textSize: SlideObject.fontSize textSize: SlideObj.fontSize
pdfIndex: SlideObject.slideIndex pdfIndex: SlideObj.slideIndex
itemType: SlideObject.ty itemType: SlideObj.ty
vidLoop: SlideObject.looping vidLoop: SlideObj.looping
vidStartTime: SlideObject.videoStartTime vidStartTime: SlideObj.videoStartTime
vidEndTime: SlideObject.videoEndTime vidEndTime: SlideObj.videoEndTime
} }
Connections { Connections {
target: SlideObject target: SlideObj
function onVideoBackgroundChanged() { function onVideoBackgroundChanged() {
if (SlideObject.videoBackground === "") if (SlideObj.videoBackground === "")
stopVideo(); stopVideo();
else { else {
loadVideo(); loadVideo();
@ -74,12 +74,12 @@ Window {
} }
} }
function onIsPlayingChanged() { function onIsPlayingChanged() {
if(SlideObject.isPlaying) if(SlideObj.isPlaying)
presentationSlide.playVideo(); presentationSlide.playVideo();
pauseVideo(); pauseVideo();
} }
function onLoopingChanged() { function onLoopingChanged() {
if(SlideObject.looping) if(SlideObj.looping)
presentationSlide.loopVideo(); presentationSlide.loopVideo();
} }
function onAudioChanged() { function onAudioChanged() {

View file

@ -21,7 +21,6 @@ Kirigami.OverlaySheet {
Kirigami.FormLayout { Kirigami.FormLayout {
implicitHeight: Kirigami.Units.gridUnit * 30 implicitHeight: Kirigami.Units.gridUnit * 30
implicitWidth: Kirigami.Units.gridUnit * 30
Controls.ComboBox { Controls.ComboBox {
id: screenSelectionField id: screenSelectionField
Kirigami.FormData.label: i18nc("@label:textbox", "Presentation Screen:") Kirigami.FormData.label: i18nc("@label:textbox", "Presentation Screen:")

View file

@ -1,5 +1,5 @@
[package] [package]
name = "lumina_core" name = "lumina-core"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
authors = [ authors = [

View file

@ -1,133 +1,82 @@
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 tar::{Archive, Builder};
use tracing::error; use tracing::error;
use zstd::Encoder; 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( pub async fn save(list: Vec<ServiceItem>, path: impl AsRef<Path>) -> Result<()> {
list: Vec<ServiceItem>,
path: impl AsRef<Path>,
) -> Result<()> {
let path = path.as_ref(); let path = path.as_ref();
let save_file = File::create(path)?; let save_file = File::create(path)?;
let mut db = get_db().await; let mut db = get_db().await;
let json = process_service_items(&list, &mut db).await?; let json = process_service_items(&list, &mut db).await?;
let archive = let archive = store_service_items(&list, &mut db, &save_file, &json).await?;
store_service_items(&list, &mut db, &save_file, &json)
.await?;
Ok(()) Ok(())
} }
async fn store_service_items( async fn store_service_items(items: &Vec<ServiceItem>, db: &mut SqliteConnection, save_file: &File, json: &Value) -> Result<()> {
items: &Vec<ServiceItem>,
db: &mut SqliteConnection,
save_file: &File,
json: &Value,
) -> Result<()> {
let encoder = Encoder::new(save_file, 3).unwrap(); let encoder = Encoder::new(save_file, 3).unwrap();
let mut tar = Builder::new(encoder); let mut tar = Builder::new(encoder);
let mut temp_dir = dirs::data_dir().unwrap(); let mut temp_dir = dirs::data_dir().unwrap();
temp_dir.push("lumina"); temp_dir.push("lumina");
let mut s: String = 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_"); s.insert_str(0, "temp_");
temp_dir.push(s); temp_dir.push(s);
fs::create_dir_all(&temp_dir)?; fs::create_dir_all(&temp_dir)?;
let service_file = temp_dir.join("serviceitems.json"); let service_file = temp_dir.join("serviceitems.json");
fs::File::create(&service_file)?; fs::File::create(&service_file)?;
match fs::File::options() match fs::File::options().read(true).write(true).open(service_file) {
.read(true)
.write(true)
.open(service_file)
{
Ok(f) => { Ok(f) => {
serde_json::to_writer_pretty(f, json)?; serde_json::to_writer_pretty(f, json)?;
} },
Err(e) => { Err(e) => error!("There were problems making a file i guess: {e}"),
error!("There were problems making a file i guess: {e}")
}
}; };
for item in items { for item in items {
let background; let background;
let audio: Option<PathBuf>; let audio: Option<PathBuf>;
match item.kind { match item.kind {
ServiceItemKind::Song => { ServiceItemKind::Song => {
let song = let song = get_song_from_db(item.database_id, db).await?;
get_song_from_db(item.database_id, db).await?;
background = song.background; background = song.background;
audio = song.audio; audio = song.audio;
} },
ServiceItemKind::Image => { ServiceItemKind::Image => {
let image = let image = get_image_from_db(item.database_id, db).await?;
get_image_from_db(item.database_id, db).await?;
background = Some(Background::try_from(image.path)?); background = Some(Background::try_from(image.path)?);
audio = None; audio = None;
} },
ServiceItemKind::Video => { ServiceItemKind::Video => {
let video = let video = get_video_from_db(item.database_id, db).await?;
get_video_from_db(item.database_id, db).await?;
background = Some(Background::try_from(video.path)?); background = Some(Background::try_from(video.path)?);
audio = None; audio = None;
} },
ServiceItemKind::Presentation(_) => { ServiceItemKind::Presentation(_) => {
let presentation = let presentation = get_presentation_from_db(item.database_id, db).await?;
get_presentation_from_db(item.database_id, db) background = Some(Background::try_from(presentation.path)?);
.await?;
background =
Some(Background::try_from(presentation.path)?);
audio = None; audio = None;
} },
ServiceItemKind::Content => { ServiceItemKind::Content => {
todo!() todo!()
} },
}; };
if let Some(file) = audio { if let Some(file) = audio {
let audio_file = let audio_file = temp_dir.join(file.file_name().expect("Audio file couldn't be added to temp_dir"));
temp_dir.join(file.file_name().expect( match fs::File::create(&audio_file) {
"Audio file couldn't be added to temp_dir", Ok(_) => Ok(fs::copy(file, &audio_file)?),
)); Err(e) => Err(eyre!("Couldn't create audio file: {e}")),
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 { if let Some(file) = background {
let background_file = let background_file = temp_dir.join(file.path.file_name().expect("Background file couldn't be added to temp_dir"));
temp_dir.join(file.path.file_name().expect( match fs::File::create(&background_file) {
"Background file couldn't be added to temp_dir", Ok(_) => Ok(fs::copy(file.path, &background_file)?),
)); Err(e) => Err(eyre!("Couldn't create background file: {e}")),
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(()) Ok(())
@ -137,96 +86,66 @@ async fn clear_temp_dir(temp_dir: &Path) -> Result<()> {
todo!() todo!()
} }
async fn process_service_items( async fn process_service_items(items: &Vec<ServiceItem>, db: &mut SqliteConnection) -> Result<Value> {
items: &Vec<ServiceItem>,
db: &mut SqliteConnection,
) -> Result<Value> {
let mut values: Vec<Value> = vec![]; let mut values: Vec<Value> = vec![];
for item in items { for item in items {
match item.kind { match item.kind {
ServiceItemKind::Song => { ServiceItemKind::Song => {
let value = let value = process_song(item.database_id, db).await?;
process_song(item.database_id, db).await?;
values.push(value); values.push(value);
} },
ServiceItemKind::Image => { ServiceItemKind::Image => {
let value = let value = process_image(item.database_id, db).await?;
process_image(item.database_id, db).await?;
values.push(value); values.push(value);
} },
ServiceItemKind::Video => { ServiceItemKind::Video => {
let value = let value = process_video(item.database_id, db).await?;
process_video(item.database_id, db).await?;
values.push(value); values.push(value);
} },
ServiceItemKind::Presentation(_) => { ServiceItemKind::Presentation(_) => {
let value = let value = process_presentation(item.database_id, db).await?;
process_presentation(item.database_id, db)
.await?;
values.push(value); values.push(value);
} },
ServiceItemKind::Content => { ServiceItemKind::Content => {
todo!() todo!()
} },
} }
} }
let json = Value::from(values); let json = Value::from(values);
Ok(json) Ok(json)
} }
async fn process_song( async fn process_song(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Value> {
let song = get_song_from_db(database_id, db).await?; let song = get_song_from_db(database_id, db).await?;
let song_json = serde_json::to_value(&song)?; let song_json = serde_json::to_value(&song)?;
let kind_json = serde_json::to_value(ServiceItemKind::Song)?; let kind_json = serde_json::to_value(ServiceItemKind::Song)?;
let json = let json = serde_json::json!({"item": song_json, "kind": kind_json});
serde_json::json!({"item": song_json, "kind": kind_json});
Ok(json) Ok(json)
} }
async fn process_image( async fn process_image(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Value> {
let image = get_image_from_db(database_id, db).await?; let image = get_image_from_db(database_id, db).await?;
let image_json = serde_json::to_value(&image)?; let image_json = serde_json::to_value(&image)?;
let kind_json = serde_json::to_value(ServiceItemKind::Image)?; let kind_json = serde_json::to_value(ServiceItemKind::Image)?;
let json = let json = serde_json::json!({"item": image_json, "kind": kind_json});
serde_json::json!({"item": image_json, "kind": kind_json});
Ok(json) Ok(json)
} }
async fn process_video( async fn process_video(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Value> {
let video = get_video_from_db(database_id, db).await?; let video = get_video_from_db(database_id, db).await?;
let video_json = serde_json::to_value(&video)?; let video_json = serde_json::to_value(&video)?;
let kind_json = serde_json::to_value(ServiceItemKind::Video)?; let kind_json = serde_json::to_value(ServiceItemKind::Video)?;
let json = let json = serde_json::json!({"item": video_json, "kind": kind_json});
serde_json::json!({"item": video_json, "kind": kind_json});
Ok(json) Ok(json)
} }
async fn process_presentation( async fn process_presentation(database_id: i32, db: &mut SqliteConnection) -> Result<Value> {
database_id: i32, let presentation = get_presentation_from_db(database_id, db).await?;
db: &mut SqliteConnection,
) -> Result<Value> {
let presentation =
get_presentation_from_db(database_id, db).await?;
let presentation_json = serde_json::to_value(&presentation)?; let presentation_json = serde_json::to_value(&presentation)?;
let kind_json = match presentation.kind { let kind_json = match presentation.kind {
PresKind::Html => serde_json::to_value( PresKind::Html => serde_json::to_value(ServiceItemKind::Presentation(PresKind::Html))?,
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::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}); let json = serde_json::json!({"item": presentation_json, "kind": kind_json});
Ok(json) Ok(json)
@ -236,11 +155,11 @@ async fn process_presentation(
mod test { mod test {
use std::path::PathBuf; use std::path::PathBuf;
use super::*;
use fs::canonicalize; use fs::canonicalize;
use pretty_assertions::assert_eq;
use sqlx::Connection; use sqlx::Connection;
use pretty_assertions::{assert_eq, assert_ne};
use tracing::debug; use tracing::debug;
use super::*;
async fn get_db() -> SqliteConnection { async fn get_db() -> SqliteConnection {
let mut data = dirs::data_local_dir().unwrap(); let mut data = dirs::data_local_dir().unwrap();
@ -248,7 +167,9 @@ mod test {
data.push("library-db.sqlite3"); data.push("library-db.sqlite3");
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); 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")] #[tokio::test(flavor = "current_thread")]
@ -318,8 +239,7 @@ mod test {
async fn test_process_presentation() { async fn test_process_presentation() {
let mut db = get_db().await; let mut db = get_db().await;
let result = process_presentation(54, &mut db).await; let result = process_presentation(54, &mut db).await;
let json_presentation_file = let json_presentation_file = PathBuf::from("./test/test_presentation.json");
PathBuf::from("./test/test_presentation.json");
if let Ok(path) = canonicalize(json_presentation_file) { if let Ok(path) = canonicalize(json_presentation_file) {
debug!(file = ?&path); debug!(file = ?&path);
if let Ok(s) = fs::read_to_string(path) { if let Ok(s) = fs::read_to_string(path) {
@ -332,9 +252,7 @@ mod test {
panic!("String wasn't read from file"); panic!("String wasn't read from file");
} }
} else { } else {
panic!( panic!("Cannot find absolute path to test_presentation.json");
"Cannot find absolute path to test_presentation.json"
);
} }
} }
@ -363,8 +281,7 @@ mod test {
async fn test_service_items() { async fn test_service_items() {
let mut db = get_db().await; let mut db = get_db().await;
let items = get_items(); let items = get_items();
let json_item_file = let json_item_file = PathBuf::from("./test/test_service_items.json");
PathBuf::from("./test/test_service_items.json");
let result = process_service_items(&items, &mut db).await; let result = process_service_items(&items, &mut db).await;
if let Ok(path) = canonicalize(json_item_file) { if let Ok(path) = canonicalize(json_item_file) {
if let Ok(s) = fs::read_to_string(path) { if let Ok(s) = fs::read_to_string(path) {
@ -388,23 +305,16 @@ mod test {
#[tokio::test] #[tokio::test]
async fn test_store() { async fn test_store() {
let path = PathBuf::from( let path = PathBuf::from("/home/chris/dev/lumina/src/rust/core/test.pres");
"/home/chris/dev/lumina/src/rust/core/test.pres",
);
let save_file = match File::create(path) { let save_file = match File::create(path) {
Ok(f) => f, Ok(f) => f,
Err(e) => panic!("Couldn't create save_file: {e}"), Err(e) => panic!("Couldn't create save_file: {e}"),
}; };
let mut db = get_db().await; let mut db = get_db().await;
let list = get_items(); 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); println!("{:?}", json);
match store_service_items( match store_service_items(&list, &mut db, &save_file, &json).await {
&list, &mut db, &save_file, &json,
)
.await
{
Ok(_) => assert!(true), Ok(_) => assert!(true),
Err(e) => panic!("There was an error: {e}"), Err(e) => panic!("There was an error: {e}"),
} }

View file

@ -5,9 +5,7 @@ use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::error; use tracing::error;
#[derive( #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Image { pub struct Image {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -18,7 +16,7 @@ impl Model<Image> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
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; 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;
match result { match result {
Ok(v) => { Ok(v) => {
for image in v.into_iter() { for image in v.into_iter() {
@ -31,11 +29,9 @@ impl Model<Image> {
} }
} }
pub async fn get_image_from_db(
database_id: i32, pub async fn get_image_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Image> {
db: &mut SqliteConnection, 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?)
) -> 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)] #[cfg(test)]
@ -71,10 +67,7 @@ mod test {
let new_image = test_image("A newer image".into()); let new_image = test_image("A newer image".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!( assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap());
&image,
image_model.find(|i| i.id == 0).unwrap()
);
assert_ne!( assert_ne!(
&new_image, &new_image,
image_model.find(|i| i.id == 0).unwrap() image_model.find(|i| i.id == 0).unwrap()

View file

@ -4,9 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::presentations::PresKind; use crate::presentations::PresKind;
#[derive( #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum ServiceItemKind { pub enum ServiceItemKind {
#[default] #[default]
Song, Song,

View file

@ -1,4 +1,3 @@
pub mod file;
pub mod images; pub mod images;
pub mod kinds; pub mod kinds;
pub mod model; pub mod model;
@ -7,3 +6,4 @@ pub mod service_items;
pub mod slides; pub mod slides;
pub mod songs; pub mod songs;
pub mod videos; pub mod videos;
pub mod file;

View file

@ -1 +0,0 @@
mod service_items;

View file

@ -36,7 +36,8 @@ impl<T> Model<T> {
Ok(()) 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) self.items.get(index as usize)
} }
@ -59,8 +60,10 @@ impl<T> Default for Model<T> {
items: vec![], items: vec![],
db: { db: {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { get_db().await }) rt.block_on(async {
}, get_db().await
})
}
} }
} }
} }
@ -71,7 +74,9 @@ pub async fn get_db() -> SqliteConnection {
data.push("library-db.sqlite3"); data.push("library-db.sqlite3");
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); 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 { pub trait Modeling {

View file

@ -1,16 +1,12 @@
use std::path::PathBuf;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{ use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection};
prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection,
};
use std::path::PathBuf;
use tracing::error; use tracing::error;
use crate::model::Model; use crate::model::Model;
#[derive( #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum PresKind { pub enum PresKind {
Html, Html,
#[default] #[default]
@ -18,9 +14,7 @@ pub enum PresKind {
Generic, Generic,
} }
#[derive( #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Presentation { pub struct Presentation {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -63,7 +57,7 @@ impl Model<Presentation> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!(r#"SELECT id as "id: i32", title, file_path as "path", html from presentations"#).fetch_all(&mut self.db).await; let result = query!(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations"#).fetch_all(&mut self.db).await;
match result { match result {
Ok(v) => { Ok(v) => {
for presentation in v.into_iter() { for presentation in v.into_iter() {
@ -85,11 +79,8 @@ impl Model<Presentation> {
} }
} }
pub async fn get_presentation_from_db( pub async fn get_presentation_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Presentation> {
database_id: i32, 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?;
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)?) Ok(Presentation::from_row(&row)?)
} }
@ -120,9 +111,7 @@ mod test {
let mut presentation_model: Model<Presentation> = let mut presentation_model: Model<Presentation> =
Model::default(); Model::default();
presentation_model.load_from_db(); presentation_model.load_from_db();
if let Some(presentation) = if let Some(presentation) = presentation_model.find(|p| p.id == 54) {
presentation_model.find(|p| p.id == 54)
{
let test_presentation = test_presentation(); let test_presentation = test_presentation();
assert_eq!(&test_presentation, presentation); assert_eq!(&test_presentation, presentation);
} else { } else {

View file

@ -15,7 +15,7 @@ pub struct ServiceItem {
} }
#[derive(Debug, Default, PartialEq)] #[derive(Debug, Default, PartialEq)]
pub struct ServiceItemModel { struct ServiceItemModel {
items: Vec<ServiceItem>, items: Vec<ServiceItem>,
} }
@ -52,9 +52,7 @@ impl From<&Image> for ServiceItem {
impl From<&Presentation> for ServiceItem { impl From<&Presentation> for ServiceItem {
fn from(presentation: &Presentation) -> Self { fn from(presentation: &Presentation) -> Self {
Self { Self {
kind: ServiceItemKind::Presentation( kind: ServiceItemKind::Presentation(presentation.kind.clone()),
presentation.kind.clone(),
),
database_id: presentation.id, database_id: presentation.id,
..Default::default() ..Default::default()
} }
@ -62,10 +60,7 @@ impl From<&Presentation> for ServiceItem {
} }
impl ServiceItemModel { impl ServiceItemModel {
fn add_item( fn add_item(&mut self, item: impl Into<ServiceItem>) -> Result<()> {
&mut self,
item: impl Into<ServiceItem>,
) -> Result<()> {
let service_item: ServiceItem = item.into(); let service_item: ServiceItem = item.into();
self.items.push(service_item); self.items.push(service_item);
Ok(()) Ok(())
@ -99,6 +94,7 @@ mod test {
} }
} }
#[test] #[test]
pub fn test_service_item() { pub fn test_service_item() {
let song = test_song(); let song = test_song();
@ -108,16 +104,10 @@ mod test {
let mut service_model = ServiceItemModel::default(); let mut service_model = ServiceItemModel::default();
match service_model.add_item(&song) { match service_model.add_item(&song) {
Ok(_) => { Ok(_) => {
assert_eq!( assert_eq!(ServiceItemKind::Song, service_model.items[0].kind);
ServiceItemKind::Song, assert_eq!(ServiceItemKind::Presentation(PresKind::Html), pres_item.kind);
service_model.items[0].kind
);
assert_eq!(
ServiceItemKind::Presentation(PresKind::Html),
pres_item.kind
);
assert_eq!(service_item, service_model.items[0]); assert_eq!(service_item, service_model.items[0]);
} },
Err(e) => panic!("Problem adding item: {:?}", e), Err(e) => panic!("Problem adding item: {:?}", e),
} }
} }

View file

@ -1,8 +1,4 @@
use std::{ use std::{error::Error, fmt::Display, path::{Path, PathBuf}};
error::Error,
fmt::Display,
path::{Path, PathBuf},
};
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -14,9 +10,7 @@ use crate::{
presentations::Presentation, songs::Song, videos::Video, presentations::Presentation, songs::Song, videos::Video,
}; };
#[derive( #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum TextAlignment { pub enum TextAlignment {
TopLeft, TopLeft,
TopCenter, TopCenter,
@ -30,9 +24,7 @@ pub enum TextAlignment {
BottomRight, BottomRight,
} }
#[derive( #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Background { pub struct Background {
pub path: PathBuf, pub path: PathBuf,
pub kind: BackgroundKind, pub kind: BackgroundKind,
@ -44,7 +36,7 @@ impl TryFrom<String> for Background {
let value = value.trim_start_matches("file://"); let value = value.trim_start_matches("file://");
let path = PathBuf::from(value); let path = PathBuf::from(value);
if !path.exists() { if !path.exists() {
return Err(ParseError::DoesNotExist); return Err(ParseError::DoesNotExist)
} }
let extension = value.rsplit_once('.').unwrap_or_default(); let extension = value.rsplit_once('.').unwrap_or_default();
match extension.1 { match extension.1 {
@ -114,15 +106,11 @@ impl DatabaseError for ParseError {
todo!() todo!()
} }
fn as_error_mut( fn as_error_mut(&mut self) -> &mut (dyn Error + Send + Sync + 'static) {
&mut self,
) -> &mut (dyn Error + Send + Sync + 'static) {
todo!() todo!()
} }
fn into_error( fn into_error(self: Box<Self>) -> Box<dyn Error + Send + Sync + 'static> {
self: Box<Self>,
) -> Box<dyn Error + Send + Sync + 'static> {
todo!() todo!()
} }
@ -140,15 +128,15 @@ impl Display for ParseError {
Self::NonBackgroundFile => { Self::NonBackgroundFile => {
"The file is not a recognized image or video type" "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}") write!(f, "Error: {message}")
} }
} }
#[derive( #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum BackgroundKind { pub enum BackgroundKind {
#[default] #[default]
Image, Image,

View file

@ -2,10 +2,7 @@ use std::{collections::HashMap, path::PathBuf};
use color_eyre::eyre::{eyre, Context, Result}; use color_eyre::eyre::{eyre, Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{ use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection};
query, query_as, sqlite::SqliteRow, FromRow, Row,
SqliteConnection,
};
use tracing::{debug, error}; use tracing::{debug, error};
use crate::{ use crate::{
@ -13,9 +10,7 @@ use crate::{
slides::{Background, TextAlignment}, slides::{Background, TextAlignment},
}; };
#[derive( #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Song { pub struct Song {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -61,24 +56,17 @@ impl FromRow<'_, SqliteRow> for Song {
text_alignment: Some({ text_alignment: Some({
let horizontal_alignment: String = row.try_get(3)?; let horizontal_alignment: String = row.try_get(3)?;
let vertical_alignment: String = row.try_get(4)?; let vertical_alignment: String = row.try_get(4)?;
match ( match (horizontal_alignment.to_lowercase().as_str(), vertical_alignment.to_lowercase().as_str()) {
horizontal_alignment.to_lowercase().as_str(),
vertical_alignment.to_lowercase().as_str(),
) {
("left", "top") => TextAlignment::TopLeft, ("left", "top") => TextAlignment::TopLeft,
("left", "center") => TextAlignment::MiddleLeft, ("left", "center") => TextAlignment::MiddleLeft,
("left", "bottom") => TextAlignment::BottomLeft, ("left", "bottom") => TextAlignment::BottomLeft,
("center", "top") => TextAlignment::TopCenter, ("center", "top") => TextAlignment::TopCenter,
("center", "center") => { ("center", "center") => TextAlignment::MiddleCenter,
TextAlignment::MiddleCenter ("center", "bottom") => TextAlignment::BottomCenter,
}
("center", "bottom") => {
TextAlignment::BottomCenter
}
("right", "top") => TextAlignment::TopRight, ("right", "top") => TextAlignment::TopRight,
("right", "center") => TextAlignment::MiddleRight, ("right", "center") => TextAlignment::MiddleRight,
("right", "bottom") => TextAlignment::BottomRight, ("right", "bottom") => TextAlignment::BottomRight,
_ => TextAlignment::MiddleCenter, _ => TextAlignment::MiddleCenter
} }
}), }),
font: row.try_get(6)?, font: row.try_get(6)?,
@ -87,20 +75,19 @@ impl FromRow<'_, SqliteRow> for Song {
} }
} }
pub async fn get_song_from_db(
index: i32, pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result<Song> {
db: &mut SqliteConnection, 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?;
) -> 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)?) Ok(Song::from_row(&row)?)
} }
impl Model<Song> { impl Model<Song> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
// static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3"; // static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
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; 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;
match result { match result {
Ok(s) => { Ok(s) => {
for song in s.into_iter() { for song in s.into_iter() {

View file

@ -5,9 +5,7 @@ use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::error; use tracing::error;
#[derive( #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Video { pub struct Video {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -21,7 +19,7 @@ impl Model<Video> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
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; 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;
match result { match result {
Ok(v) => { Ok(v) => {
for video in v.into_iter() { for video in v.into_iter() {
@ -34,13 +32,12 @@ impl Model<Video> {
} }
} }
pub async fn get_video_from_db(
database_id: i32, pub async fn get_video_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Video> {
db: &mut SqliteConnection, 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?)
) -> 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)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -74,10 +71,7 @@ mod test {
let new_video = test_video("A newer video".into()); let new_video = test_video("A newer video".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!( assert_eq!(&video, video_model.find(|v| v.id == 0).unwrap());
&video,
video_model.find(|v| v.id == 0).unwrap()
);
assert_ne!( assert_ne!(
&new_video, &new_video,
video_model.find(|v| v.id == 0).unwrap() video_model.find(|v| v.id == 0).unwrap()

View file

@ -10,9 +10,6 @@ mod file_helper {
// include!("cxx-qt-lib/qvariant.h"); // include!("cxx-qt-lib/qvariant.h");
// type QVariant = cxx_qt_lib::QVariant; // type QVariant = cxx_qt_lib::QVariant;
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[qml_element] #[qml_element]
@ -99,9 +96,7 @@ impl file_helper::FileHelper {
QUrl::from(string.as_str()) QUrl::from(string.as_str())
} }
} else { } else {
error!( error!("There was an error, is xdg-desktop-portals correctly setup?");
"There was an error, is xdg-desktop-portals correctly setup?"
);
QUrl::default() QUrl::default()
} }
} }
@ -150,9 +145,7 @@ impl file_helper::FileHelper {
QUrl::from(string.as_str()) QUrl::from(string.as_str())
} }
} else { } else {
error!( error!("Couldn't load file, is xdg-desktop-portals correctly setup?");
"Couldn't load file, is xdg-desktop-portals correctly setup?"
);
QUrl::default() QUrl::default()
} }
} }

View file

@ -2,7 +2,6 @@
pub mod image_model { pub mod image_model {
unsafe extern "C++" { unsafe extern "C++" {
include!(< QAbstractListModel >); include!(< QAbstractListModel >);
type QAbstractListModel;
include!("cxx-qt-lib/qhash.h"); include!("cxx-qt-lib/qhash.h");
type QHash_i32_QByteArray = type QHash_i32_QByteArray =
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>; cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
@ -32,18 +31,15 @@ pub mod image_model {
Title, Title,
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[base = QAbstractListModel] #[base = "QAbstractListModel"]
#[qml_element] #[qml_element]
#[qproperty(i32, count)] #[qproperty(i32, count)]
type ImageModel = super::ImageModelRust; type ImageModel = super::ImageModelRust;
#[inherit] #[inherit]
#[qsignal] #[qsignal]
#[cxx_name = "dataChanged"]
fn data_changed( fn data_changed(
self: Pin<&mut ImageModel>, self: Pin<&mut ImageModel>,
top_left: &QModelIndex, top_left: &QModelIndex,
@ -85,11 +81,8 @@ pub mod image_model {
impl cxx_qt::Threading for ImageModel {} impl cxx_qt::Threading for ImageModel {}
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[inherit] #[inherit]
#[cxx_name = "beginInsertRows"]
unsafe fn begin_insert_rows( unsafe fn begin_insert_rows(
self: Pin<&mut ImageModel>, self: Pin<&mut ImageModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -98,11 +91,9 @@ pub mod image_model {
); );
#[inherit] #[inherit]
#[cxx_name = "endInsertRows"]
unsafe fn end_insert_rows(self: Pin<&mut ImageModel>); unsafe fn end_insert_rows(self: Pin<&mut ImageModel>);
#[inherit] #[inherit]
#[cxx_name = "beginRemoveRows"]
unsafe fn begin_remove_rows( unsafe fn begin_remove_rows(
self: Pin<&mut ImageModel>, self: Pin<&mut ImageModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -111,7 +102,6 @@ pub mod image_model {
); );
#[inherit] #[inherit]
#[cxx_name = "beginMoveRows"]
unsafe fn begin_move_rows( unsafe fn begin_move_rows(
self: Pin<&mut ImageModel>, self: Pin<&mut ImageModel>,
source_parent: &QModelIndex, source_parent: &QModelIndex,
@ -122,23 +112,18 @@ pub mod image_model {
) -> bool; ) -> bool;
#[inherit] #[inherit]
#[cxx_name = "endMoveRows"]
unsafe fn end_move_rows(self: Pin<&mut ImageModel>); unsafe fn end_move_rows(self: Pin<&mut ImageModel>);
#[inherit] #[inherit]
#[cxx_name = "endRemoveRows"]
unsafe fn end_remove_rows(self: Pin<&mut ImageModel>); unsafe fn end_remove_rows(self: Pin<&mut ImageModel>);
#[inherit] #[inherit]
#[cxx_name = "beginResetModel"]
unsafe fn begin_reset_model(self: Pin<&mut ImageModel>); unsafe fn begin_reset_model(self: Pin<&mut ImageModel>);
#[inherit] #[inherit]
#[cxx_name = "endResetModel"]
unsafe fn end_reset_model(self: Pin<&mut ImageModel>); unsafe fn end_reset_model(self: Pin<&mut ImageModel>);
#[inherit] #[inherit]
#[cxx_name = "canFetchMore"]
fn can_fetch_more( fn can_fetch_more(
self: &ImageModel, self: &ImageModel,
parent: &QModelIndex, parent: &QModelIndex,
@ -162,12 +147,10 @@ pub mod image_model {
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "roleNames"]
fn role_names(self: &ImageModel) -> QHash_i32_QByteArray; fn role_names(self: &ImageModel) -> QHash_i32_QByteArray;
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "rowCount"]
fn row_count(self: &ImageModel, _parent: &QModelIndex) fn row_count(self: &ImageModel, _parent: &QModelIndex)
-> i32; -> i32;
} }
@ -175,7 +158,7 @@ pub mod image_model {
use cxx_qt::CxxQtType; use cxx_qt::CxxQtType;
use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant}; use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant};
use sqlx::{Connection, SqliteConnection, query, query_as}; use sqlx::{query, query_as, Connection, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
use tracing::{debug, error}; use tracing::{debug, error};
@ -198,7 +181,7 @@ pub struct ImageModelRust {
highest_id: i32, highest_id: i32,
images: Vec<Image>, images: Vec<Image>,
inner_images: Vec<Image>, inner_images: Vec<Image>,
db: SqliteConnection, db: SqliteConnection
} }
impl Default for ImageModelRust { impl Default for ImageModelRust {
@ -216,11 +199,9 @@ impl Default for ImageModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}, }
} }
} }
} }
@ -234,13 +215,11 @@ pub fn get_image(index: i32) -> color_eyre::Result<Image> {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}; };
rt.block_on(async { rt.block_on(async {
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?; 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?;
Ok(result) Ok(result)
}) })
} }
@ -257,7 +236,7 @@ impl image_model::ImageModel {
pub fn setup(mut self: Pin<&mut Self>) { pub fn setup(mut self: Pin<&mut Self>) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
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; 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;
match result { match result {
Ok(i) => i.into_iter().for_each(|i| self.as_mut().add_image(i)), 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}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -272,10 +251,7 @@ impl image_model::ImageModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = let result = query!("delete from images where id = ?", index).execute(&mut self.as_mut().rust_mut().db).await;
query!("delete from images where id = ?", index)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
unsafe { unsafe {
@ -332,7 +308,7 @@ impl image_model::ImageModel {
rt.block_on(async { rt.block_on(async {
let image_title = image_title.to_string(); let image_title = image_title.to_string();
let image_path = image_path.to_string(); let image_path = image_path.to_string();
let result = query!(r#"INSERT into images (id, title, file_path) VALUES (?, ?, ?)"#, let result = query!(r#"INSERT into images (id, title, filePath) VALUES (?, ?, ?)"#,
image_id, image_id,
image_title, image_title,
image_path) image_path)
@ -391,11 +367,7 @@ impl image_model::ImageModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let title = updated_title.to_string(); let title = updated_title.to_string();
let result = query!( let result = query!("UPDATE images SET title = ? where id = ?", title, index)
"UPDATE images SET title = ? where id = ?",
title,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -408,11 +380,9 @@ impl image_model::ImageModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
image.title = title.clone(); image.title = title.clone();
debug!( debug!(title = image.title,
title = image.title,
title = title, title = title,
"updated image title" "updated image title");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -424,7 +394,7 @@ impl image_model::ImageModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true
@ -444,11 +414,7 @@ impl image_model::ImageModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let updated_path = updated_path.to_string(); let updated_path = updated_path.to_string();
let result = query!( let result = query!("UPDATE images SET filePath = ? where id = ?", updated_path, index)
"UPDATE images SET file_path = ? where id = ?",
updated_path,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -461,11 +427,9 @@ impl image_model::ImageModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
image.path = updated_path.clone(); image.path = updated_path.clone();
debug!( debug!(title = image.title,
title = image.title,
path = updated_path, path = updated_path,
"updated image path" "updated image path");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -477,7 +441,7 @@ impl image_model::ImageModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true

View file

@ -8,9 +8,10 @@ pub mod service_item_model;
pub mod settings; pub mod settings;
pub mod slide_model; pub mod slide_model;
pub mod slide_object; pub mod slide_object;
pub mod slide_types;
pub mod songs; pub mod songs;
pub mod utils; pub mod utils;
pub mod video_model; pub mod video_model;
pub mod ytdl; pub mod ytdl;
pub mod slide_types;
// pub mod core;
// mod video_thumbnail; // mod video_thumbnail;

View file

@ -4,20 +4,8 @@ pub mod settings;
fn main() { fn main() {
let mut app = QGuiApplication::new(); let mut app = QGuiApplication::new();
let mut engine = QQmlApplicationEngine::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() { if let Some(engine) = engine.as_mut() {
engine.add_import_path(&QString::from(kde_qml_dir.as_str()));
engine.load(&QUrl::from( engine.load(&QUrl::from(
"qrc:/qt/qml/com/cochrun/xyz/qml/main.qml", "qrc:/qt/qml/com/cochrun/xyz/qml/main.qml",
)); ));

View file

@ -1,8 +1,9 @@
use core::fmt; use core::fmt;
use cxx_qt::CxxQtType; use cxx_qt::CxxQtType;
use cxx_qt_lib::{QString, QStringList}; use cxx_qt_lib::{QString, QStringList};
use obws::Client;
use obws::responses::scenes::{CurrentProgramScene, Scenes}; use obws::responses::scenes::{CurrentProgramScene, Scenes};
use obws::Client;
use std::{error::Error, pin::Pin}; use std::{error::Error, pin::Pin};
use tracing::{debug, error}; use tracing::{debug, error};
@ -21,10 +22,7 @@ impl fmt::Debug for Obs {
f.debug_struct("Client") f.debug_struct("Client")
.field("scenes", &self.scenes) .field("scenes", &self.scenes)
.field("client", &self.client.is_some()) .field("client", &self.client.is_some())
.field( .field("current_program_scene", &self.current_program_scene)
"current_program_scene",
&self.current_program_scene,
)
.finish() .finish()
} }
} }
@ -39,6 +37,8 @@ impl Clone for Obs {
} }
} }
impl Obs { impl Obs {
pub async fn new() -> Result<Self, Box<dyn Error>> { pub async fn new() -> Result<Self, Box<dyn Error>> {
let client = let client =
@ -127,8 +127,6 @@ mod obs {
type QList_QString = cxx_qt_lib::QList<QString>; type QList_QString = cxx_qt_lib::QList<QString>;
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[qml_element] #[qml_element]

View file

@ -2,7 +2,6 @@
pub mod presentation_model { pub mod presentation_model {
unsafe extern "C++" { unsafe extern "C++" {
include!(< QAbstractListModel >); include!(< QAbstractListModel >);
type QAbstractListModel;
include!("cxx-qt-lib/qhash.h"); include!("cxx-qt-lib/qhash.h");
type QHash_i32_QByteArray = type QHash_i32_QByteArray =
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>; cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
@ -34,18 +33,15 @@ pub mod presentation_model {
PageCount, PageCount,
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[base = QAbstractListModel] #[base = "QAbstractListModel"]
#[qml_element] #[qml_element]
#[qproperty(i32, count)] #[qproperty(i32, count)]
type PresentationModel = super::PresentationModelRust; type PresentationModel = super::PresentationModelRust;
#[inherit] #[inherit]
#[qsignal] #[qsignal]
#[cxx_name = "dataChanged"]
fn data_changed( fn data_changed(
self: Pin<&mut PresentationModel>, self: Pin<&mut PresentationModel>,
top_left: &QModelIndex, top_left: &QModelIndex,
@ -103,11 +99,8 @@ pub mod presentation_model {
impl cxx_qt::Threading for PresentationModel {} impl cxx_qt::Threading for PresentationModel {}
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[inherit] #[inherit]
#[cxx_name = "beginInsertRows"]
unsafe fn begin_insert_rows( unsafe fn begin_insert_rows(
self: Pin<&mut PresentationModel>, self: Pin<&mut PresentationModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -116,11 +109,9 @@ pub mod presentation_model {
); );
#[inherit] #[inherit]
#[cxx_name = "endInsertRows"]
unsafe fn end_insert_rows(self: Pin<&mut PresentationModel>); unsafe fn end_insert_rows(self: Pin<&mut PresentationModel>);
#[inherit] #[inherit]
#[cxx_name = "beginRemoveRows"]
unsafe fn begin_remove_rows( unsafe fn begin_remove_rows(
self: Pin<&mut PresentationModel>, self: Pin<&mut PresentationModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -129,7 +120,6 @@ pub mod presentation_model {
); );
#[inherit] #[inherit]
#[cxx_name = "beginMoveRows"]
unsafe fn begin_move_rows( unsafe fn begin_move_rows(
self: Pin<&mut PresentationModel>, self: Pin<&mut PresentationModel>,
source_parent: &QModelIndex, source_parent: &QModelIndex,
@ -140,25 +130,20 @@ pub mod presentation_model {
) -> bool; ) -> bool;
#[inherit] #[inherit]
#[cxx_name = "endMoveRows"]
unsafe fn end_move_rows(self: Pin<&mut PresentationModel>); unsafe fn end_move_rows(self: Pin<&mut PresentationModel>);
#[inherit] #[inherit]
#[cxx_name = "endRemoveRows"]
unsafe fn end_remove_rows(self: Pin<&mut PresentationModel>); unsafe fn end_remove_rows(self: Pin<&mut PresentationModel>);
#[inherit] #[inherit]
#[cxx_name = "beginResetModel"]
unsafe fn begin_reset_model( unsafe fn begin_reset_model(
self: Pin<&mut PresentationModel>, self: Pin<&mut PresentationModel>,
); );
#[inherit] #[inherit]
#[cxx_name = "endResetModel"]
unsafe fn end_reset_model(self: Pin<&mut PresentationModel>); unsafe fn end_reset_model(self: Pin<&mut PresentationModel>);
#[inherit] #[inherit]
#[cxx_name = "canFetchMore"]
fn can_fetch_more( fn can_fetch_more(
self: &PresentationModel, self: &PresentationModel,
parent: &QModelIndex, parent: &QModelIndex,
@ -182,14 +167,12 @@ pub mod presentation_model {
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "roleNames"]
fn role_names( fn role_names(
self: &PresentationModel, self: &PresentationModel,
) -> QHash_i32_QByteArray; ) -> QHash_i32_QByteArray;
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "rowCount"]
fn row_count( fn row_count(
self: &PresentationModel, self: &PresentationModel,
_parent: &QModelIndex, _parent: &QModelIndex,
@ -201,7 +184,7 @@ use crate::presentation_model::presentation_model::QMap_QString_QVariant;
use crate::reveal_js; use crate::reveal_js;
use cxx_qt::CxxQtType; use cxx_qt::CxxQtType;
use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant}; use cxx_qt_lib::{QModelIndex, QString, QUrl, QVariant};
use sqlx::{Connection, SqliteConnection, query, query_as}; use sqlx::{query, query_as, Connection, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
use tracing::{debug, error}; use tracing::{debug, error};
@ -225,7 +208,7 @@ pub struct PresentationModelRust {
highest_id: i32, highest_id: i32,
presentations: Vec<Presentation>, presentations: Vec<Presentation>,
inner_presentations: Vec<Presentation>, inner_presentations: Vec<Presentation>,
db: SqliteConnection, db: SqliteConnection
} }
impl Default for PresentationModelRust { impl Default for PresentationModelRust {
@ -243,18 +226,14 @@ impl Default for PresentationModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}, }
} }
} }
} }
pub fn get_presentation( pub fn get_presentation(index: i32) -> color_eyre::Result<Presentation> {
index: i32,
) -> color_eyre::Result<Presentation> {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
let mut db = { let mut db = {
let mut data = dirs::data_local_dir().unwrap(); let mut data = dirs::data_local_dir().unwrap();
@ -263,13 +242,11 @@ pub fn get_presentation(
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}; };
rt.block_on(async { rt.block_on(async {
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?; 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?;
Ok(result) Ok(result)
}) })
} }
@ -286,7 +263,7 @@ impl presentation_model::PresentationModel {
pub fn setup(mut self: Pin<&mut Self>) { pub fn setup(mut self: Pin<&mut Self>) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
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; 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;
match result { match result {
Ok(p) => p.into_iter().for_each(|p| self.as_mut().add_presentation(p)), 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}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -301,12 +278,7 @@ impl presentation_model::PresentationModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("delete from presentations where id = ?", index).execute(&mut self.as_mut().rust_mut().db).await;
"delete from presentations where id = ?",
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
unsafe { unsafe {
@ -393,7 +365,7 @@ impl presentation_model::PresentationModel {
rt.block_on(async { rt.block_on(async {
let presentation_title = presentation_title.to_string(); let presentation_title = presentation_title.to_string();
let presentation_path = presentation_path.to_string(); let presentation_path = presentation_path.to_string();
let result = query!(r#"INSERT into presentations (id, title, file_path, html, pageCount) VALUES (?, ?, ?, ?, ?)"#, let result = query!(r#"INSERT into presentations (id, title, filePath, html, pageCount) VALUES (?, ?, ?, ?, ?)"#,
presentation_id, presentation_id,
presentation_title, presentation_title,
presentation_path, presentation_path,
@ -531,11 +503,7 @@ impl presentation_model::PresentationModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let title = updated_title.to_string(); let title = updated_title.to_string();
let result = query!( let result = query!("UPDATE presentations SET title = ? where id = ?", title, index)
"UPDATE presentations SET title = ? where id = ?",
title,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -548,11 +516,9 @@ impl presentation_model::PresentationModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
presentation.title = title.clone(); presentation.title = title.clone();
debug!( debug!(title = presentation.title,
title = presentation.title,
title = title, title = title,
"updated presentation title" "updated presentation title");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -564,7 +530,7 @@ impl presentation_model::PresentationModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true
@ -583,11 +549,7 @@ impl presentation_model::PresentationModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE presentations SET pageCount = ? where id = ?", updated_page_count, index)
"UPDATE presentations SET pageCount = ? where id = ?",
updated_page_count,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -599,13 +561,10 @@ impl presentation_model::PresentationModel {
.iter_mut() .iter_mut()
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
presentation.page_count = presentation.page_count = updated_page_count.clone();
updated_page_count.clone(); debug!(title = presentation.title,
debug!(
title = presentation.title,
page_count = updated_page_count, page_count = updated_page_count,
"updated presentation page_count" "updated presentation page_count");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -617,7 +576,7 @@ impl presentation_model::PresentationModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true

View file

@ -2,7 +2,6 @@
mod service_item_model { mod service_item_model {
unsafe extern "C++" { unsafe extern "C++" {
include!(< QAbstractListModel >); include!(< QAbstractListModel >);
type QAbstractListModel;
include!("cxx-qt-lib/qhash.h"); include!("cxx-qt-lib/qhash.h");
type QHash_i32_QByteArray = type QHash_i32_QByteArray =
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>; cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
@ -44,11 +43,9 @@ mod service_item_model {
Id, Id,
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[base = QAbstractListModel] #[base = "QAbstractListModel"]
#[qml_element] #[qml_element]
#[qproperty(i32, count)] #[qproperty(i32, count)]
#[qproperty(f32, save_progress)] #[qproperty(f32, save_progress)]
@ -57,7 +54,6 @@ mod service_item_model {
#[inherit] #[inherit]
#[qsignal] #[qsignal]
#[cxx_name = "dataChanged"]
fn data_changed( fn data_changed(
self: Pin<&mut ServiceItemModel>, self: Pin<&mut ServiceItemModel>,
top_left: &QModelIndex, top_left: &QModelIndex,
@ -195,11 +191,8 @@ mod service_item_model {
impl cxx_qt::Threading for ServiceItemModel {} impl cxx_qt::Threading for ServiceItemModel {}
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[inherit] #[inherit]
#[cxx_name = "beginInsertRows"]
unsafe fn begin_insert_rows( unsafe fn begin_insert_rows(
self: Pin<&mut ServiceItemModel>, self: Pin<&mut ServiceItemModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -208,11 +201,9 @@ mod service_item_model {
); );
#[inherit] #[inherit]
#[cxx_name = "endInsertRows"]
unsafe fn end_insert_rows(self: Pin<&mut ServiceItemModel>); unsafe fn end_insert_rows(self: Pin<&mut ServiceItemModel>);
#[inherit] #[inherit]
#[cxx_name = "beginRemoveRows"]
unsafe fn begin_remove_rows( unsafe fn begin_remove_rows(
self: Pin<&mut ServiceItemModel>, self: Pin<&mut ServiceItemModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -221,7 +212,6 @@ mod service_item_model {
); );
#[inherit] #[inherit]
#[cxx_name = "beginMoveRows"]
unsafe fn begin_move_rows( unsafe fn begin_move_rows(
self: Pin<&mut ServiceItemModel>, self: Pin<&mut ServiceItemModel>,
source_parent: &QModelIndex, source_parent: &QModelIndex,
@ -232,23 +222,18 @@ mod service_item_model {
) -> bool; ) -> bool;
#[inherit] #[inherit]
#[cxx_name = "endMoveRows"]
unsafe fn end_move_rows(self: Pin<&mut ServiceItemModel>); unsafe fn end_move_rows(self: Pin<&mut ServiceItemModel>);
#[inherit] #[inherit]
#[cxx_name = "endRemoveRows"]
unsafe fn end_remove_rows(self: Pin<&mut ServiceItemModel>); unsafe fn end_remove_rows(self: Pin<&mut ServiceItemModel>);
#[inherit] #[inherit]
#[cxx_name = "beginResetModel"]
unsafe fn begin_reset_model(self: Pin<&mut ServiceItemModel>); unsafe fn begin_reset_model(self: Pin<&mut ServiceItemModel>);
#[inherit] #[inherit]
#[cxx_name = "endResetModel"]
unsafe fn end_reset_model(self: Pin<&mut ServiceItemModel>); unsafe fn end_reset_model(self: Pin<&mut ServiceItemModel>);
#[inherit] #[inherit]
#[cxx_name = "canFetchMore"]
fn can_fetch_more( fn can_fetch_more(
self: &ServiceItemModel, self: &ServiceItemModel,
parent: &QModelIndex, parent: &QModelIndex,
@ -272,14 +257,12 @@ mod service_item_model {
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "roleNames"]
fn role_names( fn role_names(
self: &ServiceItemModel, self: &ServiceItemModel,
) -> QHash_i32_QByteArray; ) -> QHash_i32_QByteArray;
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "rowCount"]
fn row_count( fn row_count(
self: &ServiceItemModel, self: &ServiceItemModel,
_parent: &QModelIndex, _parent: &QModelIndex,
@ -288,21 +271,15 @@ 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::service_item_model::service_item_model::QList_QString;
use crate::slide_types::SlideType; use crate::songs::song_model::{get_song, Song};
use crate::songs::song_model::{Song, get_song};
use crate::{image_model, presentation_model, video_model}; use crate::{image_model, presentation_model, video_model};
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{ use cxx_qt_lib::{
QByteArray, QModelIndex, QString, QStringList, QUrl, QVariant, QByteArray, QModelIndex, QString, QStringList, QUrl, QVariant,
}; };
use dirs; use dirs;
// use lumina_core::service_items::ServiceItem as SI; use serde_json::{json, Value};
use serde_json::{Value, json};
use std::iter; use std::iter;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin; use std::pin::Pin;
@ -311,6 +288,12 @@ use std::{fs, println};
use tar::{Archive, Builder}; use tar::{Archive, Builder};
use tracing::{debug, error}; use tracing::{debug, error};
use zstd::{Decoder, Encoder}; 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; use super::service_item_model::service_item_model::ServiceItemModel;
@ -394,9 +377,7 @@ impl service_item_model::ServiceItemModel {
pub fn remove_items(mut self: Pin<&mut Self>) { pub fn remove_items(mut self: Pin<&mut Self>) {
let mut indices = vec![]; let mut indices = vec![];
let mut items = self.service_items.clone(); let mut items = self.service_items.clone();
for (index, _item) in for (index, _item) in items.iter_mut().enumerate().filter(|(_y, x)| x.selected) {
items.iter_mut().enumerate().filter(|(_y, x)| x.selected)
{
let index = index as i32; let index = index as i32;
indices.push(index); indices.push(index);
} }
@ -455,10 +436,7 @@ impl service_item_model::ServiceItemModel {
self.as_mut().end_insert_rows(); self.as_mut().end_insert_rows();
} }
debug!("ADDING: {:?}", &service_item); debug!("ADDING: {:?}", &service_item);
self.as_mut().item_added( self.as_mut().item_added(&service_item.database_id.unwrap_or_default(), &QString::from(&service_item.ty.to_string()));
&service_item.database_id.unwrap_or_default(),
&QString::from(&service_item.ty.to_string()),
);
} }
pub fn insert_item( pub fn insert_item(
@ -497,11 +475,7 @@ impl service_item_model::ServiceItemModel {
self.as_mut().end_insert_rows(); self.as_mut().end_insert_rows();
} }
debug!("ADDING: {:?}", &service_item); debug!("ADDING: {:?}", &service_item);
self.as_mut().item_inserted( self.as_mut().item_inserted(&index, &service_item.database_id.unwrap_or_default(), &QString::from(&service_item.ty.to_string()));
&index,
&service_item.database_id.unwrap_or_default(),
&QString::from(&service_item.ty.to_string()),
);
} }
pub fn get_item( pub fn get_item(
@ -902,7 +876,8 @@ impl service_item_model::ServiceItemModel {
Some(name) => { Some(name) => {
println!("audio: {:?}", &name); println!("audio: {:?}", &name);
if name.to_str().unwrap() != "temp" { if name.to_str().unwrap() != "temp" {
flat_audio = name.to_str().unwrap() flat_audio =
name.to_str().unwrap()
} else { } else {
flat_audio = ""; flat_audio = "";
} }
@ -986,18 +961,12 @@ impl service_item_model::ServiceItemModel {
debug!(time = ?now.elapsed(), "file written"); debug!(time = ?now.elapsed(), "file written");
std::thread::spawn(move || { std::thread::spawn(move || {
debug!(time = ?now.elapsed(), "idk"); debug!(time = ?now.elapsed(), "idk");
let dir = fs::read_dir(&temp_dir) let dir = fs::read_dir(&temp_dir).expect("idk");
.expect("idk");
for (index, file) in dir.enumerate() { for (index, file) in dir.enumerate() {
if let Ok(file) = file { if let Ok(file) = file {
let file_name = let file_name = file.file_name();
file.file_name();
debug!(?file, ?file_name); debug!(?file, ?file_name);
let mut file = let mut file = std::fs::File::open(file.path()).expect("missing file");
std::fs::File::open(
file.path(),
)
.expect("missing file");
tar.append_file(file_name, &mut file).expect("Error in moving file to tar"); tar.append_file(file_name, &mut file).expect("Error in moving file to tar");
thread.queue(move |mut service| { thread.queue(move |mut service| {
service service
@ -1008,11 +977,10 @@ impl service_item_model::ServiceItemModel {
) )
}).expect("Problem queuing on cxx thread"); }).expect("Problem queuing on cxx thread");
} }
} }
if let Ok(encoder) = tar.into_inner() if let Ok(encoder) = tar.into_inner() {
{ if let Ok(done) = encoder.finish() {
if let Ok(done) = encoder.finish()
{
debug!(time = ?now.elapsed(), ?done, "tar finished"); debug!(time = ?now.elapsed(), ?done, "tar finished");
thread.queue(move |mut service| { thread.queue(move |mut service| {
service.as_mut().set_save_progress(100.0); service.as_mut().set_save_progress(100.0);
@ -1032,7 +1000,9 @@ impl service_item_model::ServiceItemModel {
} }
} else { } else {
fs::remove_dir_all(&temp_dir) fs::remove_dir_all(&temp_dir)
.expect("error in removal"); .expect(
"error in removal",
);
false false
} }
}); });
@ -1088,9 +1058,7 @@ impl service_item_model::ServiceItemModel {
if !file_path.exists() { if !file_path.exists() {
match file.unpack_in(&datadir) { match file.unpack_in(&datadir) {
Ok(_t) => (), Ok(_t) => (),
Err(e) => { Err(e) => error!("Error unpacking archive: {}", e),
error!("Error unpacking archive: {}", e)
}
} }
} }
} }
@ -1312,9 +1280,7 @@ impl service_item_model::ServiceItemModel {
..Default::default() ..Default::default()
}; };
self.as_mut().add_service_item(&service_item); self.as_mut().add_service_item(&service_item);
error!( error!("Loaded service item with generic type since it was an unknown type.");
"Loaded service item with generic type since it was an unknown type."
);
// // files implement the Read trait // // files implement the Read trait
} }
} }
@ -1375,9 +1341,7 @@ impl service_item_model::ServiceItemModel {
let mut vector_roles = QVector_i32::default(); let mut vector_roles = QVector_i32::default();
vector_roles.append(self.as_ref().get_role(role)); vector_roles.append(self.as_ref().get_role(role));
if let Some(index) = if let Some(index) =
self.as_ref().service_items.iter().position(|x| { self.as_ref().service_items.iter().position(|x| x.database_id.unwrap_or_default() == item_id)
x.database_id.unwrap_or_default() == item_id
})
{ {
let model_index = self.as_ref().index( let model_index = self.as_ref().index(
index as i32, index as i32,
@ -1391,6 +1355,7 @@ impl service_item_model::ServiceItemModel {
} }
} }
pub fn load_last_saved(self: Pin<&mut Self>) -> bool { pub fn load_last_saved(self: Pin<&mut Self>) -> bool {
todo!(); todo!();
// Don't actually need // Don't actually need
@ -1429,9 +1394,9 @@ impl service_item_model::ServiceItemModel {
ServiceRoles::Name => { ServiceRoles::Name => {
QVariant::from(&service_item.name) QVariant::from(&service_item.name)
} }
ServiceRoles::Type => QVariant::from(&QString::from( ServiceRoles::Type => {
&service_item.ty.clone().to_string(), QVariant::from(&QString::from(&service_item.ty.clone().to_string()))
)), }
ServiceRoles::Audio => { ServiceRoles::Audio => {
QVariant::from(&service_item.audio) QVariant::from(&service_item.audio)
} }
@ -1468,9 +1433,9 @@ impl service_item_model::ServiceItemModel {
ServiceRoles::VideoEndTime => { ServiceRoles::VideoEndTime => {
QVariant::from(&service_item.video_end_time) QVariant::from(&service_item.video_end_time)
} }
ServiceRoles::Id => QVariant::from( ServiceRoles::Id => {
&service_item.database_id.unwrap_or_default(), QVariant::from(&service_item.database_id.unwrap_or_default())
), }
_ => QVariant::default(), _ => QVariant::default(),
}; };
} }
@ -1538,21 +1503,22 @@ impl service_item_model::ServiceItemModel {
ServiceRoles::VideoEndTime.repr, ServiceRoles::VideoEndTime.repr,
QByteArray::from("videoEndTime"), QByteArray::from("videoEndTime"),
); );
roles.insert(ServiceRoles::Id.repr, QByteArray::from("id")); roles.insert(
ServiceRoles::Id.repr,
QByteArray::from("id"),
);
roles roles
} }
pub fn row_count(&self, _parent: &QModelIndex) -> i32 { pub fn row_count(&self, _parent: &QModelIndex) -> i32 {
// println!("row count is {cnt}"); // println!("row count is {cnt}");
self.service_items.len() as i32 self.service_items.len() as i32
} }
} }
impl ServiceItemModelRust { impl ServiceItemModelRust {
pub fn save( pub fn save(_model: Pin<&mut ServiceItemModel>, _file: QUrl) -> bool {
_model: Pin<&mut ServiceItemModel>,
_file: QUrl,
) -> bool {
todo!() todo!()
} }
} }

View file

@ -7,8 +7,6 @@ mod settings {
type QUrl = cxx_qt_lib::QUrl; type QUrl = cxx_qt_lib::QUrl;
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[qml_element] #[qml_element]

View file

@ -2,7 +2,6 @@
pub mod slide_model { pub mod slide_model {
unsafe extern "C++" { unsafe extern "C++" {
include!(< QAbstractListModel >); include!(< QAbstractListModel >);
type QAbstractListModel;
include!("cxx-qt-lib/qhash.h"); include!("cxx-qt-lib/qhash.h");
type QHash_i32_QByteArray = type QHash_i32_QByteArray =
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>; cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
@ -19,23 +18,18 @@ pub mod slide_model {
type QVector_i32 = cxx_qt_lib::QVector<i32>; type QVector_i32 = cxx_qt_lib::QVector<i32>;
include!("cxx-qt-lib/qlist.h"); include!("cxx-qt-lib/qlist.h");
type QList_QString = cxx_qt_lib::QList<QString>; type QList_QString = cxx_qt_lib::QList<QString>;
include!("liblumina/src/rust/slide_object.cxxqt.h"); include!("cxx-qt-gen/slide_object.cxxqt.h");
type SlideObject = crate::slide_object::qobject::SlideObject; type SlideObject = crate::slide_object::slide_object::SlideObject;
include!("liblumina/src/rust/songs/song_model.cxxqt.h"); include!("cxx-qt-gen/song_model.cxxqt.h");
type SongModel = type SongModel = crate::songs::song_model::song_model::SongModel;
crate::songs::song_model::song_model::SongModel; include!("cxx-qt-gen/video_model.cxxqt.h");
include!("liblumina/src/rust/video_model.cxxqt.h");
type VideoModel = crate::video_model::video_model::VideoModel; type VideoModel = crate::video_model::video_model::VideoModel;
include!("liblumina/src/rust/image_model.cxxqt.h"); include!("cxx-qt-gen/image_model.cxxqt.h");
type ImageModel = crate::image_model::image_model::ImageModel; type ImageModel = crate::image_model::image_model::ImageModel;
include!("liblumina/src/rust/presentation_model.cxxqt.h"); include!("cxx-qt-gen/presentation_model.cxxqt.h");
type PresentationModel = crate::presentation_model::presentation_model::PresentationModel; type PresentationModel = crate::presentation_model::presentation_model::PresentationModel;
} }
// extern "C++" {
// type SlideObject = crate::slide_object::qobject::SlideObject;
// }
#[qenum(SlideModel)] #[qenum(SlideModel)]
enum SlideRoles { enum SlideRoles {
Ty, Ty,
@ -60,11 +54,9 @@ pub mod slide_model {
ObsScene, ObsScene,
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[base = QAbstractListModel] #[base = "QAbstractListModel"]
#[qml_element] #[qml_element]
#[qproperty(i32, count)] #[qproperty(i32, count)]
#[qproperty(*mut SlideObject, slide_object)] #[qproperty(*mut SlideObject, slide_object)]
@ -76,7 +68,6 @@ pub mod slide_model {
#[inherit] #[inherit]
#[qsignal] #[qsignal]
#[cxx_name = "dataChanged"]
fn data_changed( fn data_changed(
self: Pin<&mut SlideModel>, self: Pin<&mut SlideModel>,
top_left: &QModelIndex, top_left: &QModelIndex,
@ -160,11 +151,8 @@ pub mod slide_model {
impl cxx_qt::Threading for SlideModel {} impl cxx_qt::Threading for SlideModel {}
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[inherit] #[inherit]
#[cxx_name = "beginInsertRows"]
unsafe fn begin_insert_rows( unsafe fn begin_insert_rows(
self: Pin<&mut SlideModel>, self: Pin<&mut SlideModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -173,11 +161,9 @@ pub mod slide_model {
); );
#[inherit] #[inherit]
#[cxx_name = "endInsertRows"]
unsafe fn end_insert_rows(self: Pin<&mut SlideModel>); unsafe fn end_insert_rows(self: Pin<&mut SlideModel>);
#[inherit] #[inherit]
#[cxx_name = "beginRemoveRows"]
unsafe fn begin_remove_rows( unsafe fn begin_remove_rows(
self: Pin<&mut SlideModel>, self: Pin<&mut SlideModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -186,19 +172,15 @@ pub mod slide_model {
); );
#[inherit] #[inherit]
#[cxx_name = "endRemoveRows"]
unsafe fn end_remove_rows(self: Pin<&mut SlideModel>); unsafe fn end_remove_rows(self: Pin<&mut SlideModel>);
#[inherit] #[inherit]
#[cxx_name = "beginResetModel"]
unsafe fn begin_reset_model(self: Pin<&mut SlideModel>); unsafe fn begin_reset_model(self: Pin<&mut SlideModel>);
#[inherit] #[inherit]
#[cxx_name = "endResetModel"]
unsafe fn end_reset_model(self: Pin<&mut SlideModel>); unsafe fn end_reset_model(self: Pin<&mut SlideModel>);
#[inherit] #[inherit]
#[cxx_name = "beginMoveRows"]
unsafe fn begin_move_rows( unsafe fn begin_move_rows(
self: Pin<&mut SlideModel>, self: Pin<&mut SlideModel>,
source_parent: &QModelIndex, source_parent: &QModelIndex,
@ -209,11 +191,9 @@ pub mod slide_model {
) -> bool; ) -> bool;
#[inherit] #[inherit]
#[cxx_name = "endMoveRows"]
unsafe fn end_move_rows(self: Pin<&mut SlideModel>); unsafe fn end_move_rows(self: Pin<&mut SlideModel>);
#[inherit] #[inherit]
#[cxx_name = "canFetchMore"]
fn can_fetch_more( fn can_fetch_more(
self: &SlideModel, self: &SlideModel,
parent: &QModelIndex, parent: &QModelIndex,
@ -237,12 +217,10 @@ pub mod slide_model {
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "roleNames"]
fn role_names(self: &SlideModel) -> QHash_i32_QByteArray; fn role_names(self: &SlideModel) -> QHash_i32_QByteArray;
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "rowCount"]
fn row_count(self: &SlideModel, _parent: &QModelIndex) fn row_count(self: &SlideModel, _parent: &QModelIndex)
-> i32; -> i32;
@ -251,29 +229,26 @@ pub mod slide_model {
use crate::image_model::image_model::ImageModel; use crate::image_model::image_model::ImageModel;
use crate::image_model::{self, Image, ImageModelRust}; use crate::image_model::{self, Image, ImageModelRust};
use crate::obs::Obs;
use crate::presentation_model::presentation_model::PresentationModel; use crate::presentation_model::presentation_model::PresentationModel;
use crate::presentation_model::{ use crate::presentation_model::{self, Presentation, PresentationModelRust};
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::song_model::{self, SongModel};
use crate::songs::song_model::{Song, SongModelRust, get_song}; use crate::songs::song_model::{get_song, Song, SongModelRust};
use crate::video_model::video_model::VideoModel; use crate::video_model::video_model::VideoModel;
use crate::video_model::{self, Video, VideoModelRust}; use crate::video_model::{self, Video, VideoModelRust};
use crate::{ffmpeg, slide_types::SlideType}; use crate::{ffmpeg, slide_types::SlideType};
use color_eyre::Section; use crate::obs::Obs;
use crate::slide_model::slide_model::QList_QString;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use color_eyre::Section;
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{ use cxx_qt_lib::{
CaseSensitivity, QByteArray, QList, QModelIndex, QString, CaseSensitivity, QByteArray, QList, QModelIndex, QString, QStringList, QVariant
QStringList, QVariant,
}; };
use slide_model::SlideObject; use slide_model::SlideObject;
use std::error::Error; use std::error::Error;
use std::fmt::Display; use std::fmt::{Display};
use std::{path::PathBuf, pin::Pin}; use std::{path::PathBuf, pin::Pin};
use tracing::{debug, error, warn}; use tracing::{debug, error};
use self::slide_model::{ use self::slide_model::{
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32, QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
@ -344,9 +319,7 @@ impl Display for ParseSlideError {
f: &mut std::fmt::Formatter<'_>, f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result { ) -> std::fmt::Result {
let message = match self { let message = match self {
Self::UnknownType => { Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'",
"The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'"
}
}; };
write!(f, "Error: {message}") write!(f, "Error: {message}")
} }
@ -363,40 +336,45 @@ impl Slide {
fn slides_from_song(song: Song) -> Result<Vec<Self>> { fn slides_from_song(song: Song) -> Result<Vec<Self>> {
let list = song.get_lyric_list(); let list = song.get_lyric_list();
let total = list.len(); let total = list.len();
let vector = list let mut vector: Vec<Slide> = vec![];
.iter() list.iter().map(|t| t.to_string()).enumerate()
.map(|t| { .for_each(|(i, s)| {
let s = t.to_string(); if song.background_type == "image" {
warn!(s); vector.push(
s Self {
})
.enumerate()
.map(|(i, s)| Self {
text: s, text: s,
ty: SlideType::Song, ty: SlideType::Song,
audio: song.audio.clone(), audio: song.audio.clone(),
image_background: if song.background_type == "image" { image_background: song.background.clone(),
song.background.clone() video_background: "".to_owned(),
} else { htext_alignment: song.horizontal_text_alignment.clone(),
"".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(), vtext_alignment: song.vertical_text_alignment.clone(),
font: song.font.clone(), font: song.font.clone(),
font_size: song.font_size, font_size: song.font_size,
slide_count: total as i32, slide_count: total as i32,
slide_index: i as i32, slide_index: i as i32,
..Default::default() ..Default::default()
}) }
.collect(); );
warn!(?vector); } 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()
}
)
}
});
Ok(vector) Ok(vector)
} }
@ -417,9 +395,7 @@ impl Slide {
}) })
} }
fn slides_from_presentation( fn slides_from_presentation(presentation: Presentation) -> Result<Vec<Self>> {
presentation: Presentation,
) -> Result<Vec<Self>> {
let total = presentation.page_count; let total = presentation.page_count;
let mut slides: Vec<Slide> = vec![]; let mut slides: Vec<Slide> = vec![];
for i in 0..total { for i in 0..total {
@ -430,7 +406,7 @@ impl Slide {
image_background: presentation.path.clone(), image_background: presentation.path.clone(),
..Default::default() ..Default::default()
}) })
} };
Ok(slides) Ok(slides)
} }
} }
@ -480,12 +456,9 @@ impl slide_model::SlideModel {
index: i32, index: i32,
) -> bool { ) -> bool {
let mut vector_roles = QVector_i32::default(); let mut vector_roles = QVector_i32::default();
vector_roles vector_roles.append(self.get_role(SlideRoles::VideoThumbnail));
.append(self.get_role(SlideRoles::VideoThumbnail)); vector_roles.append(self.get_role(SlideRoles::VideoBackground));
vector_roles vector_roles.append(self.get_role(SlideRoles::ImageBackground));
.append(self.get_role(SlideRoles::VideoBackground));
vector_roles
.append(self.get_role(SlideRoles::ImageBackground));
let rc = self.as_ref().count() - 1; let rc = self.as_ref().count() - 1;
let tl = self.as_ref().index(0, 0, &QModelIndex::default()); let tl = self.as_ref().index(0, 0, &QModelIndex::default());
let br = self.as_ref().index(rc, 0, &QModelIndex::default()); let br = self.as_ref().index(rc, 0, &QModelIndex::default());
@ -497,11 +470,7 @@ impl slide_model::SlideModel {
let path = let path =
PathBuf::from(slide.video_background.to_string()); PathBuf::from(slide.video_background.to_string());
let screenshot = ffmpeg::bg_path_from_video(&path); let screenshot = ffmpeg::bg_path_from_video(&path);
let mut screenshot_string = screenshot let mut screenshot_string = screenshot.clone().into_os_string().into_string().unwrap_or_default();
.clone()
.into_os_string()
.into_string()
.unwrap_or_default();
screenshot_string.insert_str(0, "file://"); screenshot_string.insert_str(0, "file://");
slide.video_thumbnail = screenshot_string; slide.video_thumbnail = screenshot_string;
std::thread::spawn(move || { std::thread::spawn(move || {
@ -647,56 +616,37 @@ impl slide_model::SlideModel {
SlideType::Song => { SlideType::Song => {
let song = get_song(item_model_id)?; let song = get_song(item_model_id)?;
let slides = Slide::slides_from_song(song)?; let slides = Slide::slides_from_song(song)?;
slides.iter().enumerate().for_each(|(i, slide)| { slides.iter().for_each(|slide| self.as_mut().insert_slide(slide, index));
self.as_mut()
.insert_slide(slide, index + i as i32)
});
Ok(()) Ok(())
} },
SlideType::Video => { SlideType::Video => {
let video = video_model::get_video(item_model_id)?; let video = video_model::get_video(item_model_id)?;
self.insert_slide( self.insert_slide(&Slide::slide_from_video(video)?, index);
&Slide::slide_from_video(video)?,
index,
);
Ok(()) Ok(())
} },
SlideType::Image => { SlideType::Image => {
let result = image_model::get_image(item_model_id); let result = image_model::get_image(item_model_id);
match result { match result {
Ok(image) => self.insert_slide( Ok(image) => self.insert_slide(&Slide::slide_from_image(image)?, index),
&Slide::slide_from_image(image)?,
index,
),
Err(e) => { Err(e) => {
e.with_note(|| { e.with_note(|| {
format!("This might fail if we are loading the items from a file") format!("This might fail if we are loading the items from a file")
}); });
let mut slide = Slide::default(); let mut slide = Slide::default();
slide.image_background = slide.image_background = "qrc:/assets/black.jpg".to_owned();
"qrc:/assets/black.jpg".to_owned();
self.insert_slide(&slide, index); self.insert_slide(&slide, index);
} },
} }
Ok(()) Ok(())
} },
SlideType::Content => { SlideType::Content => {
todo!(); todo!();
Ok(()) Ok(())
} },
SlideType::Presentation(_) => { SlideType::Presentation(_) => {
let presentation = let presentation = presentation_model::get_presentation(item_model_id)?;
presentation_model::get_presentation( let slides = Slide::slides_from_presentation(presentation)?;
item_model_id, slides.iter().for_each(|slide| self.as_mut().insert_slide(slide, slide.slide_index + index));
)?;
let slides =
Slide::slides_from_presentation(presentation)?;
slides.iter().for_each(|slide| {
self.as_mut().insert_slide(
slide,
slide.slide_index + index,
)
});
Ok(()) Ok(())
} }
} }
@ -706,7 +656,7 @@ impl slide_model::SlideModel {
self: Pin<&mut Self>, self: Pin<&mut Self>,
item_model_id: i32, item_model_id: i32,
kind: &QString, kind: &QString,
) -> Result<()> { ) -> Result<()>{
let index = self.count; let index = self.count;
self.insert_item_from_service(index, item_model_id, kind) self.insert_item_from_service(index, item_model_id, kind)
} }
@ -742,8 +692,7 @@ impl slide_model::SlideModel {
if let Some((i, slide)) = slides_iter if let Some((i, slide)) = slides_iter
.clone() .clone()
.enumerate() .enumerate().find(|slide| slide.1.service_item_id == source_index)
.find(|slide| slide.1.service_item_id == source_index)
{ {
debug!(index = i, ?slide); debug!(index = i, ?slide);
first_slide = i as i32; first_slide = i as i32;
@ -756,8 +705,11 @@ impl slide_model::SlideModel {
// lets get the dest_slide and count // lets get the dest_slide and count
if move_down { if move_down {
if let Some((i, slide)) = if let Some((i, slide)) = slides_iter
slides_iter.clone().enumerate().rev().find(|slide| { .clone()
.enumerate()
.rev()
.find(|slide| {
slide.1.service_item_id == destination_index slide.1.service_item_id == destination_index
}) })
{ {
@ -772,8 +724,9 @@ impl slide_model::SlideModel {
dest_slide, dest_count dest_slide, dest_count
); );
} }
} else if let Some((i, slide)) = } else if let Some((i, slide)) = slides_iter
slides_iter.enumerate().find(|slide| { .enumerate()
.find(|slide| {
slide.1.service_item_id == destination_index slide.1.service_item_id == destination_index
}) })
{ {
@ -820,9 +773,7 @@ impl slide_model::SlideModel {
// Change the service_item_id of the moved slide // Change the service_item_id of the moved slide
if count > 1 { if count > 1 {
if move_down { if move_down {
debug!( debug!("While moving down, change service items id of moved slide");
"While moving down, change service items id of moved slide"
);
for (i, _slide) in slides_iter for (i, _slide) in slides_iter
.clone() .clone()
.enumerate() .enumerate()
@ -840,16 +791,13 @@ impl slide_model::SlideModel {
debug!( debug!(
?slide, ?slide,
"rust: these ones right here officer. from {:?} to {:?}", "rust: these ones right here officer. from {:?} to {:?}",
slide.service_item_id, slide.service_item_id, destination_index
destination_index
); );
slide.service_item_id = destination_index; slide.service_item_id = destination_index;
} }
} }
} else { } else {
debug!( debug!("While moving up, change service items id of moved slide");
"While moving up, change service items id of moved slide"
);
for (i, _slide) in slides_iter for (i, _slide) in slides_iter
.clone() .clone()
.enumerate() .enumerate()
@ -862,8 +810,7 @@ impl slide_model::SlideModel {
debug!( debug!(
?slide, ?slide,
"rust: these ones right here officer. from {:?} to {:?}", "rust: these ones right here officer. from {:?} to {:?}",
slide.service_item_id, slide.service_item_id, destination_index
destination_index
); );
slide.service_item_id = destination_index; slide.service_item_id = destination_index;
} }
@ -935,9 +882,7 @@ impl slide_model::SlideModel {
// self.as_mut().end_reset_model(); // self.as_mut().end_reset_model();
// } // }
debug!( debug!("rust-move: {first_slide} to {dest_slide} with {count} slides");
"rust-move: {first_slide} to {dest_slide} with {count} slides"
);
} }
fn move_items( fn move_items(
@ -1056,8 +1001,7 @@ impl slide_model::SlideModel {
debug!(service_item = index, "Getting slide from this item"); debug!(service_item = index, "Getting slide from this item");
let mut id = 0; let mut id = 0;
if let Some((i, slide)) = slides_iter if let Some((i, slide)) = slides_iter
.enumerate() .enumerate().find(|(_i, slide)| slide.service_item_id == index)
.find(|(_i, slide)| slide.service_item_id == index)
{ {
debug!(slide_id = i, ?slide); debug!(slide_id = i, ?slide);
id = i as i32; id = i as i32;
@ -1161,6 +1105,7 @@ impl slide_model::SlideModel {
(0, QModelIndex::default(), vector_roles) (0, QModelIndex::default(), vector_roles)
} }
} }
} }
// QAbstractListModel implementation // QAbstractListModel implementation
@ -1169,30 +1114,22 @@ impl slide_model::SlideModel {
let role = SlideRoles { repr: role }; let role = SlideRoles { repr: role };
if let Some(slide) = self.slides.get(index.row() as usize) { if let Some(slide) = self.slides.get(index.row() as usize) {
return match role { return match role {
SlideRoles::Ty => QVariant::from(&QString::from( SlideRoles::Ty => QVariant::from(&QString::from(&slide.ty.to_string())),
&slide.ty.to_string(), SlideRoles::Text => QVariant::from(&QString::from(&slide.text)),
)), SlideRoles::Audio => QVariant::from(&QString::from(&slide.audio)),
SlideRoles::Text => { SlideRoles::ImageBackground => {
QVariant::from(&QString::from(&slide.text)) QVariant::from(&QString::from(&slide.image_background))
} }
SlideRoles::Audio => { SlideRoles::VideoBackground => {
QVariant::from(&QString::from(&slide.audio)) QVariant::from(&QString::from(&slide.video_background))
} }
SlideRoles::ImageBackground => QVariant::from( SlideRoles::HTextAlignment => {
&QString::from(&slide.image_background), QVariant::from(&QString::from(&slide.htext_alignment))
),
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 => { SlideRoles::FontSize => {
QVariant::from(&slide.font_size) QVariant::from(&slide.font_size)
} }
@ -1210,9 +1147,9 @@ impl slide_model::SlideModel {
QVariant::from(&slide.selected) QVariant::from(&slide.selected)
} }
SlideRoles::Looping => QVariant::from(&slide.looping), SlideRoles::Looping => QVariant::from(&slide.looping),
SlideRoles::VideoThumbnail => QVariant::from( SlideRoles::VideoThumbnail => {
&QString::from(&slide.video_thumbnail), QVariant::from(&QString::from(&slide.video_thumbnail))
), }
SlideRoles::VideoStartTime => { SlideRoles::VideoStartTime => {
QVariant::from(&slide.video_start_time) QVariant::from(&slide.video_start_time)
} }
@ -1319,8 +1256,7 @@ impl slide_model::SlideModel {
fn extract_string(item: &QMap_QString_QVariant, key: &str) -> String { fn extract_string(item: &QMap_QString_QVariant, key: &str) -> String {
item.get(&QString::from(key)) item.get(&QString::from(key))
.unwrap_or(QVariant::from(&QString::default())) .unwrap_or(QVariant::from(&QString::default()))
.value_or_default::<QString>() .value_or_default::<QString>().to_string()
.to_string()
} }
fn extract_value(item: &QMap_QString_QVariant, key: &str) -> i32 { fn extract_value(item: &QMap_QString_QVariant, key: &str) -> i32 {
@ -1341,11 +1277,12 @@ fn extract_bool(item: &QMap_QString_QVariant, key: &str) -> bool {
.value_or_default::<bool>() .value_or_default::<bool>()
} }
// #[cfg(test)] #[cfg(test)]
// mod test { mod test {
// #[test]
// pub fn test_obs_setting_scene() { #[test]
// assert_eq!(true, true) pub fn test_obs_setting_scene() {
// } assert_eq!(true, true)
// } }
}

View file

@ -1,5 +1,5 @@
#[cxx_qt::bridge] #[cxx_qt::bridge]
pub mod qobject { pub mod slide_object {
unsafe extern "C++" { unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h"); include!("cxx-qt-lib/qstring.h");
type QString = cxx_qt_lib::QString; type QString = cxx_qt_lib::QString;
@ -10,31 +10,7 @@ pub mod qobject {
// type SlideModel = crate::slide_model::slide_model::SlideModel; // type SlideModel = crate::slide_model::slide_model::SlideModel;
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { 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] #[qsignal]
fn playing_changed( fn playing_changed(
self: Pin<&mut SlideObject>, self: Pin<&mut SlideObject>,
@ -59,6 +35,28 @@ pub mod qobject {
#[qsignal] #[qsignal]
fn reveal_prev(self: Pin<&mut SlideObject>); 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] #[qinvokable]
fn change_slide( fn change_slide(
self: Pin<&mut SlideObject>, self: Pin<&mut SlideObject>,
@ -91,11 +89,10 @@ use cxx_qt_lib::{CaseSensitivity, QString, QVariant};
use tracing::{debug, error}; use tracing::{debug, error};
use crate::{ use crate::{
slide_model::{Slide, slide_model}, slide_model::{slide_model, Slide}, slide_types::SlideType
slide_types::SlideType,
}; };
use self::qobject::QMap_QString_QVariant; use self::slide_object::QMap_QString_QVariant;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SlideObjectRust { pub struct SlideObjectRust {
@ -144,7 +141,7 @@ impl Default for SlideObjectRust {
} }
} }
impl qobject::SlideObject { impl slide_object::SlideObject {
pub fn change_slide( pub fn change_slide(
mut self: Pin<&mut Self>, mut self: Pin<&mut Self>,
item: QMap_QString_QVariant, item: QMap_QString_QVariant,
@ -487,18 +484,10 @@ impl qobject::SlideObject {
self.as_mut().set_text(QString::from(&slide.text)); self.as_mut().set_text(QString::from(&slide.text));
self.as_mut().set_ty(QString::from(&slide.ty.to_string())); self.as_mut().set_ty(QString::from(&slide.ty.to_string()));
self.as_mut().set_audio(QString::from(&slide.audio)); self.as_mut().set_audio(QString::from(&slide.audio));
self.as_mut().set_image_background(QString::from( self.as_mut().set_image_background(QString::from(&slide.image_background));
&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_video_background(QString::from( self.as_mut().set_htext_alignment(QString::from(&slide.htext_alignment));
&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(QString::from(&slide.font));
self.as_mut().set_font_size(slide.font_size); self.as_mut().set_font_size(slide.font_size);
self.as_mut().set_video_start_time(slide.video_start_time); self.as_mut().set_video_start_time(slide.video_start_time);

View file

@ -15,13 +15,11 @@ pub mod song_editor {
include!("cxx-qt-lib/qlist.h"); include!("cxx-qt-lib/qlist.h");
type QList_QString = cxx_qt_lib::QList<QString>; type QList_QString = cxx_qt_lib::QList<QString>;
include!("liblumina/src/rust/songs/song_model.cxxqt.h"); include!("cxx-qt-gen/song_model.cxxqt.h");
type SongModel = type SongModel =
crate::songs::song_model::song_model::SongModel; crate::songs::song_model::song_model::SongModel;
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[qml_element] #[qml_element]

View file

@ -2,7 +2,6 @@
pub mod song_model { pub mod song_model {
unsafe extern "C++" { unsafe extern "C++" {
include!(< QAbstractListModel >); include!(< QAbstractListModel >);
type QAbstractListModel;
include!("cxx-qt-lib/qhash.h"); include!("cxx-qt-lib/qhash.h");
type QHash_i32_QByteArray = type QHash_i32_QByteArray =
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>; cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
@ -40,18 +39,15 @@ pub mod song_model {
FontSize, FontSize,
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[base = QAbstractListModel] #[base = "QAbstractListModel"]
#[qml_element] #[qml_element]
#[qproperty(i32, count)] #[qproperty(i32, count)]
type SongModel = super::SongModelRust; type SongModel = super::SongModelRust;
#[inherit] #[inherit]
#[qsignal] #[qsignal]
#[cxx_name = "dataChanged"]
fn data_changed( fn data_changed(
self: Pin<&mut SongModel>, self: Pin<&mut SongModel>,
top_left: &QModelIndex, top_left: &QModelIndex,
@ -170,11 +166,8 @@ pub mod song_model {
impl cxx_qt::Threading for SongModel {} impl cxx_qt::Threading for SongModel {}
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[inherit] #[inherit]
#[cxx_name = "beginInsertRows"]
unsafe fn begin_insert_rows( unsafe fn begin_insert_rows(
self: Pin<&mut SongModel>, self: Pin<&mut SongModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -183,11 +176,9 @@ pub mod song_model {
); );
#[inherit] #[inherit]
#[cxx_name = "endInsertRows"]
unsafe fn end_insert_rows(self: Pin<&mut SongModel>); unsafe fn end_insert_rows(self: Pin<&mut SongModel>);
#[inherit] #[inherit]
#[cxx_name = "beginRemoveRows"]
unsafe fn begin_remove_rows( unsafe fn begin_remove_rows(
self: Pin<&mut SongModel>, self: Pin<&mut SongModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -196,7 +187,6 @@ pub mod song_model {
); );
#[inherit] #[inherit]
#[cxx_name = "beginMoveRows"]
unsafe fn begin_move_rows( unsafe fn begin_move_rows(
self: Pin<&mut SongModel>, self: Pin<&mut SongModel>,
source_parent: &QModelIndex, source_parent: &QModelIndex,
@ -207,23 +197,18 @@ pub mod song_model {
) -> bool; ) -> bool;
#[inherit] #[inherit]
#[cxx_name = "endMoveRows"]
unsafe fn end_move_rows(self: Pin<&mut SongModel>); unsafe fn end_move_rows(self: Pin<&mut SongModel>);
#[inherit] #[inherit]
#[cxx_name = "endRemoveRows"]
unsafe fn end_remove_rows(self: Pin<&mut SongModel>); unsafe fn end_remove_rows(self: Pin<&mut SongModel>);
#[inherit] #[inherit]
#[cxx_name = "beginResetModel"]
unsafe fn begin_reset_model(self: Pin<&mut SongModel>); unsafe fn begin_reset_model(self: Pin<&mut SongModel>);
#[inherit] #[inherit]
#[cxx_name = "endResetModel"]
unsafe fn end_reset_model(self: Pin<&mut SongModel>); unsafe fn end_reset_model(self: Pin<&mut SongModel>);
#[inherit] #[inherit]
#[cxx_name = "canFetchMore"]
fn can_fetch_more( fn can_fetch_more(
self: &SongModel, self: &SongModel,
parent: &QModelIndex, parent: &QModelIndex,
@ -247,26 +232,24 @@ pub mod song_model {
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "roleNames"]
fn role_names(self: &SongModel) -> QHash_i32_QByteArray; fn role_names(self: &SongModel) -> QHash_i32_QByteArray;
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "rowCount"]
fn row_count(self: &SongModel, _parent: &QModelIndex) -> i32; fn row_count(self: &SongModel, _parent: &QModelIndex) -> i32;
} }
} }
use crate::songs::song_editor::song_editor::QList_QString; use crate::songs::song_editor::song_editor::QList_QString;
use color_eyre::Result;
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{ use cxx_qt_lib::{
QByteArray, QModelIndex, QString, QStringList, QVariant, QByteArray, QModelIndex, QString, QStringList, QVariant,
}; };
use sqlx::{Connection, SqliteConnection, query, query_as}; use sqlx::{query, query_as, Connection, SqliteConnection};
use std::collections::HashMap; use std::collections::HashMap;
use std::pin::Pin; use std::pin::Pin;
use tracing::{debug, error}; use tracing::{debug, error};
use color_eyre::Result;
use self::song_model::{ use self::song_model::{
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32, QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
@ -310,13 +293,15 @@ impl Song {
} }
let raw_lyrics = self.lyrics.clone(); let raw_lyrics = self.lyrics.clone();
println!("raw-lyrics: {:?}", raw_lyrics); println!("raw-lyrics: {:?}", raw_lyrics);
let vorder: Vec<&str> = self.verse_order.split(' ').collect(); let vorder: Vec<&str> =
self.verse_order.split(' ').collect();
let keywords = vec![ let keywords = vec![
"Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 1", "Verse 2", "Verse 3", "Verse 4",
"Verse 6", "Verse 7", "Verse 8", "Chorus 1", "Chorus 2", "Verse 5", "Verse 6", "Verse 7", "Verse 8",
"Chorus 3", "Chorus 4", "Bridge 1", "Bridge 2", "Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4",
"Bridge 3", "Bridge 4", "Intro 1", "Intro 2", "Ending 1", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4",
"Ending 2", "Other 1", "Other 2", "Other 3", "Other 4", "Intro 1", "Intro 2", "Ending 1", "Ending 2",
"Other 1", "Other 2", "Other 3", "Other 4",
]; ];
let _first_item = true; let _first_item = true;
@ -350,8 +335,10 @@ impl Song {
let mut verse_name = ""; let mut verse_name = "";
// debug!(verse = verse); // debug!(verse = verse);
for word in keywords.clone() { for word in keywords.clone() {
let end_verse = verse.get(1..2).unwrap_or_default(); let end_verse =
let beg_verse = verse.get(0..1).unwrap_or_default(); verse.get(1..2).unwrap_or_default();
let beg_verse =
verse.get(0..1).unwrap_or_default();
// println!( // println!(
// "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}", // "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}",
// verse, beg_verse, end_verse, word // verse, beg_verse, end_verse, word
@ -413,11 +400,9 @@ impl Default for SongModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}, }
} }
} }
} }
@ -431,14 +416,12 @@ pub fn get_song(id: i32) -> Result<Song> {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}; };
debug!("getting song with id: {id}"); debug!("getting song with id: {id}");
rt.block_on(async { rt.block_on(async {
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?; 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?;
debug!(?result); debug!(?result);
Ok(result) Ok(result)
}) })
@ -457,7 +440,7 @@ impl song_model::SongModel {
static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3"; static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
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; 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;
match result { match result {
Ok(s) => s.into_iter().for_each(|s| self.as_mut().add_song(s)), 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}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -470,13 +453,7 @@ impl song_model::SongModel {
return false; return false;
} }
let song_id = self let song_id = self.as_mut().rust_mut().songs.get(index as usize).unwrap().id;
.as_mut()
.rust_mut()
.songs
.get(index as usize)
.unwrap()
.id;
let thread = self.qt_thread(); let thread = self.qt_thread();
let db = &mut self.as_mut().rust_mut().db; let db = &mut self.as_mut().rust_mut().db;
@ -527,7 +504,7 @@ impl song_model::SongModel {
}; };
rt.block_on(async { rt.block_on(async {
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#, let result = query!(r#"INSERT into songs (vorder, fontSize, backgroundType, horizontalTextAlignment, verticalTextAlignment, title, font, background, lyrics, ccli, author, audio, id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#,
song.verse_order, song.verse_order,
song.font_size, song.font_size,
song.background_type, song.background_type,
@ -609,11 +586,7 @@ impl song_model::SongModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
let db_string = updated_title.clone().to_string(); let db_string = updated_title.clone().to_string();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE songs SET title = ? where id = ?", db_string, song_id)
"UPDATE songs SET title = ? where id = ?",
db_string,
song_id
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -622,10 +595,7 @@ impl song_model::SongModel {
if let Some(song) = if let Some(song) =
self.as_mut().rust_mut().songs.get_mut(index) self.as_mut().rust_mut().songs.get_mut(index)
{ {
debug!( debug!(?song, title = updated_title.to_string());
?song,
title = updated_title.to_string()
);
song.title = updated_title.to_string(); song.title = updated_title.to_string();
self.as_mut().data_changed( self.as_mut().data_changed(
&model_index, &model_index,
@ -638,11 +608,9 @@ impl song_model::SongModel {
} }
} }
Err(e) => { Err(e) => {
error!( error!("There was an error updating title in db: {e}");
"There was an error updating title in db: {e}"
);
false false
} },
} }
}); });
true true
@ -746,11 +714,7 @@ impl song_model::SongModel {
let db_string = updated_audio.clone().to_string(); let db_string = updated_audio.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE songs SET audio = ? where id = ?", db_string, song_id)
"UPDATE songs SET audio = ? where id = ?",
db_string,
song_id
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -775,11 +739,9 @@ impl song_model::SongModel {
} }
} }
Err(e) => { Err(e) => {
error!( error!("There was an error updating audio in db: {e}");
"There was an error updating audio in db: {e}"
);
false false
} },
} }
}); });
true true
@ -796,11 +758,7 @@ impl song_model::SongModel {
let db_string = updated_ccli.clone().to_string(); let db_string = updated_ccli.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE songs SET ccli = ? where id = ?", db_string, song_id)
"UPDATE songs SET ccli = ? where id = ?",
db_string,
song_id
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -825,11 +783,9 @@ impl song_model::SongModel {
} }
} }
Err(e) => { Err(e) => {
error!( error!("There was an error updating ccli in db: {e}");
"There was an error updating ccli in db: {e}"
);
false false
} },
} }
}); });
true true
@ -846,7 +802,7 @@ impl song_model::SongModel {
let db_string = updated_verse_order.clone().to_string(); let db_string = updated_verse_order.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET verse_order = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET vorder = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -935,7 +891,7 @@ impl song_model::SongModel {
let db_string = updated_background_type.clone().to_string(); let db_string = updated_background_type.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET background_type = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET backgroundType = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -977,11 +933,10 @@ impl song_model::SongModel {
.as_mut() .as_mut()
.get_indices(song_id, SongRoles::HorizontalTextAlignment); .get_indices(song_id, SongRoles::HorizontalTextAlignment);
let db_string = let db_string = updated_horizontal_text_alignment.clone().to_string();
updated_horizontal_text_alignment.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET horizontal_text_alignment = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET horizontalTextAlignment = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -1023,11 +978,10 @@ impl song_model::SongModel {
.as_mut() .as_mut()
.get_indices(song_id, SongRoles::VerticalTextAlignment); .get_indices(song_id, SongRoles::VerticalTextAlignment);
let db_string = let db_string = updated_vertical_text_alignment.clone().to_string();
updated_vertical_text_alignment.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET vertical_text_alignment = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET verticalTextAlignment = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -1071,11 +1025,7 @@ impl song_model::SongModel {
let db_string = updated_font.clone().to_string(); let db_string = updated_font.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE songs SET font = ? where id = ?", db_string, song_id)
"UPDATE songs SET font = ? where id = ?",
db_string,
song_id
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -1100,11 +1050,9 @@ impl song_model::SongModel {
} }
} }
Err(e) => { Err(e) => {
error!( error!("There was an error updating font in db: {e}");
"There was an error updating font in db: {e}"
);
false false
} },
} }
}); });
true true
@ -1121,7 +1069,7 @@ impl song_model::SongModel {
let db_string = updated_font_size.clone().to_string(); let db_string = updated_font_size.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET font_size = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET fontSize = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;

View file

@ -2,7 +2,6 @@
pub mod video_model { pub mod video_model {
unsafe extern "C++" { unsafe extern "C++" {
include!(< QAbstractListModel >); include!(< QAbstractListModel >);
type QAbstractListModel;
include!("cxx-qt-lib/qhash.h"); include!("cxx-qt-lib/qhash.h");
type QHash_i32_QByteArray = type QHash_i32_QByteArray =
cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>; cxx_qt_lib::QHash<cxx_qt_lib::QHashPair_i32_QByteArray>;
@ -35,18 +34,15 @@ pub mod video_model {
Looping, Looping,
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[base = QAbstractListModel] #[base = "QAbstractListModel"]
#[qml_element] #[qml_element]
#[qproperty(i32, count)] #[qproperty(i32, count)]
type VideoModel = super::VideoModelRust; type VideoModel = super::VideoModelRust;
#[inherit] #[inherit]
#[qsignal] #[qsignal]
#[cxx_name = "dataChanged"]
fn data_changed( fn data_changed(
self: Pin<&mut VideoModel>, self: Pin<&mut VideoModel>,
top_left: &QModelIndex, top_left: &QModelIndex,
@ -106,11 +102,8 @@ pub mod video_model {
impl cxx_qt::Threading for VideoModel {} impl cxx_qt::Threading for VideoModel {}
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[inherit] #[inherit]
#[cxx_name = "beginInsertRows"]
unsafe fn begin_insert_rows( unsafe fn begin_insert_rows(
self: Pin<&mut VideoModel>, self: Pin<&mut VideoModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -119,11 +112,9 @@ pub mod video_model {
); );
#[inherit] #[inherit]
#[cxx_name = "endInsertRows"]
unsafe fn end_insert_rows(self: Pin<&mut VideoModel>); unsafe fn end_insert_rows(self: Pin<&mut VideoModel>);
#[inherit] #[inherit]
#[cxx_name = "beginRemoveRows"]
unsafe fn begin_remove_rows( unsafe fn begin_remove_rows(
self: Pin<&mut VideoModel>, self: Pin<&mut VideoModel>,
parent: &QModelIndex, parent: &QModelIndex,
@ -132,7 +123,6 @@ pub mod video_model {
); );
#[inherit] #[inherit]
#[cxx_name = "beginMoveRows"]
unsafe fn begin_move_rows( unsafe fn begin_move_rows(
self: Pin<&mut VideoModel>, self: Pin<&mut VideoModel>,
source_parent: &QModelIndex, source_parent: &QModelIndex,
@ -143,23 +133,18 @@ pub mod video_model {
) -> bool; ) -> bool;
#[inherit] #[inherit]
#[cxx_name = "endMoveRows"]
unsafe fn end_move_rows(self: Pin<&mut VideoModel>); unsafe fn end_move_rows(self: Pin<&mut VideoModel>);
#[inherit] #[inherit]
#[cxx_name = "endRemoveRows"]
unsafe fn end_remove_rows(self: Pin<&mut VideoModel>); unsafe fn end_remove_rows(self: Pin<&mut VideoModel>);
#[inherit] #[inherit]
#[cxx_name = "beginResetModel"]
unsafe fn begin_reset_model(self: Pin<&mut VideoModel>); unsafe fn begin_reset_model(self: Pin<&mut VideoModel>);
#[inherit] #[inherit]
#[cxx_name = "endResetModel"]
unsafe fn end_reset_model(self: Pin<&mut VideoModel>); unsafe fn end_reset_model(self: Pin<&mut VideoModel>);
#[inherit] #[inherit]
#[cxx_name = "canFetchMore"]
fn can_fetch_more( fn can_fetch_more(
self: &VideoModel, self: &VideoModel,
parent: &QModelIndex, parent: &QModelIndex,
@ -183,22 +168,19 @@ pub mod video_model {
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "roleNames"]
fn role_names(self: &VideoModel) -> QHash_i32_QByteArray; fn role_names(self: &VideoModel) -> QHash_i32_QByteArray;
#[qinvokable] #[qinvokable]
#[cxx_override] #[cxx_override]
#[cxx_name = "rowCount"]
fn row_count(self: &VideoModel, _parent: &QModelIndex) fn row_count(self: &VideoModel, _parent: &QModelIndex)
-> i32; -> i32;
} }
} }
use color_eyre::eyre::Error;
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{QByteArray, QModelIndex, QString, QUrl, QVariant}; use cxx_qt_lib::{QByteArray, QModelIndex, QString, QUrl, QVariant};
use sqlx::{Connection, SqliteConnection, query, query_as}; use sqlx::{query, query_as, Connection, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
use tracing::{debug, error}; use tracing::{debug, error};
@ -242,11 +224,9 @@ impl Default for VideoModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}, }
} }
} }
} }
@ -260,20 +240,12 @@ pub fn get_video(index: i32) -> color_eyre::Result<Video> {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
}) })
}; };
rt.block_on(async { rt.block_on(async {
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; 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?;
match result { Ok(result)
Ok(v) => Ok(v),
Err(e) => {
error!(?e);
Err(color_eyre::Report::from(e))
},
}
}) })
} }
@ -289,7 +261,7 @@ impl video_model::VideoModel {
pub fn setup(mut self: Pin<&mut Self>) { pub fn setup(mut self: Pin<&mut Self>) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
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; 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;
match result { match result {
Ok(v) => v.into_iter().for_each(|v| self.as_mut().add_video(v)), 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}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -305,10 +277,7 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = let result = query!("delete from videos where id = ?", video_id).execute(&mut self.as_mut().rust_mut().db).await;
query!("delete from videos where id = ?", video_id)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
unsafe { unsafe {
@ -365,7 +334,7 @@ impl video_model::VideoModel {
rt.block_on(async { rt.block_on(async {
let video_title = video_title.to_string(); let video_title = video_title.to_string();
let video_path = video_path.to_string(); let video_path = video_path.to_string();
let result = query!(r#"INSERT into videos (id, title, file_path, start_time, end_time, loop) VALUES (?, ?, ?, ?, ?, ?)"#, let result = query!(r#"INSERT into videos (id, title, filePath, startTime, endTime, loop) VALUES (?, ?, ?, ?, ?, ?)"#,
video_id, video_id,
video_title, video_title,
video_path, video_path,
@ -466,11 +435,7 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE videos SET loop = ? where id = ?", loop_value, index)
"UPDATE videos SET loop = ? where id = ?",
loop_value,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -483,11 +448,9 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.looping = loop_value; video.looping = loop_value;
debug!( debug!(title = video.title,
title = video.title,
looping = loop_value, looping = loop_value,
"updated video loop" "updated video loop");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -499,7 +462,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true
@ -518,11 +481,7 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE videos SET endTime = ? where id = ?", updated_end_time, index)
"UPDATE videos SET end_time = ? where id = ?",
updated_end_time,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -535,11 +494,9 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.end_time = updated_end_time; video.end_time = updated_end_time;
debug!( debug!(title = video.title,
title = video.title,
end_time = updated_end_time, end_time = updated_end_time,
"updated video end_time" "updated video end_time");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -551,7 +508,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true
@ -570,11 +527,7 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!( let result = query!("UPDATE videos SET startTime = ? where id = ?", updated_start_time, index)
"UPDATE videos SET start_time = ? where id = ?",
updated_start_time,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -587,11 +540,9 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.start_time = updated_start_time; video.start_time = updated_start_time;
debug!( debug!(title = video.title,
title = video.title,
start_time = updated_start_time, start_time = updated_start_time,
"updated video start_time" "updated video start_time");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -603,7 +554,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true
@ -623,11 +574,7 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let title = updated_title.to_string(); let title = updated_title.to_string();
let result = query!( let result = query!("UPDATE videos SET title = ? where id = ?", title, index)
"UPDATE videos SET title = ? where id = ?",
title,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -640,11 +587,9 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.title = title.clone(); video.title = title.clone();
debug!( debug!(title = video.title,
title = video.title,
title = title, title = title,
"updated video title" "updated video title");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -656,7 +601,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true
@ -675,11 +620,7 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let updated_path = updated_path.to_string(); let updated_path = updated_path.to_string();
let result = query!( let result = query!("UPDATE videos SET filePath = ? where id = ?", updated_path, index)
"UPDATE videos SET file_path = ? where id = ?",
updated_path,
index
)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
match result { match result {
@ -692,11 +633,9 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.path = updated_path.clone(); video.path = updated_path.clone();
debug!( debug!(title = video.title,
title = video.title,
path = updated_path, path = updated_path,
"updated video path" "updated video path");
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -708,7 +647,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
} },
} }
}); });
true true

View file

@ -7,8 +7,6 @@ mod ytdl {
type QString = cxx_qt_lib::QString; type QString = cxx_qt_lib::QString;
} }
#[auto_cxx_name]
#[auto_rust_name]
unsafe extern "RustQt" { unsafe extern "RustQt" {
#[qobject] #[qobject]
#[qml_element] #[qml_element]
@ -69,10 +67,14 @@ impl ytdl::Ytdl {
.run() .run()
.unwrap(); .unwrap();
let output = ytdl.into_single_video().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 title = QString::from(&output.title);
let thumbnail = let thumbnail = QUrl::from(
QUrl::from(&output.thumbnail.unwrap_or_default()); &output.thumbnail.unwrap_or_default(),
);
let mut file = String::from(output_dirs); let mut file = String::from(output_dirs);
file.push('/'); file.push('/');
file.push_str(&output.title); file.push_str(&output.title);
@ -84,8 +86,12 @@ impl ytdl::Ytdl {
qobject_ytdl.as_mut().set_loaded(true); qobject_ytdl.as_mut().set_loaded(true);
qobject_ytdl.as_mut().set_loading(false); qobject_ytdl.as_mut().set_loading(false);
qobject_ytdl.as_mut().set_title(title); qobject_ytdl.as_mut().set_title(title);
qobject_ytdl.as_mut().set_thumbnail(thumbnail); qobject_ytdl
qobject_ytdl.as_mut().set_file(QUrl::from(&file)); .as_mut()
.set_thumbnail(thumbnail);
qobject_ytdl
.as_mut()
.set_file(QUrl::from(&file));
}) })
}); });
true true