add book
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) Daniel Gakwaya.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(2-SettingsAutomatic VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 6.5 REQUIRED COMPONENTS Quick QuickControls2)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.5)
|
||||
|
||||
qt_add_executable(app2-SettingsAutomatic
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(app2-SettingsAutomatic
|
||||
URI 2-SettingsAutomatic
|
||||
VERSION 1.0
|
||||
QML_FILES Main.qml
|
||||
)
|
||||
|
||||
set_target_properties(app2-SettingsAutomatic PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(app2-SettingsAutomatic
|
||||
PRIVATE Qt6::Quick Qt6::QuickControls2
|
||||
)
|
||||
|
||||
install(TARGETS app2-SettingsAutomatic
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
54
Qt6QMLBeginnersCode/13-Storage/2-SettingsAutomatic/Main.qml
Normal file
54
Qt6QMLBeginnersCode/13-Storage/2-SettingsAutomatic/Main.qml
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Dialogs
|
||||
import QtCore
|
||||
|
||||
Window {
|
||||
id: rootId
|
||||
visible: true
|
||||
width: 640
|
||||
height: 480
|
||||
title: qsTr("SettingsDemo1")
|
||||
|
||||
Rectangle {
|
||||
id: rectId
|
||||
anchors.fill: parent
|
||||
color: "red"
|
||||
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
colorDialogId.open()
|
||||
}
|
||||
|
||||
ColorDialog {
|
||||
id: colorDialogId
|
||||
title: "Please choose a color"
|
||||
onAccepted: {
|
||||
console.log("The new color is: "+ selectedColor)
|
||||
rectId.color = selectedColor
|
||||
}
|
||||
onRejected: {
|
||||
console.log("Canceled")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Settings{
|
||||
category: "window"
|
||||
property alias x: rootId.x
|
||||
property alias y: rootId.y
|
||||
property alias width: rootId.width
|
||||
property alias height: rootId.height
|
||||
}
|
||||
|
||||
Settings{
|
||||
category: "colors"
|
||||
property alias rectColor: rectId.color
|
||||
}
|
||||
|
||||
}
|
||||
28
Qt6QMLBeginnersCode/13-Storage/2-SettingsAutomatic/main.cpp
Normal file
28
Qt6QMLBeginnersCode/13-Storage/2-SettingsAutomatic/main.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickStyle>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QQuickStyle::setStyle("Basic");
|
||||
|
||||
//App Information
|
||||
app.setOrganizationName("LearnQt");
|
||||
app.setOrganizationDomain("learnqt.guide");
|
||||
app.setApplicationName("SettingsDemo");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
|
||||
&app, []() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
engine.loadFromModule("2-SettingsAutomatic", "Main");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) Daniel Gakwaya.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(3-SettingsCustom VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 6.5 REQUIRED COMPONENTS Quick QuickControls2)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.5)
|
||||
|
||||
qt_add_executable(app3-SettingsCustom
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(app3-SettingsCustom
|
||||
URI 3-SettingsCustom
|
||||
VERSION 1.0
|
||||
QML_FILES Main.qml
|
||||
)
|
||||
|
||||
set_target_properties(app3-SettingsCustom PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(app3-SettingsCustom
|
||||
PRIVATE Qt6::Quick Qt6::QuickControls2
|
||||
)
|
||||
|
||||
install(TARGETS app3-SettingsCustom
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
75
Qt6QMLBeginnersCode/13-Storage/3-SettingsCustom/Main.qml
Normal file
75
Qt6QMLBeginnersCode/13-Storage/3-SettingsCustom/Main.qml
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Dialogs
|
||||
import QtCore
|
||||
|
||||
Window {
|
||||
id: rootId
|
||||
visible: true
|
||||
|
||||
//2.Read data from the Settings object
|
||||
x: windowSettingsId.x
|
||||
y: windowSettingsId.y
|
||||
width: windowSettingsId.width
|
||||
height: windowSettingsId.height
|
||||
|
||||
title: qsTr("Custom Settings")
|
||||
|
||||
Rectangle {
|
||||
id : rectId
|
||||
anchors.fill: parent
|
||||
|
||||
//2.Read data from the Settings object
|
||||
color: colorSettingsId.rectColor
|
||||
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
colorDialogId.open()
|
||||
}
|
||||
|
||||
ColorDialog {
|
||||
id: colorDialogId
|
||||
title: "Please choose a color"
|
||||
onAccepted: {
|
||||
console.log("The new color is: "+ selectedColor)
|
||||
rectId.color = selectedColor
|
||||
}
|
||||
onRejected: {
|
||||
console.log("Canceled")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//1. Don't use property aliases in the Settings objects
|
||||
Settings{
|
||||
id: windowSettingsId
|
||||
category: "window"
|
||||
property int x: 300
|
||||
property int y: 300
|
||||
property int width: 640
|
||||
property int height: 480
|
||||
}
|
||||
|
||||
Settings{
|
||||
id: colorSettingsId
|
||||
category: "colors"
|
||||
property color rectColor: "red"
|
||||
}
|
||||
|
||||
//3.Save the data when the Window object is about to die
|
||||
Component.onDestruction: {
|
||||
//Save the window properties
|
||||
windowSettingsId.x = rootId.x
|
||||
windowSettingsId.y = rootId.y
|
||||
windowSettingsId.width = rootId.width
|
||||
windowSettingsId.height = rootId.height
|
||||
|
||||
//Save the color property
|
||||
colorSettingsId.rectColor = rectId.color
|
||||
}
|
||||
}
|
||||
28
Qt6QMLBeginnersCode/13-Storage/3-SettingsCustom/main.cpp
Normal file
28
Qt6QMLBeginnersCode/13-Storage/3-SettingsCustom/main.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickStyle>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
QQuickStyle::setStyle("Basic");
|
||||
|
||||
//App Information
|
||||
app.setOrganizationName("LearnQt2");
|
||||
app.setOrganizationDomain("learnqts.guide");
|
||||
app.setApplicationName("SettingsDemos");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
|
||||
&app, []() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
engine.loadFromModule("3-SettingsCustom", "Main");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
# Copyright (c) Daniel Gakwaya.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(4-SaveTheStates VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.5)
|
||||
|
||||
qt_add_executable(app4-SaveTheStates
|
||||
main.cpp resource.qrc
|
||||
)
|
||||
|
||||
qt_add_qml_module(app4-SaveTheStates
|
||||
URI 4-SaveTheStates
|
||||
VERSION 1.0
|
||||
QML_FILES Main.qml
|
||||
)
|
||||
|
||||
set_target_properties(app4-SaveTheStates PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(app4-SaveTheStates
|
||||
PRIVATE Qt6::Quick
|
||||
)
|
||||
|
||||
install(TARGETS app4-SaveTheStates
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
189
Qt6QMLBeginnersCode/13-Storage/4-SaveTheStates/Main.qml
Normal file
189
Qt6QMLBeginnersCode/13-Storage/4-SaveTheStates/Main.qml
Normal file
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Window
|
||||
import QtCore
|
||||
Window {
|
||||
visible: true
|
||||
width: 640
|
||||
height: 480
|
||||
title: qsTr("Custom Settings Demo")
|
||||
|
||||
Rectangle {
|
||||
id: containerRectId
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
id: skyId
|
||||
width: parent.width
|
||||
height: 200
|
||||
//color : "blue"
|
||||
gradient: Gradient {
|
||||
GradientStop {id: skyStartColorId; position: 0.0; color: "blue" }
|
||||
GradientStop {id: skyEndColorId; position: 1.0; color: "#66CCFF" }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: groundId
|
||||
anchors.top: skyId.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
width: parent.width
|
||||
//color: "lime"
|
||||
gradient: Gradient {
|
||||
GradientStop {id: groundStartColorId; position: 0.0; color: "lime" }
|
||||
GradientStop {id: groundEndColorId; position: 1.0; color: "#66CCFF" }
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: treespringId
|
||||
x: 50
|
||||
y: 100
|
||||
width: 200
|
||||
height: 300
|
||||
source: "qrc:/images/treespringsmall.png"
|
||||
}
|
||||
Image {
|
||||
id: treeSummerId
|
||||
x: 50
|
||||
y: 100
|
||||
width: 200
|
||||
height: 300
|
||||
source: "qrc:/images/treesummersmall.png"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id : sunId
|
||||
x: parent.width - width -100
|
||||
y: 50
|
||||
width: 100
|
||||
height: 100
|
||||
color: "yellow"
|
||||
radius: 60
|
||||
|
||||
|
||||
}
|
||||
|
||||
//state : "spring"
|
||||
state: settings.state
|
||||
|
||||
//States
|
||||
states: [
|
||||
State {
|
||||
name : "summer"
|
||||
PropertyChanges {
|
||||
target: skyId
|
||||
color: "lightblue"
|
||||
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: skyStartColorId
|
||||
color: "lightblue"
|
||||
}
|
||||
PropertyChanges {
|
||||
target: skyEndColorId
|
||||
color: "#EECCFF"
|
||||
}
|
||||
|
||||
|
||||
|
||||
PropertyChanges {
|
||||
target: treeSummerId
|
||||
opacity: 1
|
||||
}
|
||||
PropertyChanges {
|
||||
target: treespringId
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
|
||||
PropertyChanges {
|
||||
target: groundStartColorId
|
||||
color: "lime"
|
||||
}
|
||||
PropertyChanges {
|
||||
target: groundEndColorId
|
||||
color: "darkkhaki"
|
||||
}
|
||||
PropertyChanges {
|
||||
target: sunId
|
||||
color: "yellow"
|
||||
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
State {
|
||||
name: "spring"
|
||||
PropertyChanges {
|
||||
target: skyId
|
||||
color: "deepskyblue"
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: skyStartColorId
|
||||
color: "deepskyblue"
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: skyEndColorId
|
||||
color: "#AACCFF"
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: treeSummerId
|
||||
opacity: 0
|
||||
}
|
||||
PropertyChanges {
|
||||
target: treespringId
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: groundStartColorId
|
||||
color: "lime"
|
||||
}
|
||||
PropertyChanges {
|
||||
target: groundStartColorId
|
||||
color: "lime"
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: sunId
|
||||
color: "lightyellow"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions : Transition {
|
||||
from: "*" ; to: "*"
|
||||
|
||||
ColorAnimation {
|
||||
duration: 500
|
||||
}
|
||||
NumberAnimation {
|
||||
properties: "opacity"
|
||||
duration: 500
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
containerRectId.state = (containerRectId.state === "spring" ? "summer" : "spring")
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
property string state: "spring"
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
settings.state = containerRectId.state
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 293 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 201 KiB |
26
Qt6QMLBeginnersCode/13-Storage/4-SaveTheStates/main.cpp
Normal file
26
Qt6QMLBeginnersCode/13-Storage/4-SaveTheStates/main.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
|
||||
//App Information
|
||||
app.setOrganizationName("LearnQt1");
|
||||
app.setOrganizationDomain("learnqt1.guide");
|
||||
app.setApplicationName("SettingsDemo1");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
|
||||
&app, []() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
engine.loadFromModule("4-SaveTheStates", "Main");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>images/treespringsmall.png</file>
|
||||
<file>images/treesummersmall.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
40
Qt6QMLBeginnersCode/13-Storage/5-SQLite/CMakeLists.txt
Normal file
40
Qt6QMLBeginnersCode/13-Storage/5-SQLite/CMakeLists.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) Daniel Gakwaya.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(5-SQLite VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 6.5 REQUIRED COMPONENTS Quick QuickControls2)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.5)
|
||||
|
||||
qt_add_executable(app5-SQLite
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(app5-SQLite
|
||||
URI 5-SQLite
|
||||
VERSION 1.0
|
||||
QML_FILES Main.qml Database.js
|
||||
)
|
||||
|
||||
set_target_properties(app5-SQLite PROPERTIES
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(app5-SQLite
|
||||
PRIVATE Qt6::Quick Qt6::QuickControls2
|
||||
)
|
||||
|
||||
install(TARGETS app5-SQLite
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
79
Qt6QMLBeginnersCode/13-Storage/5-SQLite/Database.js
Normal file
79
Qt6QMLBeginnersCode/13-Storage/5-SQLite/Database.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
function dbInit(){
|
||||
console.log(" Initializing database...")
|
||||
|
||||
db = LocalStorage.openDatabaseSync("sqlitedemodb", "1.0", "SQLite Demo database", 100000);
|
||||
db.transaction( function(tx) {
|
||||
print('... create table')
|
||||
tx.executeSql('CREATE TABLE IF NOT EXISTS sqlitedemotable(name TEXT, value TEXT)');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function storeData(){
|
||||
console.log(" Storing data...")
|
||||
|
||||
//Check if the database was ever created
|
||||
if (!db){
|
||||
return ;
|
||||
}
|
||||
|
||||
db.transaction(function(tx){
|
||||
//Check if sqlitedemo entry is available in database table
|
||||
var result = tx.executeSql('SELECT * from sqlitedemotable where name = "sqlitedemo"');
|
||||
|
||||
//Prepare json object data from qml code
|
||||
var obj = { x: rootId.x, y: rootId.y,
|
||||
width : rootId.width,height : rootId.height,
|
||||
colorred : rectId.color.r,colorgreen : rectId.color.g ,
|
||||
colorblue : rectId.color.b };
|
||||
|
||||
if ( result.rows.length ===1 ){
|
||||
//Update
|
||||
console.log("Updating database table...")
|
||||
result = tx.executeSql('UPDATE sqlitedemotable set value=? where name="sqlitedemo"',
|
||||
[JSON.stringify(obj)])
|
||||
}else{
|
||||
//Create entry
|
||||
console.log("Creating new database table entry")
|
||||
result = tx.executeSql('INSERT INTO sqlitedemotable VALUES (?,?)',
|
||||
['sqlitedemo', JSON.stringify(obj)])
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function readData(){
|
||||
console.log(" Reading data...")
|
||||
|
||||
if (!db){
|
||||
return ;
|
||||
}
|
||||
|
||||
db.transaction( function(tx) {
|
||||
print('... Reading data from database')
|
||||
var result = tx.executeSql('select * from sqlitedemotable where name="sqlitedemo"');
|
||||
|
||||
if(result.rows.length === 1){
|
||||
//We have data that we can work with
|
||||
|
||||
// get the value column
|
||||
var value = result.rows[0].value;
|
||||
// convert to JS object
|
||||
var obj = JSON.parse(value)
|
||||
|
||||
// apply to object
|
||||
rootId.x = obj.x;
|
||||
rootId.y = obj.y;
|
||||
rootId.width= obj.width;
|
||||
rootId.height = obj.height
|
||||
rectId.color= Qt.rgba(obj.colorred,obj.colorgreen,obj.colorblue,1)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
51
Qt6QMLBeginnersCode/13-Storage/5-SQLite/Main.qml
Normal file
51
Qt6QMLBeginnersCode/13-Storage/5-SQLite/Main.qml
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.LocalStorage
|
||||
import QtQuick.Dialogs
|
||||
import "Database.js" as JS
|
||||
|
||||
Window {
|
||||
id: rootId
|
||||
visible: true
|
||||
width: 640
|
||||
height: 480
|
||||
title: qsTr("SQLite")
|
||||
property var db ;
|
||||
|
||||
Rectangle{
|
||||
id: rectId
|
||||
anchors.fill: parent
|
||||
color: "red"
|
||||
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
colorDialogId.open()
|
||||
}
|
||||
|
||||
ColorDialog {
|
||||
id: colorDialogId
|
||||
title: "Please choose a color"
|
||||
onAccepted: {
|
||||
console.log("The new color is: "+ selectedColor)
|
||||
rectId.color = selectedColor
|
||||
}
|
||||
onRejected: {
|
||||
console.log("Canceled")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
//Read data
|
||||
JS.dbInit()
|
||||
JS.readData()
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
JS.storeData()
|
||||
}
|
||||
}
|
||||
22
Qt6QMLBeginnersCode/13-Storage/5-SQLite/main.cpp
Normal file
22
Qt6QMLBeginnersCode/13-Storage/5-SQLite/main.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Daniel Gakwaya.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickStyle>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
QQuickStyle::setStyle("Basic");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
|
||||
&app, []() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
engine.loadFromModule("5-SQLite", "Main");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
57
Qt6QMLBeginnersCode/13-Storage/6-TodolistStorage/.gitignore
vendored
Normal file
57
Qt6QMLBeginnersCode/13-Storage/6-TodolistStorage/.gitignore
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
# Qt QML Language Server configuration
|
||||
qmlls.ini
|
||||
|
||||
# Build directories
|
||||
build/
|
||||
Desktop_Qt_6_9_0_MinGW_64_bit-Debug/
|
||||
|
||||
# Qt Creator user settings
|
||||
CMakeLists.txt.user
|
||||
|
||||
# Compiled Object files
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Compiled Static libraries
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Qt-specific
|
||||
*.qm
|
||||
*.prl
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*.qbs.user
|
||||
*.qbs.user.*
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
Makefile*
|
||||
*build-*
|
||||
|
||||
# QML cache and compiled files
|
||||
*.qmlc
|
||||
*.jsc
|
||||
|
||||
# Qt temporary files
|
||||
*~
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Windows
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
@@ -0,0 +1,55 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(TodoList VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Quick QuickControls2)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.8)
|
||||
|
||||
qt_add_executable(TodoList
|
||||
src/main.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(TodoList
|
||||
URI TodoList
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
# Main View
|
||||
src/views/MainView.qml
|
||||
|
||||
# Components
|
||||
src/components/AppHeader.qml
|
||||
src/components/AddTaskBar.qml
|
||||
src/components/TaskItem.qml
|
||||
src/components/TaskStats.qml
|
||||
|
||||
# Models
|
||||
src/models/TaskListModel.qml
|
||||
|
||||
# Utils
|
||||
src/utils/TaskStorage.qml
|
||||
)
|
||||
|
||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||
# If you are developing for iOS or macOS you should consider setting an
|
||||
# explicit, fixed bundle identifier manually though.
|
||||
set_target_properties(TodoList PROPERTIES
|
||||
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.app01_todolist_starter
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(TodoList
|
||||
PRIVATE Qt6::Quick Qt6::QuickControls2
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS TodoList
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
@@ -0,0 +1,110 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
height: 60
|
||||
|
||||
signal taskAdded(string taskText)
|
||||
|
||||
property color backgroundColor: "#ffffff"
|
||||
property color textColor: "#333333"
|
||||
property color primaryColor: "#007aff"
|
||||
property bool darkMode: false
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: root.backgroundColor
|
||||
radius: 12
|
||||
border.color: root.darkMode ? "#404040" : "#e0e0e0"
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 12
|
||||
|
||||
// Add icon
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 36
|
||||
Layout.preferredHeight: 36
|
||||
color: root.primaryColor
|
||||
radius: 18
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "+"
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 20
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
}
|
||||
|
||||
// Text input
|
||||
TextField {
|
||||
id: taskInput
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 36
|
||||
placeholderText: qsTr("Add a new task...")
|
||||
placeholderTextColor: root.darkMode ? "#888888" : "#999999"
|
||||
color: root.textColor
|
||||
font.pixelSize: 16
|
||||
selectByMouse: true
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
border.color: "transparent"
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: root.addTask()
|
||||
Keys.onEnterPressed: root.addTask()
|
||||
|
||||
}
|
||||
|
||||
// Add button
|
||||
Button {
|
||||
id: addButton
|
||||
Layout.preferredWidth: 80
|
||||
Layout.preferredHeight: 36
|
||||
text: qsTr("Add")
|
||||
enabled: taskInput.text.trim().length > 0
|
||||
|
||||
background: Rectangle {
|
||||
color: addButton.enabled ?
|
||||
(addButton.pressed ? Qt.darker(root.primaryColor, 1.2) : root.primaryColor) :
|
||||
(root.darkMode ? "#404040" : "#e0e0e0")
|
||||
radius: 8
|
||||
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
text: addButton.text
|
||||
color: addButton.enabled ? "#ffffff" : (root.darkMode ? "#888888" : "#cccccc")
|
||||
font.pixelSize: 14
|
||||
font.weight: Font.Medium
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
}
|
||||
|
||||
onClicked: root.addTask()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addTask() {
|
||||
if (taskInput.text.trim().length > 0) {
|
||||
root.taskAdded(taskInput.text.trim())
|
||||
taskInput.text = ""
|
||||
taskInput.focus = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
height: 80
|
||||
|
||||
signal toggleDarkMode()
|
||||
|
||||
// Properties that will be bound from parent
|
||||
property color textColor: "#333333"
|
||||
property color textSecondary: "#999999"
|
||||
property bool darkMode: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
RowLayout{
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
spacing: 12
|
||||
|
||||
// App icon
|
||||
Text {
|
||||
text: "📝"
|
||||
font.pixelSize: 32
|
||||
}
|
||||
|
||||
// App title and subtitle
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: "My Tasks"
|
||||
font.pixelSize: 28
|
||||
font.weight: Font.Bold
|
||||
color: root.textColor
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("Stay organized, stay productive")
|
||||
font.pixelSize: 12
|
||||
color: root.textSecondary
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Dark mode toggle
|
||||
Button {
|
||||
id: themeToggle
|
||||
Layout.preferredWidth: 50
|
||||
Layout.preferredHeight: 50
|
||||
|
||||
background: Rectangle {
|
||||
color: themeToggle.pressed ?
|
||||
(root.darkMode ? "#404040" : "#e0e0e0") :
|
||||
(root.darkMode ? "#2d2d2d" : "#f5f5f5")
|
||||
radius: 25
|
||||
border.color: root.darkMode ? "#555555" : "#d0d0d0"
|
||||
border.width: 1
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Text{
|
||||
text: root.darkMode ? "☀️" : "🌙"
|
||||
font.pixelSize: 20
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
//Emit the signal when the button is clicked
|
||||
onClicked: root.toggleDarkMode()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
height: 56
|
||||
|
||||
required property string taskTitle
|
||||
required property bool taskDone
|
||||
|
||||
signal toggleDone()
|
||||
signal deleteTask()
|
||||
|
||||
property color backgroundColor: "#ffffff"
|
||||
property color textColor: "#333333"
|
||||
property color completedColor: "#999999"
|
||||
property color primaryColor: "#007aff"
|
||||
property bool darkMode: false
|
||||
|
||||
// Constants for this component
|
||||
readonly property int itemHeight: 56
|
||||
readonly property int margins: 4
|
||||
readonly property int innerMargins: 12
|
||||
readonly property int checkboxSize: 24
|
||||
readonly property int deleteButtonSize: 32
|
||||
|
||||
Rectangle {
|
||||
id: taskItemBackground
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
id: itemBackground
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.margins
|
||||
color: root.backgroundColor
|
||||
radius: 8
|
||||
border.color: root.taskDone ? "transparent" : (root.darkMode ? "#404040" : "#f0f0f0")
|
||||
border.width: 1
|
||||
opacity: root.taskDone ? 0.7 : 1.0
|
||||
|
||||
scale: itemBackground.hovered ? 1.02 : 1.0
|
||||
|
||||
// Smooth transitions for background properties
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 300 }
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: 300 }
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 150; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: root.innerMargins
|
||||
spacing: 12
|
||||
|
||||
// Checkbox
|
||||
Rectangle {
|
||||
id: checkbox
|
||||
Layout.preferredWidth: root.checkboxSize
|
||||
Layout.preferredHeight: root.checkboxSize
|
||||
color: root.taskDone ? root.primaryColor : "transparent"
|
||||
border.color: root.taskDone ? root.primaryColor : (root.darkMode ? "#666666" : "#cccccc")
|
||||
border.width: 2
|
||||
radius: 4
|
||||
|
||||
// Smooth transitions for checkbox state changes
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 100; easing.type: Easing.OutBack }
|
||||
}
|
||||
|
||||
// Checkmark
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "✓"
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Bold
|
||||
opacity: root.taskDone ? 1.0 : 0.0
|
||||
|
||||
scale: root.taskDone ? 1.0 : 0.3
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutBack }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
// Add click animation
|
||||
checkbox.scale = 0.9
|
||||
scaleResetTimer.restart()
|
||||
|
||||
//Toggle the task
|
||||
root.toggleDone()
|
||||
}
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
// Timer to reset scale after click
|
||||
Timer {
|
||||
id: scaleResetTimer
|
||||
interval: 100
|
||||
onTriggered: checkbox.scale = 1.0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Task text
|
||||
Text {
|
||||
id: taskText
|
||||
Layout.fillWidth: true
|
||||
text: root.taskTitle
|
||||
color: root.taskDone ? root.completedColor : root.textColor
|
||||
font.pixelSize: 16
|
||||
font.strikeout: root.taskDone
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
// Smooth color transition when task state changes
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 300 }
|
||||
}
|
||||
|
||||
// Subtle scale animation on completion
|
||||
scale: root.taskDone ? 0.95 : 1.0
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.toggleDone()
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
|
||||
// Delete button
|
||||
Button {
|
||||
id: deleteButton
|
||||
Layout.preferredWidth: root.deleteButtonSize
|
||||
Layout.preferredHeight: root.deleteButtonSize
|
||||
opacity: itemBackground.hovered ? 1.0 : 0.3
|
||||
scale: deleteButton.pressed ? 0.9 : 1.0
|
||||
|
||||
// Smooth transitions
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: 100; easing.type: Easing.OutQuad }
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: deleteButton.pressed ? "#ff3b30" : "transparent"
|
||||
radius: 16
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
text: "🗑"
|
||||
font.pixelSize: 16
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
rotation: deleteButton.pressed ? 15 : 0
|
||||
|
||||
Behavior on rotation {
|
||||
NumberAnimation { duration: 100 }
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.deleteTask()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hover effect
|
||||
property bool hovered: false
|
||||
|
||||
HoverHandler {
|
||||
onHoveredChanged: itemBackground.hovered = hovered
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
height: visible ? 60 : 0
|
||||
visible: totalTasks > 0
|
||||
|
||||
property int totalTasks: 0
|
||||
property int completedTasks: 0
|
||||
property int remainingTasks: 0
|
||||
property bool hasCompleted: false
|
||||
|
||||
property color backgroundColor: "#ffffff"
|
||||
property color textColor: "#333333"
|
||||
property color secondaryTextColor: "#666666"
|
||||
property color primaryColor: "#007aff"
|
||||
property color dangerColor: "#ff3b30"
|
||||
property bool darkMode: false
|
||||
|
||||
signal clearCompleted()
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: root.backgroundColor
|
||||
radius: 12
|
||||
border.color: root.darkMode ? "#404040" : "#e0e0e0"
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 16
|
||||
|
||||
// Statistics text
|
||||
Column {
|
||||
Layout.fillWidth: true
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
text: root.totalTasks === 1 ?
|
||||
qsTr("%1 task").arg(root.totalTasks) :
|
||||
qsTr("%1 tasks").arg(root.totalTasks)
|
||||
color: root.textColor
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.completedTasks > 0 ?
|
||||
qsTr("%1 completed, %2 remaining").arg(root.completedTasks).arg(root.remainingTasks) :
|
||||
qsTr("No tasks completed yet")
|
||||
color: root.secondaryTextColor
|
||||
font.pixelSize: 14
|
||||
visible: root.totalTasks > 0
|
||||
}
|
||||
}
|
||||
|
||||
// Clear completed button
|
||||
Button {
|
||||
id: clearButton
|
||||
Layout.preferredHeight: 36
|
||||
text: qsTr("Clear Completed")
|
||||
visible: root.hasCompleted
|
||||
enabled: root.hasCompleted
|
||||
|
||||
background: Rectangle {
|
||||
color: clearButton.pressed ?
|
||||
Qt.darker(root.dangerColor, 1.2) :
|
||||
(clearButton.hovered ? root.dangerColor : "transparent")
|
||||
border.color: root.dangerColor
|
||||
border.width: 1
|
||||
radius: 8
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
text: clearButton.text
|
||||
color: clearButton.hovered ? "#ffffff" : root.dangerColor
|
||||
font.pixelSize: 14
|
||||
font.weight: Font.Medium
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
onClicked: root.clearCompleted()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickStyle>
|
||||
#include <QSettings>
|
||||
#include <QDebug>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
// Set application identifiers for Settings
|
||||
app.setOrganizationName("TodoApp");
|
||||
app.setOrganizationDomain("todoapp.local");
|
||||
app.setApplicationName("TodoList");
|
||||
|
||||
// Set Qt Quick Controls style to Basic to enable customization
|
||||
QQuickStyle::setStyle("Basic");
|
||||
|
||||
// Print the settings location
|
||||
QSettings settings;
|
||||
qDebug() << "Settings location:" << settings.fileName();
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
QObject::connect(
|
||||
&engine,
|
||||
&QQmlApplicationEngine::objectCreationFailed,
|
||||
&app,
|
||||
[]() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
engine.loadFromModule("TodoList", "MainView");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Signal emitted when storage is initialized and ready
|
||||
signal storageInitialized()
|
||||
|
||||
// The actual ListModel for tasks
|
||||
property alias model: taskListModel
|
||||
property alias count: taskListModel.count
|
||||
|
||||
// Auto-save flag
|
||||
property bool autoSave: true
|
||||
|
||||
ListModel {
|
||||
id: taskListModel
|
||||
}
|
||||
|
||||
// Storage component for persistence
|
||||
TaskStorage {
|
||||
id: storage
|
||||
|
||||
onTasksLoaded: function(tasks) {
|
||||
root.loadTasksFromArray(tasks)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Emit signal that storage is ready
|
||||
root.storageInitialized()
|
||||
|
||||
// Load existing tasks
|
||||
let savedTasks = loadTasks()
|
||||
if (savedTasks.length === 0) {
|
||||
// Add some sample tasks only if no saved tasks exist
|
||||
root.addTask("Learn Qt QML")
|
||||
root.addTask("Build a todo app")
|
||||
root.addTask("Practice QML components")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-save trigger - called after any modification
|
||||
function saveToStorage() {
|
||||
if (autoSave) {
|
||||
storage.saveTasks(taskListModel)
|
||||
}
|
||||
}
|
||||
|
||||
// Load tasks from an array (used by storage)
|
||||
function loadTasksFromArray(taskArray) {
|
||||
taskListModel.clear()
|
||||
for (let i = 0; i < taskArray.length; i++) {
|
||||
let task = taskArray[i]
|
||||
taskListModel.append({
|
||||
"id": task.id || generateId(),
|
||||
"title": task.title || "",
|
||||
"completed": task.completed || false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new task
|
||||
function addTask(title) {
|
||||
if (title && title.trim().length > 0) {
|
||||
taskListModel.append({
|
||||
"title": title.trim(),
|
||||
"completed": false,
|
||||
"id": generateId()
|
||||
})
|
||||
saveToStorage()
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle task completion status
|
||||
function toggleTask(index) {
|
||||
if (index >= 0 && index < taskListModel.count) {
|
||||
taskListModel.setProperty(index, "completed", !taskListModel.get(index).completed)
|
||||
saveToStorage()
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a task
|
||||
function deleteTask(index) {
|
||||
if (index >= 0 && index < taskListModel.count) {
|
||||
taskListModel.remove(index)
|
||||
saveToStorage()
|
||||
}
|
||||
}
|
||||
|
||||
// Delete task by ID
|
||||
function deleteTaskById(taskId) {
|
||||
for (let i = 0; i < taskListModel.count; i++) {
|
||||
if (taskListModel.get(i).id === taskId) {
|
||||
taskListModel.remove(i)
|
||||
saveToStorage()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all completed tasks
|
||||
function clearCompletedTasks() {
|
||||
for (let i = taskListModel.count - 1; i >= 0; i--) {
|
||||
if (taskListModel.get(i).completed) {
|
||||
taskListModel.remove(i)
|
||||
}
|
||||
}
|
||||
saveToStorage()
|
||||
}
|
||||
|
||||
// Get statistics
|
||||
function getStats() {
|
||||
let total = taskListModel.count
|
||||
let completed = 0
|
||||
|
||||
for (let i = 0; i < taskListModel.count; i++) {
|
||||
if (taskListModel.get(i).completed) {
|
||||
completed++
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"total": total,
|
||||
"completed": completed,
|
||||
"remaining": total - completed
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there are any completed tasks
|
||||
function hasCompletedTasks() {
|
||||
for (let i = 0; i < taskListModel.count; i++) {
|
||||
if (taskListModel.get(i).completed) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Get item at index
|
||||
function get(index) {
|
||||
return taskListModel.get(index)
|
||||
}
|
||||
|
||||
// Generate a unique ID for tasks
|
||||
function generateId() {
|
||||
return Date.now() + Math.random().toString(36).substr(2, 9)
|
||||
}
|
||||
|
||||
// Storage utility functions
|
||||
function clearAllData() {
|
||||
storage.clearStorage()
|
||||
taskListModel.clear()
|
||||
}
|
||||
|
||||
// Access to storage for dark mode preference
|
||||
function saveDarkMode(darkMode) {
|
||||
storage.saveDarkMode(darkMode)
|
||||
}
|
||||
|
||||
function loadDarkMode() {
|
||||
return storage.loadDarkMode()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import QtQuick
|
||||
import QtCore
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Signal emitted when tasks are loaded from storage
|
||||
signal tasksLoaded(var tasks)
|
||||
|
||||
// Settings component for persistent storage
|
||||
Settings {
|
||||
id: settings
|
||||
category: "Tasks"
|
||||
|
||||
// Store tasks as a JSON string
|
||||
property string tasksData: "[]"
|
||||
// Store dark mode preference
|
||||
property bool darkMode: false
|
||||
}
|
||||
|
||||
// Save tasks to storage
|
||||
function saveTasks(tasks) {
|
||||
try {
|
||||
// Convert ListModel data to a proper array
|
||||
let taskArray = []
|
||||
for (let i = 0; i < tasks.count; i++) {
|
||||
let task = tasks.get(i)
|
||||
taskArray.push({
|
||||
id: task.id,
|
||||
title: task.title,
|
||||
completed: task.completed
|
||||
})
|
||||
}
|
||||
|
||||
// Save as JSON string
|
||||
settings.tasksData = JSON.stringify(taskArray)
|
||||
settings.sync() // Force immediate save
|
||||
|
||||
console.log("Tasks saved to storage:", taskArray.length, "tasks")
|
||||
} catch (error) {
|
||||
console.error("Error saving tasks:", error)
|
||||
}
|
||||
}
|
||||
|
||||
// Load tasks from storage
|
||||
function loadTasks() {
|
||||
try {
|
||||
if (settings.tasksData && settings.tasksData !== "[]") {
|
||||
let taskArray = JSON.parse(settings.tasksData)
|
||||
console.log("Tasks loaded from storage:", taskArray.length, "tasks")
|
||||
root.tasksLoaded(taskArray)
|
||||
return taskArray
|
||||
} else {
|
||||
console.log("No saved tasks found, starting with empty list")
|
||||
root.tasksLoaded([])
|
||||
return []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading tasks:", error)
|
||||
root.tasksLoaded([])
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// Save dark mode preference
|
||||
function saveDarkMode(darkMode) {
|
||||
settings.darkMode = darkMode
|
||||
settings.sync()
|
||||
}
|
||||
|
||||
// Load dark mode preference
|
||||
function loadDarkMode() {
|
||||
return settings.darkMode
|
||||
}
|
||||
|
||||
// Clear all stored data
|
||||
function clearStorage() {
|
||||
settings.tasksData = "[]"
|
||||
settings.darkMode = false
|
||||
settings.sync()
|
||||
console.log("Storage cleared")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
ApplicationWindow {
|
||||
id: root
|
||||
width: 400
|
||||
height: 700
|
||||
visible: true
|
||||
title: qsTr("My Tasks")
|
||||
|
||||
// Theme properties
|
||||
property bool darkMode: false
|
||||
property color backgroundColor: darkMode ? "#1e1e1e" : "#f0f2f5"
|
||||
property color primaryColor: "#007aff"
|
||||
property color textColor: darkMode ? "#ffffff" : "#333333"
|
||||
property color cardColor: darkMode ? "#2d2d2d" : "#ffffff"
|
||||
property color completedColor: darkMode ? "#666666" : "#999999"
|
||||
|
||||
//Change 1
|
||||
// Task model - Using the dedicated TaskListModel
|
||||
/*
|
||||
TaskListModel {
|
||||
id: taskModel
|
||||
}
|
||||
*/
|
||||
|
||||
// Task model - Using the dedicated TaskListModel
|
||||
TaskListModel {
|
||||
id: taskModel
|
||||
|
||||
// Connect to storage ready signal to load dark mode
|
||||
onStorageInitialized: {
|
||||
root.darkMode = loadDarkMode()
|
||||
}
|
||||
}
|
||||
|
||||
// Save dark mode preference when changed
|
||||
onDarkModeChanged: {
|
||||
taskModel.saveDarkMode(darkMode)
|
||||
}
|
||||
|
||||
|
||||
// Background
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: root.backgroundColor
|
||||
}
|
||||
|
||||
//The components of the ui
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
spacing: 20
|
||||
|
||||
// Header
|
||||
AppHeader {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
textColor: root.textColor
|
||||
textSecondary: root.completedColor
|
||||
darkMode: root.darkMode
|
||||
onToggleDarkMode: root.darkMode = !root.darkMode
|
||||
}
|
||||
|
||||
// Add task bar
|
||||
AddTaskBar {
|
||||
id: addTaskBar
|
||||
Layout.fillWidth: true
|
||||
backgroundColor: root.cardColor
|
||||
textColor: root.textColor
|
||||
primaryColor: root.primaryColor
|
||||
darkMode: root.darkMode
|
||||
|
||||
onTaskAdded: function(taskText) {
|
||||
taskModel.addTask(taskText)
|
||||
}
|
||||
}
|
||||
|
||||
// Tasks list
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
color: root.cardColor
|
||||
radius: 12
|
||||
border.width: 1
|
||||
border.color: root.darkMode ? "#404040" : "#e0e0e0"
|
||||
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
clip: true
|
||||
|
||||
ListView {
|
||||
id: taskListView
|
||||
|
||||
//Change 2
|
||||
//model: taskModel
|
||||
model: taskModel.model
|
||||
spacing: 8
|
||||
anchors.margins: 12
|
||||
|
||||
|
||||
|
||||
// Add animation transitions
|
||||
add: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x"
|
||||
from: 100; to: 0
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 0; to: 1
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x"
|
||||
to: 100
|
||||
duration: 250
|
||||
easing.type: Easing.InCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: 250
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
properties: "x,y"
|
||||
duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
delegate: TaskItem {
|
||||
required property int index
|
||||
required property string title
|
||||
required property bool completed
|
||||
|
||||
width: taskListView.width
|
||||
taskTitle: title
|
||||
taskDone: completed
|
||||
backgroundColor: root.cardColor
|
||||
textColor: root.textColor
|
||||
completedColor: root.completedColor
|
||||
primaryColor: root.primaryColor
|
||||
darkMode: root.darkMode
|
||||
|
||||
onToggleDone: {
|
||||
taskModel.toggleTask(index)
|
||||
}
|
||||
|
||||
onDeleteTask: {
|
||||
taskModel.deleteTask(index)
|
||||
}
|
||||
}
|
||||
|
||||
// Empty state
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - 40
|
||||
height: 120
|
||||
color: "transparent"
|
||||
visible: taskListView.count === 0
|
||||
opacity: taskListView.count === 0 ? 1.0 : 0.0
|
||||
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 400; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: "📝"
|
||||
font.pixelSize: 48
|
||||
opacity: 0.3
|
||||
|
||||
// Subtle floating animation
|
||||
SequentialAnimation on y {
|
||||
running: taskListView.count === 0
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation { from: 0; to: -5; duration: 1000; easing.type: Easing.InOutSine }
|
||||
NumberAnimation { from: -5; to: 0; duration: 1000; easing.type: Easing.InOutSine }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: qsTr("No tasks yet")
|
||||
color: root.completedColor
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Medium
|
||||
|
||||
// Gentle opacity breathing animation
|
||||
SequentialAnimation on opacity {
|
||||
running: taskListView.count === 0
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation { from: 0.7; to: 1.0; duration: 1500; easing.type: Easing.InOutSine }
|
||||
NumberAnimation { from: 1.0; to: 0.7; duration: 1500; easing.type: Easing.InOutSine }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: qsTr("Add a task above to get started")
|
||||
color: root.completedColor
|
||||
font.pixelSize: 14
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
// Gentle opacity breathing animation with slight delay
|
||||
SequentialAnimation on opacity {
|
||||
running: taskListView.count === 0
|
||||
loops: Animation.Infinite
|
||||
PauseAnimation { duration: 300 } // Small delay for staggered effect
|
||||
NumberAnimation { from: 0.6; to: 0.9; duration: 1500; easing.type: Easing.InOutSine }
|
||||
NumberAnimation { from: 0.9; to: 0.6; duration: 1500; easing.type: Easing.InOutSine }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Task statistics at bottom
|
||||
TaskStats {
|
||||
id: taskStats
|
||||
Layout.fillWidth: true
|
||||
backgroundColor: root.cardColor
|
||||
textColor: root.textColor
|
||||
secondaryTextColor: root.completedColor
|
||||
primaryColor: root.primaryColor
|
||||
darkMode: root.darkMode
|
||||
totalTasks: taskModel.count
|
||||
completedTasks: taskModel.getStats().completed
|
||||
remainingTasks: taskModel.getStats().remaining
|
||||
hasCompleted: taskModel.hasCompletedTasks()
|
||||
|
||||
onClearCompleted: {
|
||||
taskModel.clearCompletedTasks()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user