Reupload
This commit is contained in:
commit
1bb1ade305
36 changed files with 2837 additions and 0 deletions
64
src/qml/components/AnimeCard.qml
Normal file
64
src/qml/components/AnimeCard.qml
Normal file
|
@ -0,0 +1,64 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
Rectangle {
|
||||
property var anime
|
||||
property var title: anime.title
|
||||
property var imageUrl: anime.imageUrl
|
||||
property var cachedImagePath: anime.cachedImage
|
||||
property bool cachedImageFound: true
|
||||
|
||||
property int imageWidth: (grid.width / grid.columns) - ((grid.columnSpacing * grid.columns) / grid.columns)
|
||||
|
||||
Layout.preferredWidth: imageWidth
|
||||
Layout.preferredHeight: imageWidth * 1.5 + 64
|
||||
radius: 16
|
||||
color: "transparent"
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredWidth: parent.parent.width
|
||||
Layout.preferredHeight: parent.parent.height - 64
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
source: cachedImagePath
|
||||
|
||||
signal failedToLoad
|
||||
|
||||
onStatusChanged: {
|
||||
if (status === Image.Error && cachedImageFound === true) {
|
||||
source = imageUrl
|
||||
cachedImageFound = false
|
||||
}
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: mask
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredWidth: parent.parent.width
|
||||
text: title || "[Missing title]"
|
||||
wrapMode: Text.Wrap
|
||||
color: "white"
|
||||
font.pixelSize: 16
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mask
|
||||
width: 500
|
||||
height: 500
|
||||
radius: 16
|
||||
visible: false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
92
src/qml/components/AnimeInfo.qml
Normal file
92
src/qml/components/AnimeInfo.qml
Normal file
|
@ -0,0 +1,92 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Lali.Types
|
||||
|
||||
ColumnLayout {
|
||||
property Anime anime
|
||||
|
||||
anchors.fill: parent
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
onAnimeChanged: {
|
||||
image.source = anime.cachedImage
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
Image {
|
||||
id: image
|
||||
property bool cachedImageFound: true
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
Layout.preferredHeight: 128 * 1.5
|
||||
Layout.preferredWidth: 128
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
source: anime.cachedImage
|
||||
|
||||
signal failedToLoad
|
||||
|
||||
onStatusChanged: {
|
||||
if (status === Image.Error && cachedImageFound === true) {
|
||||
source = anime?.imageUrl
|
||||
cachedImageFound = false
|
||||
}
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: mask
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mask
|
||||
width: 128
|
||||
height: 128
|
||||
radius: 8
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.leftMargin: 16
|
||||
spacing: 32
|
||||
|
||||
// Missing status and genres
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
text: anime?.title || "[Missing title]"
|
||||
wrapMode: Text.Wrap
|
||||
color: "white"
|
||||
font.pixelSize: 24
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
text: `${anime?.startDay}/${anime?.startMonth}/${anime?.startYear} - ${anime?.endDay}/${anime?.endMonth}/${anime?.endYear}\n${anime?.episodeCount} episode${anime?.episodeCount > 1 ? "s" : ""}`
|
||||
wrapMode: Text.Wrap
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { implicitHeight: 16 }
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
text: anime?.description || "[No description given]"
|
||||
wrapMode: Text.Wrap
|
||||
color: "white"
|
||||
}
|
||||
}
|
||||
|
132
src/qml/components/AnimeList.qml
Normal file
132
src/qml/components/AnimeList.qml
Normal file
|
@ -0,0 +1,132 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Lali.Types
|
||||
|
||||
import "../components" as Components
|
||||
|
||||
ScrollView {
|
||||
id: scroller
|
||||
|
||||
property AnimeList list
|
||||
property Anime selectedAnime
|
||||
property string filterByTitle
|
||||
|
||||
anchors.fill: parent
|
||||
clip : true
|
||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
||||
contentHeight: grid.height
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
color: "transparent"
|
||||
|
||||
GridLayout {
|
||||
property int animeCardWidth: 256 // Yes, this is an arbitrary number, "because it looks good on my computer"
|
||||
id: grid
|
||||
columns: grid.width / animeCardWidth
|
||||
rows: 300
|
||||
width: parent.width
|
||||
columnSpacing: 32
|
||||
rowSpacing: 32
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!list)
|
||||
return ;
|
||||
if (filterByTitle) {
|
||||
return list.animes.filter(anime => anime.title.toLowerCase().includes(filterByTitle.toLowerCase()))
|
||||
}
|
||||
return list.animes
|
||||
}
|
||||
|
||||
AnimeCard {
|
||||
anime: modelData
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: (mouse) => {
|
||||
selectedAnime = modelData
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
animeInfo.open()
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
contextMenu.popup()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Autofill blanks
|
||||
Repeater {
|
||||
model: {
|
||||
if (!list) {
|
||||
return []
|
||||
}
|
||||
let blanks = []
|
||||
|
||||
for (let i = list.animes.length; i < grid.columns; i++) {
|
||||
blanks.push(null)
|
||||
}
|
||||
|
||||
return blanks
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: grid.animeCardWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Components.Modal {
|
||||
id: animeInfo
|
||||
width: root.width * 0.75
|
||||
x: (root.width - width) / 2
|
||||
y: 128
|
||||
|
||||
AnimeInfo {
|
||||
anime: selectedAnime
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: contextMenu
|
||||
|
||||
Menu {
|
||||
title: "Add to list"
|
||||
Repeater {
|
||||
model: _app.animeLists.map(x => x.getName())
|
||||
MenuItem {
|
||||
text: modelData
|
||||
onClicked: {
|
||||
_app.addAnimeToList(selectedAnime, modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
title: "Move to list"
|
||||
Repeater {
|
||||
model: _app.animeLists.map(x => x.getName())
|
||||
MenuItem {
|
||||
text: modelData
|
||||
onClicked: {
|
||||
_app.moveAnimeToList(selectedAnime, list.name, modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Remove from list"
|
||||
onClicked: {
|
||||
_app.removeAnimeFromList(selectedAnime, list.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
src/qml/components/Button.qml
Normal file
29
src/qml/components/Button.qml
Normal file
|
@ -0,0 +1,29 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls as QtQuick
|
||||
|
||||
QtQuick.Button {
|
||||
property string textColor: "white"
|
||||
property string bgColor: "#666666"
|
||||
text: "Delete"
|
||||
implicitHeight: 32
|
||||
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
font: parent.font
|
||||
color: textColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 100
|
||||
implicitHeight: 40
|
||||
color: bgColor
|
||||
radius: 4
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
6
src/qml/components/HorizontalSpacer.qml
Normal file
6
src/qml/components/HorizontalSpacer.qml
Normal file
|
@ -0,0 +1,6 @@
|
|||
import QtQuick
|
||||
|
||||
Rectangle {
|
||||
height: 16
|
||||
color: "transparent"
|
||||
}
|
16
src/qml/components/Modal.qml
Normal file
16
src/qml/components/Modal.qml
Normal file
|
@ -0,0 +1,16 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
Dialog {
|
||||
parent: root.contentItem
|
||||
modal: true
|
||||
width: root.width * 0.75
|
||||
x: (root.width - width) / 2
|
||||
y: 128
|
||||
padding: 16
|
||||
|
||||
background: Rectangle {
|
||||
color: "#222222"
|
||||
radius: 16
|
||||
}
|
||||
}
|
54
src/qml/components/SideBarButton.qml
Normal file
54
src/qml/components/SideBarButton.qml
Normal file
|
@ -0,0 +1,54 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
Rectangle {
|
||||
id: button
|
||||
property string text
|
||||
property string image
|
||||
property bool selected
|
||||
signal clicked
|
||||
|
||||
color: ma.hovered || selected ? "#444444" : "transparent"
|
||||
radius: 8
|
||||
|
||||
Image {
|
||||
// anchors.fill: parent
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
|
||||
sourceSize.width: 48
|
||||
sourceSize.height: 48
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: image
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: ma
|
||||
property bool hovered: false
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
button.clicked();
|
||||
}
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
onEntered: {
|
||||
hovered = true
|
||||
}
|
||||
|
||||
onExited: {
|
||||
hovered = false
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: button.text
|
||||
color: "#AAAAAA"
|
||||
font.pixelSize: 14
|
||||
}
|
||||
}
|
12
src/qml/components/TextField.qml
Normal file
12
src/qml/components/TextField.qml
Normal file
|
@ -0,0 +1,12 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls as QtQuick
|
||||
|
||||
QtQuick.TextField {
|
||||
property string textColor: "white"
|
||||
property string bgColor: "#494949"
|
||||
color : textColor
|
||||
background: Rectangle {
|
||||
color: bgColor
|
||||
radius: 4
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue