yacreader/YACReaderLibrary/qml/FlowView.qml
Igor Kushnir f88af80379 Library: fix InfoComicsView crashes
InfoComicsView constructor is the only function that connects to
FlowView's currentCoverChanged signal. Neither of the slots connected to
this signal handles the argument value index==-1. So when FlowView emits
this signal with index==-1, YACReaderLibrary crashes. Returning early
from either ComicsView::updateInfoForIndex() or
InfoComicsView::setCurrentIndex() when index==-1 is not sufficient - the
crash happens in the other slot then. Let us skip emitting the signal in
FlowView if index==-1 rather than return early from both slots.

Steps to reproduce 1:
1. Launch YACReaderLibrary version that matches the version of the
default library database. Alternatively, select a compatible library
after starting the application.
2. If InfoComicsView is not active, switch to it.
3. (optional) Switch to another comics view out of InfoComicsView.
4. Quit YACReaderLibrary. The application crashes during exit - after
the "YACReaderLibrary closed with exit code : 0" message is printed.

Steps to reproduce 2:
1. Launch a YACReaderLibrary version newer than the version of the
default library database.
2. Click the "No" button in the "Update needed" dialog that pops up.
3. Change between comics views until InfoComicsView becomes active. If
this view was active at the beginning, switch through all the views to
get back to it. At this point YACReaderLibrary crashes.
2021-02-01 11:27:18 +02:00

213 lines
5.8 KiB
QML

import QtQuick 2.3
import QtQuick.Controls 1.4
import QtGraphicalEffects 1.0
import com.yacreader.ComicModel 1.0
Rectangle {
id: main
property url backgroundImageURL;
property real backgroundBlurRadius : 100; //85;
property real backgroundBlurOpacity : 0.25; //0.35;
property bool backgroundBlurVisible : true;
property real additionalBottomSpace : 0;
property real verticalPadding: 12
property real itemsSpacing: 17
signal currentCoverChanged(int index)
Rectangle {
id: background
color: "#2A2A2A"
anchors.fill: backgroundImg
}
Image {
id: backgroundImg
width: parent.width
height: parent.height + additionalBottomSpace
source: backgroundImage
fillMode: Image.PreserveAspectCrop
smooth: true
mipmap: true
asynchronous : true
cache: false //TODO clear cache only when it is needed
opacity: 0
visible: false
}
FastBlur {
anchors.fill: backgroundImg
source: backgroundImg
radius: backgroundBlurRadius
opacity: backgroundBlurOpacity
visible: backgroundBlurVisible
}
anchors.margins: 0
MouseArea {
anchors.fill : list
onWheel: {
if(list.moving)
return;
var ci
if(wheel.angleDelta.y < 0) {
ci = Math.min(list.currentIndex+1, list.count - 1);
}
else if(wheel.angleDelta.y > 0) {
ci = Math.max(0,list.currentIndex-1);
} else {
return;
}
list.currentIndex = ci;
}
}
ListView {
id: list
objectName: "list"
anchors.fill: parent
property int previousIndex;
orientation: Qt.Horizontal
pixelAligned: true
model: comicsList
spacing: itemsSpacing
anchors.leftMargin: Math.floor(verticalPadding * 1.1)
snapMode: ListView.SnapToItem
highlightFollowsCurrentItem: true
highlightRangeMode: ListView.StrictlyEnforceRange
preferredHighlightEnd: 50
highlightMoveDuration: 250
onCurrentIndexChanged: {
if (currentIndex !== -1)
currentCoverChanged(currentIndex);
}
delegate: Component {
//cover
Rectangle {
width: Math.floor((list.height - (verticalPadding * 2)) * 0.65);
height: list.height - (verticalPadding * 2);
anchors.verticalCenter: parent.verticalCenter
color:"transparent"
BusyIndicator {
scale: 0.5
anchors.centerIn: parent
running: coverElement.status === Image.Loading
}
DropShadow {
anchors.fill: coverElement
horizontalOffset: 0
verticalOffset: 0
radius: 6
samples: 17
color: "#BB000000"
source: coverElement
visible: (Qt.platform.os === "osx") ? false : true;
}
Image {
id: coverElement
anchors.fill: parent
source: cover_path
fillMode: Image.PreserveAspectCrop
smooth: true
mipmap: true
asynchronous : true
cache: false
}
//mark
Image {
id: mark
width: 23
height: 23
source: read_column&&show_marks?"tick.png":has_been_opened&&show_marks?"reading.png":""
anchors {right: coverElement.right; top: coverElement.top; topMargin: 9; rightMargin: 9}
asynchronous : true
}
//border
Rectangle {
width: coverElement.width
height: coverElement.height
anchors.centerIn: coverElement
color: "transparent"
border {
color: "#30FFFFFF"
width: 1
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
onDoubleClicked: {
list.currentIndex = index;
currentIndexHelper.selectedItem(index);
}
onReleased: {
list.currentIndex = index;
if(mouse.button === Qt.RightButton) // context menu is requested
{
var coordinates = main.mapFromItem(coverElement,mouseX,mouseY)
contextMenuHelper.requestedContextMenu(Qt.point(coordinates.x,coordinates.y));
}
mouse.accepted = true;
}
}
}
}
focus: true
Keys.onPressed: {
if (event.modifiers & Qt.ControlModifier || event.modifiers & Qt.ShiftModifier)
return;
var ci
if (event.key === Qt.Key_Right || event.key === Qt.Key_Down) {
ci = Math.min(list.currentIndex+1, list.count - 1);
}
else if (event.key === Qt.Key_Left || event.key === Qt.Key_Up) {
ci = Math.max(0,list.currentIndex-1);
} else {
return;
}
list.currentIndex = ci;
event.accepted = true;
}
}
}