Merge branch 'main' of github.com:Teoro01/hyprland-quickshell-gui
This commit is contained in:
@@ -77,8 +77,5 @@ PanelWindow {
|
||||
PowerButton {}
|
||||
|
||||
}
|
||||
|
||||
// TODO: Somewhere add Tray
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+127
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
|
||||
ID="$1"
|
||||
|
||||
if [[ -z "$ID" ]]; then
|
||||
echo "Usage: $0 Number"
|
||||
exit 1
|
||||
fi
|
||||
# Command Helper: hyprctl clients -j | jq '.[] | select(.workspace.id == 1)'
|
||||
# Icons: https://www.nerdfonts.com/cheat-sheet
|
||||
declare -A MAP=(
|
||||
# Youtube
|
||||
["Grayjay"]=""
|
||||
# Browser
|
||||
["Ablaze Floorp"]=""
|
||||
["LibreWolf"]=""
|
||||
["midori"]=""
|
||||
["brave-browser"]=""
|
||||
["chromium"]=""
|
||||
# E-Mail
|
||||
["org.mozilla.Thunderbird"]=""
|
||||
# Terminals
|
||||
["kitty"]=""
|
||||
["Alacritty"]=""
|
||||
# Videoplayer
|
||||
["VLC media player"]=""
|
||||
["mpv"]=""
|
||||
["ffplay"]=""
|
||||
# Chats
|
||||
["discord"]=""
|
||||
["vesktop"]=""
|
||||
["Signal"]=""
|
||||
["xyz.chatboxapp.app"]=""
|
||||
# Coding
|
||||
["Visual Studio Code"]=""
|
||||
["VSCodium"]=""
|
||||
["jetbrains-idea"]=""
|
||||
["jetbrains-studio"]=""
|
||||
# Text Editor
|
||||
["mousepad"]=""
|
||||
# Password
|
||||
["org.keepassxc.KeePassXC"]=""
|
||||
["Yubico Authenticator"]=""
|
||||
# Cloud
|
||||
["com.nextcloud.desktopclient.nextcloud"]=""
|
||||
# App Store
|
||||
["Octopi"]=""
|
||||
# Games
|
||||
["steam"]=""
|
||||
["org.prismlauncher.PrismLauncher"]=""
|
||||
["Minecraft* 1.21.11"]=""
|
||||
["game"]=""
|
||||
# Digital Arts
|
||||
["Blender"]=""
|
||||
["Krita"]=""
|
||||
# VM
|
||||
["virt-manager"]=""
|
||||
["VirtualBox Manager"]=""
|
||||
["remote-viewer"]=""
|
||||
# Audio
|
||||
["qpwgraph"]=""
|
||||
["Carla"]=""
|
||||
# Video
|
||||
["com.obsproject.Studio"]=""
|
||||
["hyprland-share-picker"]=""
|
||||
# Document Editor/Viewer
|
||||
["libreoffice-startcenter"]=""
|
||||
["libreoffice-base"]=""
|
||||
["libreoffice-calc"]=""
|
||||
["libreoffice-draw"]=""
|
||||
["libreoffice-impress"]=""
|
||||
["libreoffice-math"]=""
|
||||
["libreoffice-writer"]=""
|
||||
["com.github.flxzt.rnote"]=""
|
||||
["com.github.xournalpp.xournalpp"]=""
|
||||
["qpdfview.local.qpdfview"]=""
|
||||
# Hardware
|
||||
["Mission Center"]=""
|
||||
["QDirStat"]=""
|
||||
["Disks"]=""
|
||||
# File Manager
|
||||
["nemo"]=""
|
||||
["org.gnome.Nautilus"]=""
|
||||
["org.kde.dolphin"]=""
|
||||
["xdg-desktop-portal-gtk"]=""
|
||||
# Settings
|
||||
["nwg-look"]="" # gtk-settings
|
||||
["qt5ct"]=""
|
||||
["qt6ct"]=""
|
||||
["sddm-conf"]=""
|
||||
["blueman-manager"]=""
|
||||
["nm-connection-editor"]=""
|
||||
# Calculator
|
||||
["Calculator"]=""
|
||||
# VPN
|
||||
["Proton VPN"]=""
|
||||
)
|
||||
|
||||
# APPS=$(hyprctl clients -j | jq -r ".[] | select(.workspace.id == $ID) | .initialTitle")
|
||||
|
||||
mapfile -t APPS < <(
|
||||
hyprctl clients -j |
|
||||
jq -r ".[] | select(.workspace.id == $ID) | .initialTitle"
|
||||
)
|
||||
|
||||
mapfile -t APPS_CLASS < <(
|
||||
hyprctl clients -j |
|
||||
jq -r ".[] | select(.workspace.id == $ID) | .initialClass"
|
||||
)
|
||||
|
||||
for i in "${!APPS[@]}"; do
|
||||
if [[ -n "${MAP["${APPS[$i]}"]}" ]]; then
|
||||
APPS[$i]="${MAP["${APPS[$i]}"]}"
|
||||
elif [[ -n "${MAP["${APPS_CLASS[$i]}"]}" ]]; then
|
||||
APPS[$i]="${MAP["${APPS_CLASS[$i]}"]}"
|
||||
else
|
||||
APPS[$i]="${APPS_CLASS[$i]}|${APPS[$i]}"
|
||||
fi
|
||||
done
|
||||
|
||||
# for app in "${APPS[@]}"; do
|
||||
# echo "$app"
|
||||
# done
|
||||
|
||||
RESULT="$ID $(printf '%s ' "${APPS[@]}")"
|
||||
RESULT=${RESULT% } # remove trailing space
|
||||
echo "$RESULT"
|
||||
@@ -4,34 +4,73 @@ import Quickshell.Hyprland
|
||||
import "../../../colors"
|
||||
|
||||
Rectangle { //workspace
|
||||
width: timeDisplay.width + 16
|
||||
width: timeDisplay.width + 8 + dateDisplay.width + 16
|
||||
height: timeDisplay.height + 16
|
||||
radius: 4
|
||||
color: Colors.primaryContainer
|
||||
border.color: Colors.primaryContainer_fg
|
||||
border.width: 2
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: 8
|
||||
anchors.centerIn: parent
|
||||
|
||||
Text {
|
||||
id: timeDisplay
|
||||
Text {
|
||||
id: dateDisplay
|
||||
property string currentDate: ""
|
||||
|
||||
property string currentTime: ""
|
||||
text: currentDate
|
||||
color: Colors.primary
|
||||
font.pixelSize: 18
|
||||
font.family: "Inter, sans-serif"
|
||||
|
||||
text: currentTime
|
||||
color: Colors.primary
|
||||
font.pixelSize: 18
|
||||
font.family: "Inter, sans-serif"
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
//Update time every second
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
var now = new Date()
|
||||
timeDisplay.currentTime = Qt.formatTime(now, "hh:mm:ss")
|
||||
Timer {
|
||||
id: dateTimer
|
||||
interval: 60000
|
||||
running: false
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
var now = new Date()
|
||||
dateDisplay.currentDate = Qt.formatDate(now, "dd.MM.yyyy")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: timeDisplay
|
||||
property string currentTime: ""
|
||||
|
||||
text: currentTime
|
||||
color: Colors.primary
|
||||
font.pixelSize: 18
|
||||
font.family: "Inter, sans-serif"
|
||||
|
||||
Component.onCompleted: {
|
||||
var now = new Date()
|
||||
currentTime = Qt.formatTime(now, "hh:mm:ss")
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
var now = new Date()
|
||||
timeDisplay.currentTime = Qt.formatTime(now, "hh:mm:ss")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
dateDisplay.currentDate = "";
|
||||
dateTimer.running = !dateTimer.running;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import "../../../colors"
|
||||
|
||||
MouseArea {
|
||||
id: networkButton
|
||||
width: output.width + 16
|
||||
width: bar.height
|
||||
height: bar.height
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -19,7 +19,9 @@ MouseArea {
|
||||
anchors.fill: parent
|
||||
color: networkButton.containsMouse ? Colors.tertiary : Qt.alpha(Colors.tertiaryContainer, 0.25)
|
||||
radius: 6
|
||||
width: output.width + 16
|
||||
border.width: 2
|
||||
border.color: networkButton.containsMouse ? Colors.tertiaryContainer_fg
|
||||
: Colors.secondaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: output
|
||||
@@ -37,7 +39,7 @@ MouseArea {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
output.text = this.text.trim()
|
||||
console.log("networkScript output:", this.text.trim())
|
||||
// console.log("networkScript output:", this.text.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+130
-70
@@ -7,85 +7,145 @@ import "../../../colors"
|
||||
|
||||
Row { // Workspace Row
|
||||
id: trayRow
|
||||
spacing: 8
|
||||
spacing: 4
|
||||
|
||||
Repeater {
|
||||
model: SystemTray.items
|
||||
|
||||
Rectangle { //trayItem
|
||||
id: trayItem
|
||||
width: bar.height
|
||||
height: bar.height
|
||||
radius: 4
|
||||
color: "transparent"
|
||||
border.width: 2
|
||||
|
||||
Process {
|
||||
id: steamRunner
|
||||
command: ["steam", "steam://open/main"]
|
||||
running: false
|
||||
Column{
|
||||
Rectangle{
|
||||
width: iconImage.width + 8
|
||||
height: (bar.height-trayItem.height)/2
|
||||
color: "transparent"
|
||||
}
|
||||
Rectangle { //trayItem
|
||||
id: trayItem
|
||||
width: iconImage.width + 8
|
||||
height: iconImage.height + 8
|
||||
radius: 4
|
||||
color: "transparent"
|
||||
border.width: 2
|
||||
|
||||
MouseArea {
|
||||
id: workspaceButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: (mouse) => {
|
||||
switch (mouse.button) {
|
||||
case Qt.LeftButton:
|
||||
if (!modelData.onlyMenu) {
|
||||
modelData.activate()
|
||||
console.log('Activcate function of ', modelData.title)
|
||||
Process {
|
||||
id: steamRunner
|
||||
command: ["steam", "steam://open/main"]
|
||||
running: false
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: workspaceButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: (mouse) => {
|
||||
switch (mouse.button) {
|
||||
case Qt.LeftButton:
|
||||
if (!modelData.onlyMenu) {
|
||||
modelData.activate()
|
||||
console.log('Activcate function of ', modelData.title)
|
||||
}
|
||||
if (modelData.title.trim()==="Steam") {
|
||||
steamRunner.startDetached()
|
||||
}
|
||||
break
|
||||
case Qt.MiddleButton:
|
||||
modelData.secondaryActivate()
|
||||
break
|
||||
// case Qt.RightButton:
|
||||
// if (modelData.hasMenu) {
|
||||
// console.log('Activcate menu of ', modelData.title)
|
||||
// menuAnchor.open()
|
||||
// }
|
||||
// break
|
||||
}
|
||||
if (modelData.title.trim()==="Steam") {
|
||||
steamRunner.startDetached()
|
||||
}
|
||||
break
|
||||
case Qt.MiddleButton:
|
||||
modelData.secondaryActivate()
|
||||
break
|
||||
// case Qt.RightButton:
|
||||
// if (modelData.hasMenu) {
|
||||
// console.log('Activcate menu of ', modelData.title)
|
||||
// menuAnchor.open()
|
||||
}
|
||||
|
||||
// QsMenuAnchor {
|
||||
// id: menuAnchor
|
||||
// menu: modelData.menu
|
||||
// anchor.window: menuHost
|
||||
// }
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: workspaceButton.containsMouse ? Colors.tertiaryContainer
|
||||
: modelData.active ? Colors.primaryContainer
|
||||
: Colors.secondaryContainer
|
||||
border.color: workspaceButton.containsMouse ? Colors.tertiaryContainer_fg
|
||||
: modelData.active ? Colors.primaryContainer_fg
|
||||
: Colors.secondaryContainer_fg
|
||||
radius: 6
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Image { // Image
|
||||
id: iconImage
|
||||
// source: modelData.icon; Does not work for some tray icons
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: bar.height*0.5
|
||||
height: bar.height*0.5
|
||||
|
||||
// Component.onCompleted: {
|
||||
// // Default to the original icon
|
||||
// let src = modelData.icon;
|
||||
// // console.log("########## icon: " + modelData.icon)
|
||||
|
||||
// // Check if there is a "?" in the URL (custom path)
|
||||
// if (src.includes('goxlr')) {
|
||||
// let pathMatch = src.match(/path=([^&]+)/);
|
||||
// if (pathMatch && pathMatch[1]) {
|
||||
|
||||
// let folderPath = pathMatch[1];
|
||||
// // Build a file:// URL pointing to the actual icon file
|
||||
// let segments = folderPath.split('/');
|
||||
// let fileName = segments[segments.length - 1] + "-icon.png";
|
||||
// console.log("########## filename: " + fileName)
|
||||
// console.log("########## icon: " + modelData.icon)
|
||||
// src = "file://" + pathMatch[1] + "/" + fileName;
|
||||
// }
|
||||
// }
|
||||
// break
|
||||
|
||||
// // Set the resolved source
|
||||
// iconImage.source = src;
|
||||
|
||||
// // console.log("Resolved icon source:", src);
|
||||
// }
|
||||
asynchronous: true
|
||||
cache: true
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 10000
|
||||
running: true
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
let src = modelData.icon;
|
||||
// console.log("########## icon: " + modelData.icon)
|
||||
|
||||
// Check if there is a "?" in the URL (custom path)
|
||||
if (src.includes('goxlr')) {
|
||||
let pathMatch = src.match(/path=([^&]+)/);
|
||||
if (pathMatch && pathMatch[1]) {
|
||||
|
||||
let folderPath = pathMatch[1];
|
||||
// Build a file:// URL pointing to the actual icon file
|
||||
let segments = folderPath.split('/');
|
||||
let fileName = segments[segments.length - 1] + "-icon.png";
|
||||
// console.log("########## filename: " + fileName)
|
||||
// console.log("########## icon: " + modelData.icon)
|
||||
src = "file://" + pathMatch[1] + "/" + fileName;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the resolved source
|
||||
iconImage.source = src;
|
||||
}
|
||||
}
|
||||
|
||||
// QsMenuAnchor {
|
||||
// id: menuAnchor
|
||||
// menu: modelData.menu
|
||||
// anchor.window: menuHost
|
||||
// }
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: workspaceButton.containsMouse ? Colors.tertiaryContainer
|
||||
: modelData.active ? Colors.primaryContainer
|
||||
: Colors.secondaryContainer
|
||||
border.color: workspaceButton.containsMouse ? Colors.tertiaryContainer_fg
|
||||
: modelData.active ? Colors.primaryContainer_fg
|
||||
: Colors.secondaryContainer_fg
|
||||
radius: 6
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Image { // Image
|
||||
id: iconImage
|
||||
source: modelData.icon
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: bar.height*0.75
|
||||
height: bar.height*0.75
|
||||
|
||||
asynchronous: true
|
||||
cache: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Io
|
||||
import "../../../colors"
|
||||
|
||||
Row { // Workspace Row
|
||||
@@ -9,48 +10,84 @@ Row { // Workspace Row
|
||||
required property HyprlandMonitor thisMonitor
|
||||
spacing: 8
|
||||
|
||||
// Get infos of Type Unknown
|
||||
// Repeater {
|
||||
// model: Hyprland.workspaces
|
||||
|
||||
// Rectangle {
|
||||
// Component.onCompleted: {
|
||||
// console.log("roles:")
|
||||
// console.log("id:", modelData.id)
|
||||
// console.log("monitor:", modelData.monitor)
|
||||
// console.log("monitorId:", modelData.monitorId)
|
||||
// console.log("name:", modelData.name)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Repeater { // repeats workspaces
|
||||
model: Hyprland.workspaces
|
||||
Loader {
|
||||
active: modelData.monitor === thisMonitor
|
||||
sourceComponent: Rectangle { //workspace
|
||||
// visible: modelData.monitor === thisMonitor
|
||||
width: (workspaceNum.width + 16) < (workspaceNum.height + 8) ? workspaceNum.height + 8 : workspaceNum.width + 16
|
||||
height: workspaceNum.height + 8
|
||||
radius: 4
|
||||
color: workspaceButton.containsMouse ? Colors.tertiaryContainer
|
||||
: modelData.active ? Colors.primaryContainer
|
||||
: Colors.secondaryContainer
|
||||
border.color: workspaceButton.containsMouse ? Colors.tertiaryContainer_fg
|
||||
: modelData.active ? Colors.primaryContainer_fg
|
||||
: Colors.secondaryContainer_fg
|
||||
border.width: 2
|
||||
|
||||
Rectangle { //workspace
|
||||
visible: modelData.monitor === thisMonitor
|
||||
width: workspaceNum.width + 26
|
||||
height: workspaceNum.height + 8
|
||||
radius: 4
|
||||
color: workspaceButton.containsMouse ? Colors.tertiaryContainer
|
||||
: modelData.active ? Colors.primaryContainer
|
||||
: Colors.secondaryContainer
|
||||
border.color: workspaceButton.containsMouse ? Colors.tertiaryContainer_fg
|
||||
: modelData.active ? Colors.primaryContainer_fg
|
||||
: Colors.secondaryContainer_fg
|
||||
border.width: 2
|
||||
|
||||
MouseArea {
|
||||
id: workspaceButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
onClicked: Hyprland.dispatch("workspace " + modelData.id)
|
||||
|
||||
Rectangle {
|
||||
MouseArea {
|
||||
id: workspaceButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
radius: 6
|
||||
onClicked: Hyprland.dispatch("workspace " + modelData.id)
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
radius: 6
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: workspaceNum
|
||||
text: modelData.id
|
||||
anchors.centerIn: parent
|
||||
color: workspaceButton.containsMouse ? Colors.tertiary
|
||||
: modelData.active ? Colors.primary
|
||||
: Colors.secondary
|
||||
font.pixelSize: 18
|
||||
font.family: "Inter, sans-serif"
|
||||
}
|
||||
|
||||
Process {
|
||||
id: workspaceContent
|
||||
command: ["sh", "-c", Quickshell.env("HOME") + "/.config/quickshell/modules/bar/scripts/Apps.sh " + modelData.id]
|
||||
running: true
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
workspaceNum.text = this.text
|
||||
// console.log("workspaceScript output:", this.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: workspaceContent.running = true
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: workspaceNum
|
||||
text: modelData.id
|
||||
anchors.centerIn: parent
|
||||
color: workspaceButton.containsMouse ? Colors.tertiary
|
||||
: modelData.active ? Colors.primary
|
||||
: Colors.secondary
|
||||
font.pixelSize: 18
|
||||
font.family: "Inter, sans-serif"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Text {
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import QtQuick.Controls
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Io
|
||||
import "../../colors"
|
||||
import "./modules"
|
||||
|
||||
PanelWindow {
|
||||
id: learner
|
||||
implicitWidth: screen.width * 0.75
|
||||
implicitHeight: screen.height * 0.5
|
||||
color: "transparent"
|
||||
visible: true
|
||||
focusable: true
|
||||
|
||||
Component.onCompleted: {
|
||||
semiJLoader.all_invisible()
|
||||
semiJLoader.switchModeChooser()
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
id: jLearnerScope
|
||||
focus: true
|
||||
|
||||
Keys.onReleased: function(event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
console.log("Pressed Escape, closing JLearner")
|
||||
jLearnerLoader.active = false
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "lightblue"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 10
|
||||
color: Qt.alpha(Colors.surfaceContainerLowest, 0.5)
|
||||
|
||||
border.width: 2
|
||||
border.color: Colors.outlineVariant
|
||||
|
||||
clip: true
|
||||
|
||||
Rectangle{
|
||||
width: parent.width - 20
|
||||
height: parent.height - 20
|
||||
anchors.centerIn: parent
|
||||
color: "transparent"
|
||||
|
||||
Column {
|
||||
id: learnerWindow
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
id: head
|
||||
width: parent.width
|
||||
height: parent.height * 0.1
|
||||
color: Colors.tertiaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.tertiaryContainer_fg
|
||||
|
||||
Text {
|
||||
text: "Language Learner"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: parent.height * 0.8
|
||||
color: Colors.tertiary
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
id: semiJLoader
|
||||
width: parent.width
|
||||
height: parent.height * 0.9 - parent.spacing
|
||||
|
||||
color: "transparent"
|
||||
|
||||
function all_invisible() {
|
||||
languageChooser.visible = false
|
||||
kanaVoicing.visible = false
|
||||
voicingKana.visible = false
|
||||
learnerResult.visible = false
|
||||
}
|
||||
|
||||
function switchModeChooser() {
|
||||
all_invisible()
|
||||
languageChooser.visible = true
|
||||
languageChooser.start()
|
||||
}
|
||||
|
||||
function switch_KanaVoicing() {
|
||||
all_invisible()
|
||||
kanaVoicing.visible = true
|
||||
kanaVoicing.start()
|
||||
}
|
||||
|
||||
function switch_VoicingKana() {
|
||||
all_invisible()
|
||||
voicingKana.visible = true
|
||||
voicingKana.start()
|
||||
}
|
||||
|
||||
function switchResult(result, mode, results) {
|
||||
all_invisible()
|
||||
console.log("Result: " + result)
|
||||
console.log("Mode: " + mode)
|
||||
learnerResult.visible = true
|
||||
learnerResult.result = result
|
||||
learnerResult.mode = mode
|
||||
learnerResult.results = results
|
||||
learnerResult.start()
|
||||
}
|
||||
|
||||
ModeChooser {
|
||||
id: languageChooser
|
||||
}
|
||||
|
||||
KanaVoicing {
|
||||
id: kanaVoicing
|
||||
}
|
||||
|
||||
VoicingKana {
|
||||
id: voicingKana
|
||||
}
|
||||
|
||||
JLearnerResult {
|
||||
id: learnerResult
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Io
|
||||
|
||||
|
||||
Item { // container, invisible
|
||||
id: jLoader
|
||||
|
||||
Loader {
|
||||
id: jLearnerLoader
|
||||
active: false
|
||||
sourceComponent: JLearner { id: jLearner }
|
||||
}
|
||||
|
||||
GlobalShortcut {
|
||||
name: "JLearner"
|
||||
description: "Open Japanese Learner"
|
||||
|
||||
onPressed: {
|
||||
console.log("Pressed Meta+Shift+J (Hyprland global shortcut)")
|
||||
jLearnerLoader.active = !jLearnerLoader.active
|
||||
}
|
||||
}
|
||||
|
||||
function closeJLearner() {
|
||||
jLearnerLoader.active = false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import "../../../colors"
|
||||
|
||||
Item { // Chooser
|
||||
id: learnerResult
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.margins: 15
|
||||
visible: false
|
||||
|
||||
function switch_KanaVoicing() {
|
||||
parent.switch_KanaVoicing()
|
||||
}
|
||||
|
||||
function start() {
|
||||
}
|
||||
|
||||
property real result: 0
|
||||
property string mode: ""
|
||||
property var results: createResults(10)
|
||||
|
||||
function createResults(n) {
|
||||
var arr = []
|
||||
for (var i = 0; i < n; i++) {
|
||||
arr.push({
|
||||
kana: "あ",
|
||||
correctness: false,
|
||||
answer: "a",
|
||||
correct: "a"
|
||||
})
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
id: learnerResultUpperText
|
||||
color: Colors.primaryContainer
|
||||
width: parent.width
|
||||
height: parent.height * 0.1
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: mainText
|
||||
text: "Ergebnisse:"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: parent.height * 0.6
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: parent.height - learnerResultUpperText.height - parent.spacing
|
||||
spacing: 10
|
||||
Rectangle {
|
||||
width: parent.width * 0.25
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
Column{
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
spacing: 10
|
||||
|
||||
Repeater{
|
||||
model: results
|
||||
|
||||
Row{
|
||||
width: parent.width
|
||||
height: parent.height/10 - parent.spacing * 0.9
|
||||
spacing: 10
|
||||
|
||||
Rectangle{
|
||||
width: parent.height
|
||||
height: parent.height
|
||||
color: Colors.primaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text{
|
||||
text: modelData.kana
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -parent.height * 0.125
|
||||
anchors.horizontalCenterOffset: parent.width * 0.1
|
||||
font.pixelSize: parent.height * 0.8
|
||||
color: modelData.correctness ? "green" : "red"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
width: parent.height
|
||||
height: parent.height
|
||||
color: Colors.primaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Image {
|
||||
source: modelData.correctness ? "../../../colors/icons/correct.svg" : "../../../colors/icons/wrong.svg"
|
||||
anchors.centerIn: parent
|
||||
width: parent.height*0.8
|
||||
height: parent.height*0.8
|
||||
|
||||
smooth: true
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
width: parent.width - parent.height *2 - parent.spacing*2
|
||||
height: parent.height
|
||||
color: Colors.primaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text{
|
||||
text: "[" + modelData.correct + "]"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: 10
|
||||
font.pixelSize: parent.height * 0.8
|
||||
color: modelData.correctness ? "green" : "red"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
width: parent.width * 0.75
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
Column{
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
spacing: 10
|
||||
Row {
|
||||
spacing: 10
|
||||
width: parent.width
|
||||
height: parent.height * 4 / 10 - parent.spacing * 2 / 3
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
width: (parent.width - (learnerLastResultKanaBG.width + learnerLastResultTextBG.width))/2
|
||||
height: parent.height
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: learnerLastResultKanaBG
|
||||
color: results[results.length-1].correctness ? "green" : "red"
|
||||
width: parent.height - parent.spacing
|
||||
height: parent.height
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: learnerLastResultKana
|
||||
text: results[results.length-1].kana
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -parent.height * 0.1
|
||||
font.pixelSize: parent.height * 0.8
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: learnerLastResultTextBG
|
||||
color: results[results.length-1].correctness ? "green" : "red"
|
||||
width: learnerLastResultText.width + 2 * parent.spacing
|
||||
height: parent.height
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: learnerLastResultText
|
||||
text: "[" + results[results.length-1].correct + "]"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: learnerLastResultKana.font.pixelSize/2
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: learnerResultTextBG
|
||||
color: Colors.primaryContainer
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width
|
||||
height: parent.height * 3 / 10 - parent.spacing * 2 / 3
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: learnerResultText
|
||||
text: result*100 + "% Richtig"
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: parent.height * 3 / 10 - parent.spacing * 2 / 3
|
||||
spacing: 10
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
width: parent.width / 2 - parent.spacing
|
||||
height: parent.height
|
||||
|
||||
onClicked: {
|
||||
console.log("Choosing White Window")
|
||||
mode === "KanaVoicing" ? learnerResult.parent.switch_KanaVoicing() : learnerResult.parent.switch_VoicingKana()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
|
||||
|
||||
Text {
|
||||
text: "Again"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
|
||||
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
width: parent.width / 2 - parent.spacing
|
||||
height: parent.height
|
||||
|
||||
onClicked: {
|
||||
console.log("Choosing Black Window")
|
||||
learnerResult.parent.switchModeChooser()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
|
||||
|
||||
Text {
|
||||
text: "Menu"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
|
||||
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
property var kana: [
|
||||
{ hira: "あ", voice: ["a"], known: true },
|
||||
{ hira: "い", voice: ["i"], known: true },
|
||||
{ hira: 'う', voice: ["u"], known: true },
|
||||
{ hira: 'え', voice: ["e"], known: true },
|
||||
{ hira: 'お', voice: ["o"], known: true },
|
||||
{ hira: 'か', voice: ["ka"], known: true },
|
||||
{ hira: 'が', voice: ["ga"], known: true },
|
||||
{ hira: 'き', voice: ["ki"], known: true },
|
||||
{ hira: 'ぎ', voice: ["gi"], known: true },
|
||||
{ hira: 'く', voice: ["ku"], known: true },
|
||||
{ hira: 'ぐ', voice: ["gu"], known: true },
|
||||
{ hira: 'け', voice: ["ke"], known: true },
|
||||
{ hira: 'げ', voice: ["ge"], known: true },
|
||||
{ hira: 'こ', voice: ["ko"], known: true },
|
||||
{ hira: 'ご', voice: ["go"], known: true },
|
||||
{ hira: 'さ', voice: ["sa"], known: true },
|
||||
{ hira: 'ざ', voice: ["za"], known: true },
|
||||
{ hira: 'し', voice: ["si", "shi"], known: true },
|
||||
{ hira: 'じ', voice: ["zi", "ji"], known: true },
|
||||
{ hira: 'す', voice: ["su"], known: true },
|
||||
{ hira: 'ず', voice: ["zu"], known: true },
|
||||
{ hira: 'せ', voice: ["se"], known: true },
|
||||
{ hira: 'ぜ', voice: ["ze"], known: true },
|
||||
{ hira: 'そ', voice: ["so"], known: true },
|
||||
{ hira: 'ぞ', voice: ["zo"], known: true },
|
||||
{ hira: 'た', voice: ["ta"], known: true },
|
||||
{ hira: 'だ', voice: ["da"], known: true },
|
||||
{ hira: 'ち', voice: ["ti", "shi"], known: true },
|
||||
{ hira: 'ぢ', voice: ["di", "ji"], known: true },
|
||||
{ hira: 'つ', voice: ["tu", "tsu"], known: true },
|
||||
{ hira: 'づ', voice: ["du", "zu"], known: true },
|
||||
{ hira: 'て', voice: ["te"], known: true },
|
||||
{ hira: 'で', voice: ["de"], known: true },
|
||||
{ hira: 'と', voice: ["to"], known: true },
|
||||
{ hira: 'ど', voice: ["do"], known: true },
|
||||
{ hira: 'な', voice: ["na"], known: true },
|
||||
{ hira: 'に', voice: ["ni"], known: true },
|
||||
{ hira: 'ぬ', voice: ["nu"], known: false },
|
||||
{ hira: 'ね', voice: ["ne"], known: false },
|
||||
{ hira: 'の', voice: ["no"], known: false },
|
||||
{ hira: 'は', voice: ["ha"], known: false },
|
||||
{ hira: 'ば', voice: ["ba"], known: false },
|
||||
{ hira: 'ぱ', voice: ["pa"], known: false },
|
||||
{ hira: 'ひ', voice: ["hi"], known: false },
|
||||
{ hira: 'び', voice: ["bi"], known: false },
|
||||
{ hira: 'ぴ', voice: ["pi"], known: false },
|
||||
{ hira: 'ふ', voice: ["hu"], known: false },
|
||||
{ hira: 'ぶ', voice: ["bu"], known: false },
|
||||
{ hira: 'ぷ', voice: ["pu"], known: false },
|
||||
{ hira: 'へ', voice: ["he"], known: false },
|
||||
{ hira: 'べ', voice: ["be"], known: false },
|
||||
{ hira: 'ぺ', voice: ["pe"], known: false },
|
||||
{ hira: 'ほ', voice: ["ho"], known: false },
|
||||
{ hira: 'ぼ', voice: ["bo"], known: false },
|
||||
{ hira: 'ぽ', voice: ["po"], known: false },
|
||||
{ hira: 'ま', voice: ["ma"], known: false },
|
||||
{ hira: 'み', voice: ["mi"], known: false },
|
||||
{ hira: 'む', voice: ["mu"], known: false },
|
||||
{ hira: 'め', voice: ["me"], known: false },
|
||||
{ hira: 'も', voice: ["mo"], known: false },
|
||||
{ hira: 'や', voice: ["ya"], known: false },
|
||||
{ hira: 'ゆ', voice: ["yu"], known: false },
|
||||
{ hira: 'よ', voice: ["yo"], known: false },
|
||||
{ hira: 'ら', voice: ["ra"], known: false },
|
||||
{ hira: 'り', voice: ["ri"], known: false },
|
||||
{ hira: 'る', voice: ["ru"], known: false },
|
||||
{ hira: 'れ', voice: ["re"], known: false },
|
||||
{ hira: 'ろ', voice: ["ro"], known: false },
|
||||
{ hira: 'わ', voice: ["wa"], known: false },
|
||||
{ hira: 'ゐ', voice: ["wi"], known: false },
|
||||
{ hira: 'ゑ', voice: ["we"], known: false },
|
||||
{ hira: 'を', voice: ["wo"], known: false },
|
||||
{ hira: 'ん', voice: ["n"], known: true },
|
||||
{ hira: 'ゔ', voice: ["vu"], known: false }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import "../../../colors"
|
||||
|
||||
Item { // Kana_Try
|
||||
id: kanaVoicing
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.margins: 15
|
||||
visible: false
|
||||
|
||||
// Component.onCompleted: {
|
||||
// randomKnownKana()
|
||||
// }
|
||||
|
||||
function start() {
|
||||
kanaVoicingAnswer.focus = true
|
||||
roundNum = 0
|
||||
randomKnownKana()
|
||||
}
|
||||
|
||||
KanaData {
|
||||
id: kanaData
|
||||
}
|
||||
|
||||
property var currentKana: []
|
||||
|
||||
property int roundNum: 0
|
||||
property int correct: 0
|
||||
property int maxRoundNum: 10
|
||||
|
||||
property var pastKana: []
|
||||
property var pastCorrectness: []
|
||||
|
||||
function endRounds() {
|
||||
kanaVoicingAnswer.focus = false
|
||||
jLearnerScope.focus = true
|
||||
console.log("Switching back")
|
||||
parent.switchResult(correct/maxRoundNum, "KanaVoicing", pastCorrectness)
|
||||
pastKana = []
|
||||
pastCorrectness = []
|
||||
correct = 0
|
||||
kanaVoicingAnswer.placeholderText = "Type Voicing..."
|
||||
kanaVoicingAnswerBackground.color = kanaVoicingAnswer.activeFocus ? Colors.tertiary_fg : Colors.primary_fg
|
||||
}
|
||||
|
||||
function randomKana() {
|
||||
if (roundNum >= maxRoundNum) {
|
||||
endRounds()
|
||||
}
|
||||
var list = kanaData.kana
|
||||
currentKana = list[Math.floor(Math.random() * list.length)]
|
||||
if (knownList.length > maxRoundNum) {
|
||||
while (pastKana.includes(currentKana)) {
|
||||
currentKana = list[Math.floor(Math.random() * list.length)]
|
||||
}
|
||||
}
|
||||
pastKana.push(currentKana)
|
||||
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
|
||||
roundNum = roundNum + 1
|
||||
}
|
||||
|
||||
function randomKnownKana() {
|
||||
if (roundNum >= maxRoundNum) {
|
||||
endRounds()
|
||||
}
|
||||
var knownList = kanaData.kana.filter(k => k.known)
|
||||
currentKana = knownList[Math.floor(Math.random() * knownList.length)]
|
||||
if (knownList.length > maxRoundNum) {
|
||||
while (pastKana.includes(currentKana)) {
|
||||
currentKana = knownList[Math.floor(Math.random() * knownList.length)]
|
||||
}
|
||||
}
|
||||
pastKana.push(currentKana)
|
||||
console.log("Round Num: " + roundNum + " - Choosing Kana: " + currentKana.hira)
|
||||
roundNum = roundNum + 1
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
id: kanaVoicingTextRectangale
|
||||
color: Colors.primaryContainer
|
||||
width: kanaVoicingText.width + 20
|
||||
height: parent.height * 0.1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: kanaVoicingText
|
||||
text: "Im Spiel - Runde: " + kanaVoicing.roundNum
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: parent.height * 0.6
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: kanaVoicingKanaRectangle
|
||||
color: Colors.primaryContainer
|
||||
height: (parent.height - kanaVoicingTextRectangale.height)*0.75
|
||||
width: height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: kanaVoicingKana
|
||||
text: typeof kanaVoicing.currentKana.hira === "undefined" ? "" : kanaVoicing.currentKana.hira
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: kanaVoicingAnswer
|
||||
|
||||
placeholderText: "Type Voicing..."
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
width: parent.width/2
|
||||
height: (parent.height - kanaVoicingTextRectangale.height)*0.25 - parent.spacing*2
|
||||
|
||||
font.pixelSize: height * 0.8
|
||||
|
||||
color: Colors.secondary_fg
|
||||
placeholderTextColor: Colors.secondary
|
||||
|
||||
background: Rectangle {
|
||||
id: kanaVoicingAnswerBackground
|
||||
radius: 10
|
||||
color: kanaVoicingAnswer.activeFocus ? Colors.secondaryContainer : Colors.secondaryContainer_fg
|
||||
border.color: kanaVoicingAnswer.activeFocus ? Colors.secondaryContainer_fg : Colors.secondaryContainer
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
Keys.onReleased: function(event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
console.log("Escape pressed inside TextField")
|
||||
console.log("Pressed Escape, closing JLearner")
|
||||
jLearnerLoader.active = false
|
||||
}
|
||||
}
|
||||
|
||||
onAccepted: function(event) {
|
||||
console.log("Enter pressed inside TextField")
|
||||
if (kanaVoicing.currentKana.voice.includes(kanaVoicingAnswer.text.toLowerCase())){
|
||||
console.log("Correct")
|
||||
kanaVoicingAnswer.text = ""
|
||||
kanaVoicingAnswer.placeholderText = "[" + kanaVoicing.currentKana.voice + "]"
|
||||
kanaVoicingAnswerBackground.color = "green"
|
||||
kanaVoicing.correct = kanaVoicing.correct + 1
|
||||
pastCorrectness.push({
|
||||
kana: kanaVoicing.currentKana.hira,
|
||||
correctness: true,
|
||||
answer: kanaVoicingAnswer.text.toLowerCase(),
|
||||
correct: kanaVoicing.currentKana.voice.join("|")
|
||||
})
|
||||
} else {
|
||||
console.log("Wrong: [" + currentKana.voice + "]")
|
||||
kanaVoicingAnswer.text = ""
|
||||
kanaVoicingAnswerBackground.color = "red"
|
||||
kanaVoicingAnswer.placeholderText = "[" + kanaVoicing.currentKana.voice + "]"
|
||||
pastCorrectness.push({
|
||||
kana: kanaVoicing.currentKana.hira,
|
||||
correctness: false,
|
||||
answer: kanaVoicingAnswer.text.toLowerCase(),
|
||||
correct: kanaVoicing.currentKana.voice.join("|")
|
||||
})
|
||||
}
|
||||
randomKnownKana()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import "../../../colors"
|
||||
|
||||
Item { // Chooser
|
||||
id: languageChooser
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.margins: 15
|
||||
visible: false
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
id: modeChooserUpperText
|
||||
color: Colors.primaryContainer
|
||||
width: mainText.width + 20
|
||||
height: parent.height * 0.1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: mainText
|
||||
text: "Wähle ein Modus:"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: parent.height * 0.6
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: parent.height - modeChooserUpperText.height - parent.spacing
|
||||
spacing: 10
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
width: (parent.width - parent.spacing) / 2
|
||||
height: parent.height
|
||||
|
||||
onClicked: {
|
||||
console.log("Choosing White Window")
|
||||
languageChooser.parent.switch_KanaVoicing()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
|
||||
|
||||
Text {
|
||||
text: "Kana to Voicing"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
|
||||
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
width: (parent.width - parent.spacing) / 2
|
||||
height: parent.height
|
||||
|
||||
onClicked: {
|
||||
console.log("Choosing Black Window")
|
||||
languageChooser.parent.switch_VoicingKana()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
|
||||
|
||||
Text {
|
||||
text: "Voicing to Kana"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Math.min(parent.width / text.length * 1.2, parent.height * 0.8)
|
||||
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import "../../../colors"
|
||||
|
||||
Item { // Kana_Try
|
||||
id: voicingKana
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.margins: 15
|
||||
visible: false
|
||||
|
||||
// Component.onCompleted: {
|
||||
// randomKnownKana()
|
||||
// }
|
||||
|
||||
function start() {
|
||||
roundNum = 0
|
||||
new_round()
|
||||
}
|
||||
|
||||
KanaData {
|
||||
id: kanaData
|
||||
}
|
||||
|
||||
property int roundNum: 0
|
||||
property int correct: 0
|
||||
property int maxRoundNum: 10
|
||||
|
||||
property var pastKana: []
|
||||
property var pastCorrectness: []
|
||||
|
||||
property var kanaArray: createResults(6)
|
||||
property var targetKana: kanaArray[Math.floor(Math.random() * kanaArray.length)]
|
||||
|
||||
function createResults(n) {
|
||||
var arr = []
|
||||
for (var i = 0; i < n; i++) {
|
||||
arr.push({ hira: "あ", voice: ["a"], known: true })
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
function new_round() {
|
||||
roundNum = roundNum + 1
|
||||
kanaArray = gemerateKanaArray()
|
||||
targetKana = kanaArray[Math.floor(Math.random() * kanaArray.length)]
|
||||
console.log("Round Num: " + roundNum + " - Choosing Kana: " + targetKana.hira)
|
||||
pastKana.push(targetKana)
|
||||
}
|
||||
|
||||
function gemerateKanaArray() {
|
||||
var arr = []
|
||||
for (var i = 0; i < 6; i++) {
|
||||
arr.push(randomKnownKana(arr))
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
function randomKana(arr) {
|
||||
if (roundNum > maxRoundNum) {
|
||||
endRounds()
|
||||
}
|
||||
var list = kanaData.kana
|
||||
var newKana = list[Math.floor(Math.random() * list.length)]
|
||||
|
||||
var arrExists = Array.isArray(arr)
|
||||
|
||||
if (knownList.length > maxRoundNum + 6) {
|
||||
if (arrExists) {
|
||||
while (pastKana.includes(newKana) || arr.includes(newKana)) {
|
||||
newKana = list[Math.floor(Math.random() * list.length)]
|
||||
}
|
||||
} else{
|
||||
while (pastKana.includes(newKana)){
|
||||
newKana = list[Math.floor(Math.random() * list.length)]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (arrExists) {
|
||||
while (arr.includes(newKana)) {
|
||||
newKana = list[Math.floor(Math.random() * list.length)]
|
||||
}
|
||||
}
|
||||
}
|
||||
kanaArray.push(newKana)
|
||||
return newKana
|
||||
}
|
||||
|
||||
function randomKnownKana(arr) {
|
||||
if (roundNum > maxRoundNum) {
|
||||
endRounds()
|
||||
}
|
||||
var knownList = kanaData.kana.filter(k => k.known)
|
||||
var newKana = knownList[Math.floor(Math.random() * knownList.length)]
|
||||
|
||||
var arrExists = Array.isArray(arr)
|
||||
|
||||
if (knownList.length > maxRoundNum + 6) {
|
||||
if (arrExists) {
|
||||
while (pastKana.includes(newKana) || arr.includes(newKana)) {
|
||||
newKana = knownList[Math.floor(Math.random() * knownList.length)]
|
||||
}
|
||||
} else{
|
||||
while (pastKana.includes(newKana)){
|
||||
newKana = knownList[Math.floor(Math.random() * knownList.length)]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (arrExists) {
|
||||
while (arr.includes(newKana)) {
|
||||
newKana = knownList[Math.floor(Math.random() * knownList.length)]
|
||||
}
|
||||
}
|
||||
}
|
||||
return newKana
|
||||
}
|
||||
|
||||
function endRounds() {
|
||||
console.log("Switching back")
|
||||
roundNum = 0
|
||||
parent.switchResult(correct/maxRoundNum, "VoicingKana", pastCorrectness)
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
id: voicingKanaTextRectangale
|
||||
color: Colors.primaryContainer
|
||||
width: mainText.width + 20
|
||||
height: parent.height * 0.1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: mainText
|
||||
text: "Runde: " + roundNum + " - [" + targetKana.voice.join("|") + "]:"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: parent.height * 0.6
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
width: parent.width
|
||||
height: parent.height - voicingKanaTextRectangale.height - voicingKanaResultRectangale.height - parent.spacing * 2
|
||||
color: "transparent"
|
||||
Grid {
|
||||
id: grid
|
||||
anchors.fill: parent
|
||||
columns: 3
|
||||
spacing: 10
|
||||
|
||||
property int rows: 2
|
||||
|
||||
// calculate cell width and height based on parent size, spacing, and number of columns/rows
|
||||
property real cellWidth: (width - (columns - 1) * spacing) / columns
|
||||
property real cellHeight: (height - (rows - 1) * spacing) / rows
|
||||
|
||||
Repeater {
|
||||
model: kanaArray
|
||||
MouseArea {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
width: grid.cellWidth
|
||||
height: grid.cellHeight
|
||||
|
||||
onClicked: {
|
||||
console.log("Choose a Kana: " + modelData.hira)
|
||||
if (modelData.hira === targetKana.hira) {
|
||||
console.log("Correct")
|
||||
correct = correct + 1
|
||||
voicingKanaResultRectangale.color = "green"
|
||||
} else {
|
||||
console.log("Wrong: [" + targetKana.hira + "]")
|
||||
voicingKanaResultRectangale.color = "red"
|
||||
}
|
||||
pastCorrectness.push({
|
||||
kana: targetKana.hira,
|
||||
correctness: modelData.hira === targetKana.hira,
|
||||
answer: modelData.hira,
|
||||
correct: targetKana.voice.join("|")
|
||||
})
|
||||
voicingKanaResult.text = "Letzte Runde: " + targetKana.hira + ": " + "[" + targetKana.voice.join("|") + "]"
|
||||
new_round()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: parent.containsMouse ? Colors.secondaryContainer_fg : Colors.secondaryContainer
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: parent.containsMouse ? Colors.secondaryContainer : Colors.secondaryContainer_fg
|
||||
|
||||
Text{
|
||||
text: modelData.hira
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -parent.height * 0.1
|
||||
font.pixelSize: parent.height * 0.8
|
||||
color: parent.parent.containsMouse ? Colors.secondary_fg : Colors.secondary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: voicingKanaResultRectangale
|
||||
color: Colors.primaryContainer
|
||||
width: voicingKanaResult.width + 20
|
||||
height: parent.height * 0.1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
radius: 10
|
||||
border.width: 2
|
||||
border.color: Colors.primaryContainer_fg
|
||||
|
||||
Text {
|
||||
id: voicingKanaResult
|
||||
text: "Wähle das richtige Zeichen"
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: parent.height * 0.6
|
||||
color: Colors.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,23 @@ PanelWindow {
|
||||
visible: true
|
||||
focusable: true
|
||||
|
||||
FocusScope {
|
||||
id: pickerScope
|
||||
focus: true
|
||||
|
||||
Keys.onReleased: function(event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
console.log("Pressed Escape, closing Wallpaper Picker")
|
||||
wallpaperLoader.active = false
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "lightblue"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 10
|
||||
@@ -42,11 +59,22 @@ PanelWindow {
|
||||
background: Rectangle {
|
||||
|
||||
radius: 12
|
||||
color: "#2b2b2b"
|
||||
color: filterText.activeFocus ? Colors.tertiary_fg : Colors.primary_fg
|
||||
border.color: filterText.activeFocus ? Colors.tertiary : Colors.primary
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
Keys.onReleased: {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
console.log("Escape pressed inside TextField")
|
||||
console.log("Pressed Escape, closing Wallpaper Picker")
|
||||
// wallpaperLoader.active = false
|
||||
filterText.text = ""
|
||||
filterText.focus = false
|
||||
event.accepted = true
|
||||
pickerScope.focus = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ Item { // container, invisible
|
||||
onPressed: {
|
||||
// generateThumbs.startDetached()
|
||||
generateThumbs.running = true
|
||||
wallpaperLoader.active = !wallpaperLoader.active
|
||||
console.log("Pressed Meta+Shift+W (Hyprland global shortcut)")
|
||||
wallpaperLoader.active = !wallpaperLoader.active
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,9 @@ if [ ! -d $THUMB_DIR ]; then
|
||||
mkdir -p $THUMB_DIR;
|
||||
fi
|
||||
|
||||
|
||||
shopt -s nullglob
|
||||
files=( "$THUMB_DIR"/*.jpg "$THUMB_DIR"/*.jpeg "$THUMB_DIR"/*.png )
|
||||
# printf ' %s\n' "${files[@]}"
|
||||
# Make sure the thumb directory exists
|
||||
mkdir -p "$THUMB_DIR"
|
||||
|
||||
@@ -19,6 +21,28 @@ MAX_DIM=300
|
||||
|
||||
num=0
|
||||
|
||||
remove_from_array() {
|
||||
local -n arr=$1
|
||||
local elem=$2
|
||||
local result=()
|
||||
|
||||
# echo "=== Removing element: '$elem' ==="
|
||||
# echo "Original array has ${#arr[@]} elements"
|
||||
|
||||
for item in "${arr[@]}"; do
|
||||
if [[ "$item" != "$elem" ]]; then
|
||||
result+=( "$item" )
|
||||
# echo "Keeping: '$item'"
|
||||
# else
|
||||
# echo "Removing: '$item'"
|
||||
fi
|
||||
done
|
||||
|
||||
arr=( "${result[@]}" )
|
||||
# echo "New array has ${#arr[@]} elements"
|
||||
# echo "-----------------------------------"
|
||||
}
|
||||
|
||||
# Process each image
|
||||
for img in "$WALLPAPER_DIR"/*.{jpg,jpeg,png}; do
|
||||
# Skip if no files match
|
||||
@@ -26,19 +50,44 @@ for img in "$WALLPAPER_DIR"/*.{jpg,jpeg,png}; do
|
||||
|
||||
# Get just the filename
|
||||
fname=$(basename "$img")
|
||||
name="${fname%.*}"
|
||||
ext="${fname##*.}"
|
||||
|
||||
# no magick file:
|
||||
temp_image_name="$THUMB_DIR/${name}_tmp.${ext}"
|
||||
|
||||
# Output path
|
||||
thumb="$THUMB_DIR/$fname"
|
||||
|
||||
|
||||
# If thumbnail already exists and is newer than the original, skip
|
||||
if [ -f "$thumb" ] && [ "$thumb" -nt "$img" ]; then
|
||||
remove_from_array files "$thumb"
|
||||
continue
|
||||
fi
|
||||
|
||||
num+=1
|
||||
|
||||
# Generate thumbnail using ImageMagick
|
||||
magick "$img" -resize "${MAX_DIM}x${MAX_DIM}" "$thumb"
|
||||
if [ -x "/usr/bin/magick" ]; then
|
||||
magick "$img" -resize "${MAX_DIM}x${MAX_DIM}" "$thumb"
|
||||
rm $temp_image_name
|
||||
else
|
||||
if [ -f "$temp_image_name" ] && [ "$temp_image_name" -nt "$img" ]; then
|
||||
continue
|
||||
fi
|
||||
cp $img $temp_image_name
|
||||
fi
|
||||
remove_from_array files "$thumb"
|
||||
done
|
||||
|
||||
# echo ""
|
||||
|
||||
# printf ' %s\n' "${files[@]}"
|
||||
|
||||
for img in $files; do
|
||||
# echo "$img"
|
||||
rm $img
|
||||
done
|
||||
|
||||
echo "$num Thumbnails generated in $THUMB_DIR"
|
||||
@@ -42,10 +42,15 @@ elif [ -x "/usr/bin/hyprpaper" ]; then
|
||||
sleep 0.2
|
||||
echo "daemon started"
|
||||
fi
|
||||
sed -i "3s|path = .*|path = ${image}|" ~/.config/hypr/hyprpaper.conf
|
||||
hyprctl hyprpaper wallpaper ", $image"
|
||||
fi
|
||||
|
||||
matugen image $image --mode dark
|
||||
if [ -x "/usr/bin/matugen" ]; then
|
||||
matugen image $image --mode dark
|
||||
else
|
||||
cp $HOME/.config/quickshell/colors/example_colors.qml $HOME/.config/quickshell/colors/Colors.qml
|
||||
fi
|
||||
|
||||
### Blured Wallpaper for wlogout
|
||||
blur="50x30"
|
||||
@@ -61,6 +66,14 @@ echo "$image" > $current_wallpaper
|
||||
|
||||
blurred_wp="$static_wallpaper_dir/blurred.jpg"
|
||||
|
||||
magick $image -blur $blur $blurred_wp
|
||||
if [ -x "/usr/bin/sddm" ]; then
|
||||
magick $image -blur $blur $blurred_wp
|
||||
else
|
||||
cp $image $blurred_wp
|
||||
fi
|
||||
if [ -x "/usr/bin/sddm" ] && [ -d "/usr/share/backgrounds" ]; then
|
||||
sddm_background="/usr/share/backgrounds/background.jpg"
|
||||
cp "$image" "$sddm_background"
|
||||
fi
|
||||
|
||||
echo "test"
|
||||
|
||||
Reference in New Issue
Block a user