mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-29 17:59:21 +00:00
349 lines
12 KiB
QML
349 lines
12 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQuick.Effects
|
|
import QtQuick.Controls.Basic
|
|
|
|
import Linphone
|
|
import QtQml
|
|
import UtilsCpp
|
|
|
|
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
|
|
import 'qrc:/qt/qml/Linphone/view/Style/buttonStyle.js' as ButtonStyle
|
|
|
|
ListView {
|
|
id: mainItem
|
|
property string searchBarText
|
|
property bool hoverEnabled: true
|
|
property var delegateButtons
|
|
property ConferenceInfoGui selectedConference
|
|
property ConferenceInfoGui confToBeSelected: null
|
|
property bool _moveToIndex: false
|
|
property bool loading: false
|
|
property real busyIndicatorSize: Utils.getSizeWithScreenRatio(60)
|
|
|
|
clip: true
|
|
cacheBuffer: height/2
|
|
|
|
spacing: Utils.getSizeWithScreenRatio(8)
|
|
highlightFollowsCurrentItem: false
|
|
|
|
signal meetingDeletionRequested(ConferenceInfoGui confInfo, bool canCancel)
|
|
|
|
function selectIndex(index){
|
|
mainItem.currentIndex = index
|
|
}
|
|
|
|
function resetSelections(){
|
|
mainItem.selectedConference = null
|
|
mainItem.currentIndex = -1
|
|
}
|
|
|
|
function scrollToCurrentDate() {
|
|
currentIndex = -1
|
|
confInfoProxy.selectData(confInfoProxy.getCurrentDateConfInfo())
|
|
moveToCurrentItem()
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
function moveToCurrentItem(){
|
|
if(mainItem.currentIndex >= 0)
|
|
mainItem.positionViewAtIndex(mainItem.currentIndex, ListView.Contain)
|
|
}
|
|
onCurrentItemChanged: {
|
|
moveToCurrentItem()
|
|
if(currentItem) {
|
|
mainItem.selectedConference = currentItem.itemGui
|
|
currentItem.forceActiveFocus()
|
|
}
|
|
}
|
|
// Update position only if we are moving to current item and its position is changing.
|
|
property var _currentItemY: currentItem?.y
|
|
on_CurrentItemYChanged: if(_currentItemY && moveAnimation.running){
|
|
moveToCurrentItem()
|
|
}
|
|
Behavior on contentY{
|
|
NumberAnimation {
|
|
id: moveAnimation
|
|
duration: 500
|
|
easing.type: Easing.OutExpo
|
|
alwaysRunToEnd: true
|
|
}
|
|
}
|
|
//----------------------------------------------------------------
|
|
onAtYEndChanged: if(atYEnd) confInfoProxy.displayMore()
|
|
|
|
|
|
Keys.onPressed: (event)=> {
|
|
if(event.key == Qt.Key_Up) {
|
|
if(currentIndex > 0 ) {
|
|
selectIndex(mainItem.currentIndex-1)
|
|
event.accepted = true
|
|
} else {
|
|
selectIndex(model.count - 1)
|
|
event.accepted = true
|
|
}
|
|
}else if(event.key == Qt.Key_Down){
|
|
if(currentIndex < model.count - 1) {
|
|
selectIndex(currentIndex+1)
|
|
event.accepted = true
|
|
} else {
|
|
selectIndex(0)
|
|
event.accepted = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Let some space for better UI
|
|
footer: Item{height: Utils.getSizeWithScreenRatio(38)}
|
|
|
|
model: ConferenceInfoProxy {
|
|
id: confInfoProxy
|
|
filterText: searchBarText
|
|
filterType: ConferenceInfoProxy.None
|
|
initialDisplayItems: Math.max(20, Math.round(2 * mainItem.height / Utils.getSizeWithScreenRatio(63)))
|
|
displayItemsStep: initialDisplayItems/2
|
|
onModelAboutToBeReset: {
|
|
mainItem.confToBeSelected = mainItem.selectedConference
|
|
mainItem.loading = true
|
|
}
|
|
onModelReset: {
|
|
mainItem.loading = false
|
|
if (mainItem.confToBeSelected) selectData(mainItem.confToBeSelected)
|
|
else selectData(getCurrentDateConfInfo())
|
|
}
|
|
function selectData(confInfoGui){
|
|
mainItem.currentIndex = loadUntil(confInfoGui)
|
|
}
|
|
onConferenceInfoCreated: (confInfoGui) => {
|
|
selectData(confInfoGui)
|
|
}
|
|
onConferenceInfoUpdated: (confInfoGui) => {
|
|
selectData(confInfoGui)
|
|
}
|
|
}
|
|
|
|
BusyIndicator {
|
|
anchors.horizontalCenter: mainItem.horizontalCenter
|
|
visible: mainItem.loading
|
|
height: visible ? mainItem.busyIndicatorSize : 0
|
|
width: mainItem.busyIndicatorSize
|
|
indicatorHeight: mainItem.busyIndicatorSize
|
|
indicatorWidth: mainItem.busyIndicatorSize
|
|
indicatorColor: DefaultStyle.main1_500_main
|
|
}
|
|
|
|
ScrollBar.vertical: ScrollBar {
|
|
id: scrollbar
|
|
rightPadding: Utils.getSizeWithScreenRatio(8)
|
|
|
|
active: true
|
|
interactive: true
|
|
policy: mainItem.contentHeight > mainItem.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
|
|
}
|
|
|
|
section {
|
|
criteria: ViewSection.FullString
|
|
delegate: Text {
|
|
topPadding: Utils.getSizeWithScreenRatio(24)
|
|
bottomPadding: Utils.getSizeWithScreenRatio(16)
|
|
text: section
|
|
height: Utils.getSizeWithScreenRatio(29) + topPadding + bottomPadding
|
|
wrapMode: Text.NoWrap
|
|
font {
|
|
pixelSize: Utils.getSizeWithScreenRatio(20)
|
|
weight: Utils.getSizeWithScreenRatio(800)
|
|
capitalization: Font.Capitalize
|
|
}
|
|
}
|
|
property: '$sectionMonth'
|
|
}
|
|
|
|
delegate: FocusScope {
|
|
id: itemDelegate
|
|
visible: !mainItem.loading
|
|
height: Utils.getSizeWithScreenRatio(63) + (!isFirst && dateDay.visible ? topOffset : 0)
|
|
width: mainItem.width
|
|
enabled: haveModel
|
|
|
|
property var itemGui: $modelData
|
|
// Do not use itemAtIndex because of caching items. Using getAt ensure to have a GUI
|
|
property var previousConfInfoGui : mainItem.model.getAt(index-1)
|
|
property var dateTime: itemGui.core ? itemGui.core.dateTime : UtilsCpp.getCurrentDateTime()
|
|
property string day : UtilsCpp.toDateDayNameString(dateTime)
|
|
property string dateString: UtilsCpp.toDateString(dateTime)
|
|
property string previousDateString: previousConfInfoGui ? UtilsCpp.toDateString(previousConfInfoGui.core ? previousConfInfoGui.core.dateTime : UtilsCpp.getCurrentDateTime()) : ''
|
|
property bool isFirst : ListView.previousSection !== ListView.section
|
|
property real topOffset: (dateDay.visible && !isFirst) ? Utils.getSizeWithScreenRatio(8) : 0
|
|
property var endDateTime: itemGui.core ? itemGui.core.endDateTime : UtilsCpp.getCurrentDateTime()
|
|
property bool haveModel: itemGui.core ? itemGui.core.haveModel : false
|
|
property bool isCanceled: itemGui.core ? itemGui.core.state === LinphoneEnums.ConferenceInfoState.Cancelled : false
|
|
property bool isSelected: itemGui.core == mainItem.selectedConference?.core
|
|
|
|
RowLayout{
|
|
id: delegateIn
|
|
anchors.fill: parent
|
|
anchors.topMargin: !itemDelegate.isFirst && dateDay.visible ? itemDelegate.topOffset : 0
|
|
spacing: 0
|
|
Item{
|
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(32)
|
|
visible: !dateDay.visible
|
|
}
|
|
ColumnLayout {
|
|
id: dateDay
|
|
Layout.fillWidth: false
|
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(32)
|
|
Layout.minimumWidth: Utils.getSizeWithScreenRatio(32)
|
|
Layout.preferredHeight: Utils.getSizeWithScreenRatio(51)
|
|
visible: previousDateString.length == 0 || previousDateString != dateString
|
|
spacing: 0
|
|
Text {
|
|
Layout.preferredHeight: Utils.getSizeWithScreenRatio(19)
|
|
Layout.alignment: Qt.AlignCenter
|
|
text: day.substring(0,3) + '.'
|
|
color: DefaultStyle.main2_500_main
|
|
wrapMode: Text.NoWrap
|
|
elide: Text.ElideNone
|
|
font {
|
|
pixelSize: Typography.p1.pixelSize
|
|
weight: Typography.p1.weight
|
|
capitalization: Font.Capitalize
|
|
}
|
|
}
|
|
Rectangle {
|
|
id: dayNum
|
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(32)
|
|
Layout.preferredHeight: Utils.getSizeWithScreenRatio(32)
|
|
Layout.alignment: Qt.AlignCenter
|
|
radius: height/2
|
|
property var isCurrentDay: UtilsCpp.isCurrentDay(dateTime)
|
|
|
|
color: isCurrentDay ? DefaultStyle.main1_500_main : "transparent"
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
verticalAlignment: Text.AlignVCenter
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: UtilsCpp.toDateDayString(dateTime)
|
|
color: dayNum.isCurrentDay ? DefaultStyle.grey_0 : DefaultStyle.main2_500_main
|
|
wrapMode: Text.NoWrap
|
|
font {
|
|
pixelSize: Utils.getSizeWithScreenRatio(20)
|
|
weight: Utils.getSizeWithScreenRatio(800)
|
|
}
|
|
}
|
|
}
|
|
Item{Layout.fillHeight:true;Layout.fillWidth: true}
|
|
}
|
|
Item {
|
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(265)
|
|
Layout.preferredHeight: Utils.getSizeWithScreenRatio(63)
|
|
Layout.leftMargin: Utils.getSizeWithScreenRatio(23)
|
|
Rectangle {
|
|
id: conferenceInfoDelegate
|
|
anchors.fill: parent
|
|
anchors.rightMargin: 5 // margin to avoid clipping shadows at right
|
|
radius: Utils.getSizeWithScreenRatio(10)
|
|
visible: itemDelegate.haveModel || itemDelegate.activeFocus
|
|
color: itemDelegate.isSelected ? DefaultStyle.main2_200 : DefaultStyle.grey_0 // mainItem.currentIndex === index
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: Utils.getSizeWithScreenRatio(16)
|
|
anchors.rightMargin: Utils.getSizeWithScreenRatio(16)
|
|
anchors.topMargin: Utils.getSizeWithScreenRatio(10)
|
|
anchors.bottomMargin: Utils.getSizeWithScreenRatio(10)
|
|
spacing: Utils.getSizeWithScreenRatio(2)
|
|
visible: itemDelegate.haveModel
|
|
RowLayout {
|
|
spacing: Utils.getSizeWithScreenRatio(8)
|
|
EffectImage {
|
|
imageSource: AppIcons.usersThree
|
|
colorizationColor: DefaultStyle.main2_600
|
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(24)
|
|
Layout.preferredHeight: Utils.getSizeWithScreenRatio(24)
|
|
}
|
|
Text {
|
|
text: itemGui.core? itemGui.core.subject : ""
|
|
Layout.fillWidth: true
|
|
maximumLineCount: 1
|
|
font {
|
|
pixelSize: Typography.p2.pixelSize
|
|
weight: Typography.p2.weight
|
|
}
|
|
}
|
|
}
|
|
Text {
|
|
//: "Réunion annulée"
|
|
text: itemDelegate.isCanceled ? qsTr("meeting_info_cancelled") : UtilsCpp.toDateHourString(dateTime) + " - " + UtilsCpp.toDateHourString(endDateTime)
|
|
color: itemDelegate.isCanceled ? DefaultStyle.danger_500_main : DefaultStyle.main2_500_main
|
|
font {
|
|
pixelSize: Typography.p1.pixelSize
|
|
weight: Typography.p1.weight
|
|
}
|
|
}
|
|
}
|
|
}
|
|
MultiEffect {
|
|
source: conferenceInfoDelegate
|
|
anchors.fill: conferenceInfoDelegate
|
|
visible: itemDelegate.haveModel
|
|
shadowEnabled: true
|
|
shadowBlur: 0.7
|
|
shadowOpacity: 0.2
|
|
}
|
|
Text {
|
|
anchors.fill: parent
|
|
anchors.rightMargin: Utils.getSizeWithScreenRatio(5) // margin to avoid clipping shadows at right
|
|
anchors.leftMargin: Utils.getSizeWithScreenRatio(16)
|
|
verticalAlignment: Text.AlignVCenter
|
|
visible: !itemDelegate.haveModel
|
|
//: "Aucune réunion aujourd'hui"
|
|
text: qsTr("meetings_list_no_meeting_for_today")
|
|
lineHeightMode: Text.FixedHeight
|
|
lineHeight: Utils.getSizeWithScreenRatio(18)
|
|
font {
|
|
pixelSize: Typography.p2.pixelSize
|
|
weight: Typography.p2.weight
|
|
}
|
|
}
|
|
MouseArea {
|
|
id: mouseArea
|
|
hoverEnabled: mainItem.hoverEnabled
|
|
anchors.fill: parent
|
|
cursorShape: itemDelegate.isCanceled ? Qt.ArrowCursor : Qt.PointingHandCursor
|
|
visible: itemDelegate.haveModel
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
onClicked: (mouse) => {
|
|
if (mouse.button === Qt.RightButton) {
|
|
deletePopup.x = mouse.x
|
|
deletePopup.y = mouse.y
|
|
deletePopup.open()
|
|
}
|
|
else if (!itemDelegate.isCanceled) mainItem.selectIndex(index)
|
|
}
|
|
Popup {
|
|
id: deletePopup
|
|
parent: mouseArea
|
|
padding: Utils.getSizeWithScreenRatio(10)
|
|
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnPressOutside | Popup.CloseOnEscape
|
|
contentItem: IconLabelButton {
|
|
style: ButtonStyle.hoveredBackgroundRed
|
|
property var isMeObj: UtilsCpp.isMe(itemDelegate.itemGui?.core?.organizerAddress)
|
|
property bool canCancel: isMeObj && isMeObj.value && itemDelegate.itemGui?.core?.state !== LinphoneEnums.ConferenceInfoState.Cancelled
|
|
icon.source: AppIcons.trashCan
|
|
//: "Supprimer la réunion"
|
|
text: qsTr("meeting_info_delete")
|
|
|
|
onClicked: {
|
|
if (itemDelegate.itemGui) {
|
|
mainItem.meetingDeletionRequested(itemDelegate.itemGui, canCancel)
|
|
deletePopup.close()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|