I am currently building a multi-user calendar app in Qt, and intend to use firebase realtime database to handle the user data and scheduled tasks.
Each user can login to the app and select days which, once clicking on a 'save' button, will be locked to their name. I have no previous experience with firebase and would like some help to begin structuring the database, I want to be able to separate users into departments also.
Below is the code of my calendar page on my app, what would I put into firebase to be able to connect the two?
any help would be much appreciated!!
Page {
title: "Calendar"
rightBarItem: NavigationBarItem {
contentWidth: saveButton.width
AppButton {
id: saveButton
text: "Save & Request"
anchors.right: parent.right
}
}
SystemPalette {
id: systemPalette
}
Flow {
id: row
anchors.fill: parent
spacing: 10
layoutDirection: "RightToLeft"
Calendar {
id: calendar
width: (parent.width > parent.height ? parent.width * 0.6 - parent.spacing : parent.width)
height: (parent.height > parent.width ? parent.height * 0.6 - parent.spacing : parent.height)
selectedDate: new Date()
focus: true
style: CalendarStyle {
dayDelegate: Item {
readonly property color sameMonthDateTextColor: "#444"
readonly property color selectedDateColor: Qt.platformos === "osx" ? "#3778d0" : systemPalette.highlight
readonly property color selectedDateTextColor: "white"
readonly property color differentMonthDateTextColor: "#bbb"
readonly property color invalidDatecolor: "#dddddd"
Rectangle {
anchors.fill: parent
border.color: "#00000000"
color: styleData.date !== undefined && styleData.selected? selectedDateColor : "#00000000"
anchors.margins: styleData.selected ? -1 : 0
}
Label {
id: dayDelegateText
text: styleData.date.getDate()
anchors.centerIn: parent
color: {
var color = invalidDatecolor;
if (styleData.valid) {
color = styleData.visibleMonth ? sameMonthDateTextColor : differentMonthDateTextColor ;
if (styleData.selected) {
color = selectedDateTextColor;
}
}
color ;
}
}
}
}
}
Component {
id: eventListHeader
Row {
id: eventDateRow
width: parent.width
height: eventDayLabel.height
spacing: 10
Label {
id: eventDayLabel
text: calendar.selectedDate.getDate()
font.pointSize: 35
}
Column {
height: eventDayLabel.height
Label {
readonly property var options: { weekday: "long" }
text: Qt.locale().standaloneDayName(calendar.selectedDate.getDay(), Locale.LongFormat)
font.pointSize: 18
}
Label {
text: Qt.locale().standaloneMonthName(calendar.selectedDate.getMonth())
+ calendar.selectedDate.toLocaleDateString(Qt.locale(), " yyyy")
font.pointSize: 12
}
}
}
}
Rectangle {
width: (parent.width > parent.height ? parent.width * 0.4 - parent.spacing : parent.width)
height: (parent.height > parent.width ? parent.height * 0.4 - parent.spacing : parent.height)
ListView {
id:eventListView
spacing: 4
clip: true
header: eventListHeader
anchors.fill: parent
anchors.margins: 10
model: eventModel.eventsForDate(calendar.selectedDate)
delegate: Rectangle {
width: eventListView.width
height: eventItemColumn.height
anchors.horizontalCenter: parent.horizontalCenter
Image {
anchors.top: parent.top
anchors.topMargin: 4
width: 12
height: width
source: "qrc:/images/eventindicator.png"
}
Rectangle {
width: parent.width
height: 1
color: "#eee"
}
Column {
id: eventItemColumn
anchors.left: parent.left
anchors.leftMargin: 20
anchors.right: parent.right
height: timeLabel.height + nameLabel.height + 8
Label {
id: nameLabel
width: parent.width
wrapMode: Text.Wrap
text: modelData.name
}
Label {
id: timeLabel
width: parent.width
wrapMode: Text.Wrap
text: modelData.startDate.toLocaleTimeString(calendar.locale, Locale.ShortFormat)
color: "#aaa"
}
}
}
}
}
}
}
If I understood correctly, you have not yet integrated Firebase to your Qt project?
You can have a look at this plugin for using Firebase with Qt Quick: https://v-play.net/doc/plugin-firebase/
Then you can listen to the reatimeValueChanged signal and update your calendar accordingly.
Related
I have ListView with items like this:
And I want use swipe. But when I add SwipeDelegate I get this:
How I can make swipe elements over the text? I try use z properties, but with z my swipe not animated when opened and I can't close it.
Here my code:
//SomePage.qml:
import QtQuick 2.12
import QtQuick.Controls 2.12
ScrollView {
ListView {
id: someListView
model: SomeItems {}
delegate: SwipeDelegate {
width: someListView.width
Row {
leftPadding: 5
width: parent.width
Image {
id: someImg
height: 38
source: myImage
width: height
}
Column {
leftPadding: 5
width: parent.width - someImg.width - 10
// Name
Text {
id: someName
text: myCount.toString() + " × " + myName
}
// Number
Text {
id: someNumber
text: myNumber.toLocaleString(Qt.locale("ru-RU"), "f", 0)
anchors.right: parent.right
font.pixelSize: 12
rightPadding: 5
}
}
}
swipe.right: Row {
anchors.right: parent.right
height: parent.height
// Delete button
Label {
text: "\ue800"
color: "black"
font.family: fontFontello.name
height: parent.height
padding: 12
verticalAlignment: Label.AlignVCenter
width: this.height
background: Rectangle {
color: "lightblue"
height: parent.height
width: parent.width
MouseArea {
anchors.fill: parent
onClicked: someListView.model.remove(index)
}
}
}
// Hide button
Label {
text: "\ue80a"
color: "black"
font.family: fontFontello.name
height: parent.height
padding: 12
verticalAlignment: Label.AlignVCenter
width: this.height
background: Rectangle {
color: "lightgray"
MouseArea {
anchors.fill: parent
onClicked: {
...
swipe.close()
}
}
}
}
}
}
}
}
The problem is you're adding your text/image on top of the default contentItem instead of inside it. It will look correct if you add your Row to contentItem, like this:
delegate: SwipeDelegate {
contentItem: Row {
...
}
}
I'm Developing an application with Qt 5.13.0 on a Windows 10 professional computer. I need to create a Whatsapp like message view, and to achieve that, I used a GridView component as a base. However, in order to draw the messages correctly, I need to create each GridView row with a different height, depending on the message text.
But to my surprise, I could not find any solution on the internet to achieve that, although I thought it was a simple formality. I tried a solution by myself, which I attached below, however it doesn't work. The issue is that all the rows take the height of the last resized one.
I have no doubt that Qt can do this, unfortunately, I have been looking for days now, and I can not find a solution to this issue. I simply have no idea about how to achieve that. So someone can explain to me how to create a GridView with variable height rows, or if the GridWiew isn't the appropriate component to do that, whcih I should use instead?
Here is my qss file:
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Window 2.12
import QtQuick.Layouts 1.11
Window
{
visible: true
width: 640
height: 480
title: qsTr("Grid view")
color: "#ffffff"
ColumnLayout
{
transformOrigin: Item.Center
spacing: 0
x: 0
y: 0
width: parent.width
height: parent.height
/**
* Grid view item
*/
Component
{
id: itGridItem
Item
{
Column
{
Rectangle
{
property int messageWidth: (gvMessageGrid.cellWidth / 2) - 50
id: itemRect
x: senderIsMyself ? 25 : gvMessageGrid.cellWidth - (25 + messageWidth)
y: 5
width: messageWidth
height: itemTextID.height + 20
color: senderIsMyself ? "#d5d5d5" : "#800b940e"
radius: 5
clip: true
Text
{
id: itemTextID
width: parent.width - 20
text: itemText
renderType: Text.NativeRendering
textFormat: TextEdit.RichText
wrapMode: Text.WordWrap
font.family: "Segoe UI Emoji"
font.pixelSize: 18
anchors.margins: 10
anchors.left: parent.left
anchors.top: parent.top
color: "#101010"
}
onHeightChanged: gvMessageGrid.cellHeight = height + 10
}
}
}
}
/**
* Messages grid view
*/
GridView
{
id: gvMessageGrid
y: 0
Layout.fillHeight: true
flickableDirection: Flickable.VerticalFlick
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
clip: true
contentWidth: 700
contentHeight: 300
cellWidth: contentWidth
cellHeight: 150
model: lmGridModel
delegate: itGridItem
ScrollBar.vertical: ScrollBar
{
visible: true
}
onWidthChanged: cellWidth = width
}
}
}
--- Edited on October 18, 2019
Following the eyllanesc suggestion below, here are 2 screenshots of what I want and what I get:
what I want
what I get
NOTE I'm using several languages, for test purposes, because my application must have international support. However the issue I face has nothing to do with that, i.e it's not an error with text calculation, because 1. The green rect sizes around the text are always correct, and 2. I face the exact same issue with pure English text.
I suggest you to use ListView instead of GridView. You can easily view anything inside full-width list item. Let me share with you my ListDelegate class from an old project. Pay attention to usage of isIncoming property in anchor binding, for example:
anchors {
left: isIncoming? undefined : parent.left
right: isIncoming? parent.right : undefined
}
Full listing:
import QtQuick 2.5
import "units.js" as Units
Rectangle {
id: chatMsgDelegRoot
property bool isIncoming: !model.out
property bool isSelected: model.isSelected
signal clicked(int index)
width: parent.width
height: dlgColumn.height + Units.gu(2.5)
color: "#edf1f5"
Column {
id: dlgColumn
spacing: Units.gu(4)
width: parent.width
anchors.verticalCenter: parent.verticalCenter
BorderImage {
id: borderImage
source: isIncoming?
(isSelected ? "/images/img/MsgOut_Selected_2.png" : "/images/img/MsgOut_2.png") :
(isSelected ? "/images/img/MsgIn_Selected_2.png" : "/images/img/MsgIn_2.png")
// Texture-dependent.
border {
left: isIncoming? 20 : 30
top: 20
right: isIncoming? 30 : 20
bottom: 35
}
anchors {
left: isIncoming? undefined : parent.left
right: isIncoming? parent.right : undefined
}
width: Math.max(content.width + Units.gu(15), Units.gu(21))
height: content.height + Units.gu(9)
MouseArea {
id: msgDelegateMa
anchors.fill: parent
onClicked: chatMsgDelegRoot.clicked(model.index)
}
Loader {
id: content
sourceComponent: model.type === "Text" ? textComponent : controlComponent
anchors {
left: isIncoming? undefined : parent.left
right: isIncoming? parent.right : undefined
leftMargin: Units.gu(10)
rightMargin: Units.gu(10)
top: parent.top
topMargin: Units.gu(4)
}
}
Text {
text: model.date.toTimeString()
font.pointSize: 8
font.italic: true;
color: "lightgrey"
anchors {
left: isIncoming? undefined : parent.left
right: isIncoming? parent.right : undefined
rightMargin: Units.gu(7.5)
leftMargin: Units.gu(7.5)
bottom: parent.bottom
bottomMargin: Units.gu(1)
}
}
} // BorderImage
} // Column
// TODO To separate files.
Component {
id: textComponent
Rectangle {
id: textComponentRoot
color: "#00000000"
width: msgText.paintedWidth
height: msgText.height
Text {
id: msgText
font.pointSize: 10
textFormat: Text.RichText
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
width: chatMsgDelegRoot.width * 0.7
text: model.body
color: isSelected? "white" : "black"
}
}
} // Component
Component {
id: controlComponent
Rectangle {
id: textComponentRoot
color: "#00000000"
width: innerColumn.width
height: innerColumn.height
Column {
id: innerColumn
spacing: Units.gu(1)
Text {
id: fileNameText
font.pointSize: 10
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
width: chatMsgDelegRoot.width * 0.7
elide: Text.ElideRight
text: "File transfer: " + model.body
color: isSelected? "white" : "black"
}
Row {
id: innerRow
anchors.right: parent.right
spacing: Units.gu(1)
SimpleButton {
id: allowBtn
width: Units.gu(15)
height: Units.gu(8)
text: "Allow"
}
SimpleButton {
id: denyBtn
width: Units.gu(15)
height: Units.gu(8)
text: "Deny"
}
}
} // Column
}
} // Component
}
I I´m trying get the click or press event on QML TableView Header.
I have tried on HeaderDelegate create a MouseArea with width, height and anchors.fill from the parent, and get the onClicked or onPressed events, but don´t work.
Example:
MouseArea {
width: parent.width
height: parent.height
anchors.fill: parent
onClicked: {
console.debug("CLICKED: "+styleData.pressed)
console.debug("COLUMN: "+ styleData.column)
}
onPressed: {
console.debug("PRESSED: "+styleData.pressed)
console.debug("COLUMN: "+ styleData.column)
}
}
that doesn't log anything
I also tried use "Connections" on HeaderDelegate, with "target: styleData" and "onPressedChanged"event, and worked, but the "onPressedChanged" get 4 changes in the same time.
Example:
Connections {
target: styleData
onPressedChanged: {
console.debug("PRESSED: "+ styleData.pressed)
console.debug("COLUMN: "+ styleData.column)
}
}
Return:
qml: PRESSED: true
qml: COLUMN: 0
qml: PRESSED: true
qml: COLUMN: 0
qml: PRESSED: false
qml: COLUMN: 0
qml: PRESSED: false
qml: COLUMN: 0
The whole code from TableView:
TableView {
id: tViewEnt
width: parent.width
height: parent.height
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
TableViewColumn {
id: column0
title: "column0"
width: 30
delegate: CheckBox {
style: CheckBoxStyle {
indicator: Rectangle {
//INDICATOR PROPERTIES
}
}
}
}
TableViewColumn {
title: "column1"
role: "column1"
}
TableViewColumn {
title: "column2"
role: "column2"
}
headerDelegate: Rectangle {
height: tViewEnt.height / 15
color: styleData.column===0 ? "#4D4D4D" : "#0077B3"
Rectangle {
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.bottomMargin: 1
anchors.topMargin: 1
width: 1
color: "#333"
}
Text {
text: styleData.value
color: "#CFF"
width: parent.width
height: parent.height
font.pointSize: 18
minimumPointSize: 3
fontSizeMode: Text.Fit
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Connections {
target: styleData
onPressedChanged: {
console.debug("PRESSED: "+ styleData.pressed)
console.debug("COLUMN: "+ styleData.column)
}
}
}
}
So, How do i get the Header Delegate click or pressed event in the right way?
I have a tab bar with a stacklayout like the following:
Rectangle {
id: rect
height: 190
anchors.right: parent.right
anchors.left: parent.left
color: "transparent"
anchors.top: uniqueHandleText.bottom
anchors.topMargin: 100
TabBar {
id: frame
anchors.right: parent.right
anchors.left: parent.left
background: Rectangle {
color: "#737373"
}
x: -hbar.position * width
Repeater {
model: wizard.categories
TabButton {
id: tabData
property bool selected: false
text: modelData.name
width: 200
font.pixelSize: 18
contentItem: Text {
text: tabData.text
font: tabData.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
wrapMode: Text.WordWrap
color: "#FFFFFF"
}
background: Rectangle {
implicitWidth: frame.width
implicitHeight: 180
opacity: enabled ? 1 : 0.3
color: tabData.checked ? "#BD9CBE": "#737373"
}
}
}
}
ScrollBar {
id: hbar
hoverEnabled: true
active: hovered || pressed
orientation: Qt.Horizontal
size: rect.width / frame.width
anchors.left: parent.left
anchors.right: parent.right
anchors.top: frame.bottom
}
Text {
font.pixelSize: 18
text: "Next"
anchors.right: parent.right
visible: frame.x != frame.width ? true: false
}
StackLayout {
id: stack1
anchors.left: parent.left
anchors.right: parent.right
anchors.top: frame.bottom
currentIndex: frame.currentIndex
Repeater {
model: wizard.categories
Item {
id: homeTab
TabBar {
id: homeTabTab
anchors.right: parent.right
anchors.left: parent.left
anchors.top: parent.top
height: 180
background: Rectangle {
color: "#958096"
}
Repeater {
model: modelData.sub_categories
TabButton {
property bool selected: false
id: currentTab
text: modelData.name
width: 200
font.pixelSize: 18
background: Rectangle {
implicitWidth: frame.width
implicitHeight: 180
opacity: enabled ? 1 : 0.3
color: currentTab.checked ? "#958096": "#8D758E"
}
contentItem: Text {
text: currentTab.text
font: currentTab.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
wrapMode: Text.WordWrap
color: "#FFFFFF"
MouseArea {
anchors.fill: parent
onClicked: {
if(currentTab.checked){
currentTab.checked = false
} else {
currentTab.checked = true
}
}
onDoubleClicked: {
currentTab.selected = true
var found = false;
var someText = frame.itemAt(stack1.currentIndex).text;
print(someText)
for(var i = 0; i<wizard.selectedSkills.count; i++){
if(wizard.selectedSkills.get(i).name === someText){
wizard.selectedSkills.get(i).sub_categories.append({"name":currentTab.text});
wizard.skills.push({"name": someText})
found = true;
}
}
if(!found){
print(currentTab.text)
wizard.selectedSkills.append({"name":someText, "sub_categories":[{"name":currentTab.text}]})
}
print(window.selectedSkills)
}
}
}
}
}
}
}
}
}
}
I've tried many different things to add a scrollbar or to figure out how to use the flickable functionality that TabBar has. However, the documentation doesn't specify how it works, it just does. Therefore, they are not accessible (or even rewritteable, to use those properties). I want to add a small indicator like an arrow to specify that there is more elements for ease of navigation on desktop on top of the TabBar functionality.
It doesn't seem like the necessary properties are exposed in order to make this happen the easy way.
However, since this is QML, it means the whole object tree is gaping wide open to introspection, allowing us to establish that the item that does the flicking is the contentItem of a ListView inside the Container the ToolBar inherits. The view happens to be the second visible child, although this is technically "private implementation" that one should not rely on. So it is better to take some extra care to establish whether or not you have the correct object.
ApplicationWindow {
id: main
width: 640
height: 480
visible: true
TabBar {
id: toolbar
width: parent.width
height: 50
Repeater {
model: 10
TabButton {
text: "test " + index
width: 100
}
}
}
Rectangle {
height: 5
width: main.width * (view ? view.visibleArea.widthRatio : toolbar.width / toolbar.contentWidth)
color: "red"
anchors.top: toolbar.bottom
x: view ? (main.width - width) * (view.contentX / (view.contentWidth - view.width)) : 0
}
property ListView view: {
var l = toolbar.visibleChildren.length
while (--l) if ("cacheBuffer" in toolbar.visibleChildren[l]) return toolbar.visibleChildren[l]
return null
}
}
And there you have it. We iterate the tabview children until we find one that has a property cacheBuffer which is fairly unique to ListView, and once we have that, we can access the needed properties. As you see, for the indicator width we can do even without the list view, as the toolbar exposes a contentWidth property, but for the indicator position there is no workaround.
And it works:
I am a beginer and i am not getting how to call canvas.requestPaint() in My QML ,Code is below:
//myTab.qml
TabView {
id: tv
width: parent.width
height: parent.height
antialiasing: true
style: TabViewStyle {
frameOverlap: -1
tab: Rectangle {
color: "Transparent"
implicitWidth: text1.width + 50
implicitHeight: 20
radius: 2
smooth: true
Canvas {
id: canvas1
anchors.fill: parent
width: parent.width
height: parent.height
onPaint: {
styleData.selected ? drawTab(canvas1,"#0C3142") :
drawTab(canvas1,"Transparent") //Some custom JS function to draw a object
}
Text {
id: text1
height: parent.height
verticalAlignment: Text.AlignVCenter
anchors.left : parent.left
anchors.leftMargin: 15
text: styleData.title
color: "white"
}
}
}
frame: Rectangle {
width: parent.width
height: parent.height
color: "Transparent"
border.color:"white"
}
tabBar: Rectangle {
color: "Transparent"
anchors.fill: parent
}
}
Tab {
id: tab1
title: "Tab1"
}
Tab{
id: tab2
title: "Tab2"
}
onCurrentIndexChanged: {
console.log("index changed "+currentIndex)
canvas1.repaint() //ERRROR - not defind canvas1
}
}
When i try to use in onCurrentIndexChanged, I am getting the following error:
ReferenceError: canvas1 is not defined.
Please Suggest.
You have the id canvas1 in another scope, as the tab-style is a Component and the ID therefore not necessarily unique for the TabView. It might be instantiated multiple times.
I have little experience with the TabView, so there might be another solution. I however would declare a signal: refresh in the TabView which I trigger, whenever I want to repaint.
Then I'd use a Connections-element within the Canvas to connect to this signal to execute the repaint
Example:
TabView {
id: tv
width: parent.width
height: parent.height
antialiasing: true
signal refresh // *** DEFINE SIGNAL HERE
style: TabViewStyle {
frameOverlap: -1
tab: Rectangle {
color: "Transparent"
implicitWidth: text1.width + 50
implicitHeight: 20
radius: 2
smooth: true
Canvas {
id: canvas1
anchors.fill: parent
width: parent.width
height: parent.height
onPaint: {
styleData.selected ? drawTab(canvas1,"#0C3142") :
drawTab(canvas1,"Transparent") //Some custom JS function to draw a object
}
function drawTab() { // *** I DONT KNOW WHAT SHOULD BE DONE HERE
console.log('do nothing')
}
// *** CONNECT TO SIGNAL HERE ***
Connections {
target: tv
onRefresh: canvas1.requestPaint() // *** repaint is not a function.
}
Text {
id: text1
height: parent.height
verticalAlignment: Text.AlignVCenter
anchors.left : parent.left
anchors.leftMargin: 15
text: styleData.title
color: "white"
}
}
}
frame: Rectangle {
width: parent.width
height: parent.height
color: "Transparent"
border.color:"white"
}
tabBar: Rectangle {
color: "Transparent"
anchors.fill: parent
}
}
Tab {
id: tab1
title: "Tab1"
}
Tab{
id: tab2
title: "Tab2"
}
onCurrentIndexChanged: {
console.log("index changed "+currentIndex)
refresh() // *** INVOKE SIGNAL HERE
}
}