297 lines
7.9 KiB
QML
297 lines
7.9 KiB
QML
// SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru>
|
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
|
|
|
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15 as Controls
|
|
import QtQuick.Layouts 1.15
|
|
import QtQuick.Particles 2.15
|
|
|
|
import org.kde.kirigami 2.15 as Kirigami
|
|
|
|
Item {
|
|
id: item
|
|
property bool enabled: false
|
|
property int effectInterval: Kirigami.Units.veryLongDuration*10;
|
|
property color darkSnowColor: "grey"
|
|
property bool isThemeDark: Kirigami.Theme.backgroundColor.hslLightness <= darkSnowColor.hslLightness
|
|
|
|
function showConfettiEffect() {
|
|
confettiTimer.start()
|
|
}
|
|
|
|
function showSnowEffect() {
|
|
snowTimer.start()
|
|
}
|
|
|
|
function showFireworksEffect() {
|
|
fireworksTimer.start()
|
|
}
|
|
|
|
// Confetti
|
|
|
|
Timer {
|
|
id: confettiTimer
|
|
interval: item.effectInterval;
|
|
running: false;
|
|
repeat: false;
|
|
triggeredOnStart: true;
|
|
onTriggered: {
|
|
if (item.enabled) {
|
|
confettiSystem.running = !confettiSystem.running
|
|
}
|
|
}
|
|
}
|
|
|
|
ParticleSystem {
|
|
id: confettiSystem
|
|
anchors.fill: parent
|
|
|
|
running: false
|
|
onRunningChanged: {
|
|
if (running) {
|
|
opacity = 1
|
|
} else {
|
|
opacity = 0
|
|
}
|
|
}
|
|
|
|
Behavior on opacity {
|
|
SequentialAnimation {
|
|
NumberAnimation { duration: Kirigami.Units.longDuration }
|
|
}
|
|
}
|
|
|
|
ImageParticle {
|
|
source: "qrc:/imports/NeoChat/Component/confetti.png"
|
|
entryEffect: ImageParticle.Scale
|
|
rotationVariation: 360
|
|
rotationVelocity: 90
|
|
color: Qt.hsla(Math.random(), 0.5, 0.6, 1)
|
|
colorVariation: 1
|
|
}
|
|
|
|
Emitter {
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
top: parent.top
|
|
}
|
|
|
|
sizeVariation: Kirigami.Units.iconSizes.small/2
|
|
lifeSpan: Kirigami.Units.veryLongDuration*10
|
|
size: Kirigami.Units.iconSizes.small
|
|
|
|
velocity: AngleDirection {
|
|
angle: 90
|
|
angleVariation: 42
|
|
magnitude: 500
|
|
}
|
|
}
|
|
}
|
|
|
|
// Snow
|
|
|
|
Timer {
|
|
id: snowTimer
|
|
interval: item.effectInterval;
|
|
running: false;
|
|
repeat: false;
|
|
triggeredOnStart: true;
|
|
onTriggered: {
|
|
if (item.enabled) {
|
|
snowSystem.running = !snowSystem.running
|
|
}
|
|
}
|
|
}
|
|
|
|
ParticleSystem {
|
|
id: snowSystem
|
|
anchors.fill: parent
|
|
|
|
running: false
|
|
onRunningChanged: {
|
|
if (running) {
|
|
opacity = 1
|
|
} else {
|
|
opacity = 0
|
|
}
|
|
}
|
|
|
|
Behavior on opacity {
|
|
SequentialAnimation {
|
|
NumberAnimation { duration: Kirigami.Units.longDuration }
|
|
}
|
|
}
|
|
|
|
ItemParticle {
|
|
delegate: Rectangle {
|
|
width: 10
|
|
height: width
|
|
radius: width
|
|
color: item.isThemeDark ? "white" : darkSnowColor
|
|
scale: Math.random()
|
|
opacity: Math.random()
|
|
}
|
|
}
|
|
|
|
Emitter {
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
top: parent.top
|
|
}
|
|
|
|
sizeVariation: Kirigami.Units.iconSizes.medium
|
|
lifeSpan: Kirigami.Units.veryLongDuration*10
|
|
size: Kirigami.Units.iconSizes.large
|
|
emitRate: 42
|
|
|
|
velocity: AngleDirection {
|
|
angle: 90
|
|
angleVariation: 10
|
|
magnitude: 300
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fireworks
|
|
|
|
Timer {
|
|
id: fireworksTimer
|
|
interval: item.effectInterval;
|
|
running: false;
|
|
repeat: false;
|
|
triggeredOnStart: true;
|
|
onTriggered: {
|
|
if (item.enabled) {
|
|
fireworksInternalTimer.running = !fireworksInternalTimer.running
|
|
}
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: fireworksInternalTimer
|
|
interval: 300
|
|
triggeredOnStart: true
|
|
running: false
|
|
repeat: true
|
|
onTriggered: {
|
|
var x = Math.random() * parent.width
|
|
var y = Math.random() * parent.height
|
|
customEmit(x, y)
|
|
customEmit(x, y)
|
|
customEmit(x, y)
|
|
}
|
|
}
|
|
|
|
ParticleSystem {
|
|
id: fireworksSystem
|
|
anchors.fill: parent
|
|
running: fireworksInternalTimer.running
|
|
onRunningChanged: {
|
|
if (running) {
|
|
opacity = 1
|
|
} else {
|
|
opacity = 0
|
|
}
|
|
}
|
|
|
|
Behavior on opacity {
|
|
SequentialAnimation {
|
|
NumberAnimation { duration: Kirigami.Units.longDuration }
|
|
}
|
|
}
|
|
}
|
|
|
|
ImageParticle {
|
|
id: fireworksParticleA
|
|
system: fireworksSystem
|
|
source: "qrc:/imports/NeoChat/Component/glowdot.png"
|
|
alphaVariation: item.isThemeDark ? 0.1 : 0.1
|
|
alpha: item.isThemeDark ? 0.5 : 1
|
|
groups: ["a"]
|
|
opacity: fireworksSystem.opacity
|
|
entryEffect: ImageParticle.Scale
|
|
rotationVariation: 360
|
|
}
|
|
|
|
ImageParticle {
|
|
system: fireworksSystem
|
|
source: "qrc:/imports/NeoChat/Component/glowdot.png"
|
|
color: item.isThemeDark ? "white" : "gold"
|
|
alphaVariation: item.isThemeDark ? 0.1 : 0.1
|
|
alpha: item.isThemeDark ? 0.5 : 1
|
|
groups: ["light"]
|
|
opacity: fireworksSystem.opacity
|
|
entryEffect: ImageParticle.Scale
|
|
rotationVariation: 360
|
|
}
|
|
|
|
ImageParticle {
|
|
id: fireworksParticleB
|
|
system: fireworksSystem
|
|
source: "qrc:/imports/NeoChat/Component/glowdot.png"
|
|
alphaVariation: item.isThemeDark ? 0.1 : 0.1
|
|
alpha: item.isThemeDark ? 0.5 : 1
|
|
groups: ["b"]
|
|
opacity: fireworksSystem.opacity
|
|
entryEffect: ImageParticle.Scale
|
|
rotationVariation: 360
|
|
}
|
|
|
|
Component {
|
|
id: emitterComp
|
|
Emitter {
|
|
id: container
|
|
property int life: 23
|
|
property real targetX: 0
|
|
property real targetY: 0
|
|
width: 1
|
|
height: 1
|
|
system: fireworksSystem
|
|
size: 16
|
|
endSize: 8
|
|
sizeVariation: 5
|
|
Timer {
|
|
interval: life
|
|
running: true
|
|
onTriggered: {
|
|
container.destroy();
|
|
var randomHue = Math.random()
|
|
var lightness = item.isThemeDark ? 0.8 : 0.7
|
|
fireworksParticleA.color = Qt.hsla(randomHue, 0.8, lightness, 1)
|
|
fireworksParticleB.color = Qt.hsla(1-randomHue, 0.8, lightness, 1)
|
|
}
|
|
}
|
|
velocity: AngleDirection {angleVariation:360; magnitude: 200}
|
|
}
|
|
}
|
|
|
|
function customEmit(x,y) {
|
|
var currentSize = Math.round(Math.random() * 200) + 40
|
|
var currentLifeSpan = Math.round(Math.random() * 1000) + 100
|
|
for (var i=0; i<8; i++) {
|
|
var obj = emitterComp.createObject(parent);
|
|
obj.x = x
|
|
obj.y = y
|
|
obj.targetX = Math.random() * currentSize - currentSize/2 + obj.x
|
|
obj.targetY = Math.random() * currentSize - currentSize/2 + obj.y
|
|
obj.life = Math.round(Math.random() * 23) + 150
|
|
obj.emitRate = Math.round(Math.random() * 32) + 5
|
|
obj.lifeSpan = currentLifeSpan
|
|
const group = Math.round(Math.random() * 3);
|
|
switch (group) {
|
|
case 0:
|
|
obj.group = "light";
|
|
break;
|
|
case 1:
|
|
obj.group = "a";
|
|
break;
|
|
case 2:
|
|
obj.group = "b";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|