forked from Shinonome/dots-hyprland
booru: more sexy
This commit is contained in:
@@ -445,7 +445,7 @@ Item {
|
|||||||
? `<style>img{max-width:${notificationBodyText.width}px;}</style>` +
|
? `<style>img{max-width:${notificationBodyText.width}px;}</style>` +
|
||||||
`${notificationObject.body.replace(/\n/g, "<br/>")}`
|
`${notificationObject.body.replace(/\n/g, "<br/>")}`
|
||||||
: notificationObject.body.replace(/<img/g, "\n <img").split("\n")[0]
|
: notificationObject.body.replace(/<img/g, "\n <img").split("\n")[0]
|
||||||
onLinkActivated: {
|
onLinkActivated: (link) => {
|
||||||
Qt.openUrlExternally(link)
|
Qt.openUrlExternally(link)
|
||||||
Hyprland.dispatch("global quickshell:sidebarRightClose")
|
Hyprland.dispatch("global quickshell:sidebarRightClose")
|
||||||
}
|
}
|
||||||
@@ -453,7 +453,7 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.NoButton // Only for hover
|
acceptedButtons: Qt.NoButton // Only for hover
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: notificationBodyText.hoveredLink !== "" ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: parent.hoveredLink !== "" ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import "root:/modules/common/"
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Qt5Compat.GraphicalEffects
|
||||||
|
|
||||||
|
Switch {
|
||||||
|
id: root
|
||||||
|
property real scale: 1
|
||||||
|
implicitHeight: 32 * root.scale
|
||||||
|
implicitWidth: 52 * root.scale
|
||||||
|
|
||||||
|
// Custom track styling
|
||||||
|
background: Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
color: root.checked ? Appearance.m3colors.m3primary : Appearance.m3colors.m3surfaceContainerHighest
|
||||||
|
border.width: 2 * root.scale
|
||||||
|
border.color: root.checked ? Appearance.m3colors.m3primary : Appearance.m3colors.m3outline
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on border.color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom thumb styling
|
||||||
|
indicator: Rectangle {
|
||||||
|
width: root.pressed ? (28 * root.scale) : root.checked ? (24 * root.scale) : (16 * root.scale)
|
||||||
|
height: root.pressed ? (28 * root.scale) : root.checked ? (24 * root.scale) : (16 * root.scale)
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
color: root.checked ? Appearance.m3colors.m3onPrimary : Appearance.m3colors.m3outline
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: root.checked ? (root.pressed ? (22 * root.scale) : 24 * root.scale) : (root.pressed ? (2 * root.scale) : 8 * root.scale)
|
||||||
|
|
||||||
|
Behavior on anchors.leftMargin {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,14 +16,48 @@ Item {
|
|||||||
property var panelWindow
|
property var panelWindow
|
||||||
property var inputField: tagInputField
|
property var inputField: tagInputField
|
||||||
|
|
||||||
|
function handleInput(inputText) {
|
||||||
|
if (inputText.startsWith("/")) {
|
||||||
|
// Handle special commands
|
||||||
|
const command = inputText.split(" ")[0].substring(1);
|
||||||
|
const args = inputText.split(" ").slice(1);
|
||||||
|
if (command === "clear") {
|
||||||
|
Booru.clearResponses();
|
||||||
|
}
|
||||||
|
else if (command === "mode") {
|
||||||
|
const newProvider = args[0];
|
||||||
|
Booru.setProvider(newProvider);
|
||||||
|
}
|
||||||
|
else if (command == "lewd" || command == "nsfw") {
|
||||||
|
ConfigOptions.sidebar.booru.allowNsfw = !ConfigOptions.sidebar.booru.allowNsfw
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Create tag list
|
||||||
|
const tagList = inputText.split(/\s+/);
|
||||||
|
let pageIndex = 1;
|
||||||
|
for (let i = 0; i < tagList.length; ++i) { // Detect page number
|
||||||
|
if (/^\d+$/.test(tagList[i])) {
|
||||||
|
pageIndex = parseInt(tagList[i], 10);
|
||||||
|
tagList.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Booru.makeRequest(tagList, ConfigOptions.sidebar.booru.allowNsfw, ConfigOptions.sidebar.booru.limit, pageIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Keys.onPressed: (event) => {
|
Keys.onPressed: (event) => {
|
||||||
tagInputField.forceActiveFocus()
|
tagInputField.forceActiveFocus()
|
||||||
if (event.key === Qt.Key_PageUp) {
|
if (event.modifiers === Qt.NoModifier) {
|
||||||
booruResponseListView.contentY = Math.max(0, booruResponseListView.contentY - booruResponseListView.height / 2)
|
if (event.key === Qt.Key_PageUp) {
|
||||||
event.accepted = true
|
booruResponseListView.contentY = Math.max(0, booruResponseListView.contentY - booruResponseListView.height / 2)
|
||||||
} else if (event.key === Qt.Key_PageDown) {
|
event.accepted = true
|
||||||
booruResponseListView.contentY = Math.min(booruResponseListView.contentHeight - booruResponseListView.height, booruResponseListView.contentY + booruResponseListView.height / 2)
|
} else if (event.key === Qt.Key_PageDown) {
|
||||||
event.accepted = true
|
booruResponseListView.contentY = Math.min(booruResponseListView.contentHeight - booruResponseListView.height / 2, booruResponseListView.contentY + booruResponseListView.height / 2)
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,46 +71,75 @@ Item {
|
|||||||
id: columnLayout
|
id: columnLayout
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
ListView { // Booru responses
|
Item {
|
||||||
id: booruResponseListView
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
clip: true
|
ListView { // Booru responses
|
||||||
layer.enabled: true
|
id: booruResponseListView
|
||||||
layer.effect: OpacityMask {
|
anchors.fill: parent
|
||||||
maskSource: Rectangle {
|
clip: true
|
||||||
width: swipeView.width
|
layer.enabled: true
|
||||||
height: swipeView.height
|
layer.effect: OpacityMask {
|
||||||
radius: Appearance.rounding.small
|
maskSource: Rectangle {
|
||||||
|
width: swipeView.width
|
||||||
|
height: swipeView.height
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on contentY {
|
||||||
|
NumberAnimation {
|
||||||
|
id: scrollAnim
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spacing: 10
|
||||||
|
model: ScriptModel {
|
||||||
|
values: Booru.responses
|
||||||
|
}
|
||||||
|
delegate: BooruResponse {
|
||||||
|
responseData: modelData
|
||||||
|
tagInputField: root.inputField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on contentY {
|
Item { // Placeholder when list is empty
|
||||||
NumberAnimation {
|
visible: Booru.responses.length === 0
|
||||||
id: scrollAnim
|
anchors.fill: parent
|
||||||
duration: Appearance.animation.elementDecel.duration
|
|
||||||
easing.type: Appearance.animation.elementDecel.type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spacing: 10
|
ColumnLayout {
|
||||||
model: ScriptModel {
|
anchors.centerIn: parent
|
||||||
values: Booru.responses
|
spacing: 5
|
||||||
}
|
|
||||||
delegate: BooruResponse {
|
MaterialSymbol {
|
||||||
responseData: modelData
|
Layout.alignment: Qt.AlignHCenter
|
||||||
tagInputField: root.inputField
|
font.pixelSize: 55
|
||||||
|
color: Appearance.m3colors.m3outline
|
||||||
|
text: "bookmark_heart"
|
||||||
|
}
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.normal
|
||||||
|
color: Appearance.m3colors.m3outline
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: "Anime boorus"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle { // Tag input field
|
||||||
id: tagInputFieldContainer
|
id: tagInputContainer
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
radius: Appearance.rounding.small
|
radius: Appearance.rounding.small
|
||||||
color: Appearance.colors.colLayer1
|
color: Appearance.colors.colLayer1
|
||||||
implicitWidth: tagInputField.implicitWidth
|
implicitWidth: tagInputColumnLayout.implicitWidth
|
||||||
implicitHeight: Math.max(tagInputField.implicitHeight, 45)
|
implicitHeight: Math.max(tagInputColumnLayout.implicitHeight, 45)
|
||||||
clip: true
|
clip: true
|
||||||
|
border.color: Appearance.m3colors.m3outlineVariant
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
Behavior on implicitHeight {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -85,56 +148,118 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextArea {
|
ColumnLayout {
|
||||||
id: tagInputField
|
id: tagInputColumnLayout
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
wrapMode: TextArea.Wrap
|
TextArea { // The actual input field widget
|
||||||
|
id: tagInputField
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 5
|
||||||
|
padding: 10
|
||||||
|
color: activeFocus ? Appearance.m3colors.m3onSurface : Appearance.m3colors.m3onSurfaceVariant
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
selectedTextColor: Appearance.m3colors.m3onPrimary
|
||||||
|
selectionColor: Appearance.m3colors.m3primary
|
||||||
|
placeholderText: qsTr("Enter tags")
|
||||||
|
placeholderTextColor: Appearance.m3colors.m3outline
|
||||||
|
|
||||||
padding: 10
|
background: Item {}
|
||||||
color: activeFocus ? Appearance.m3colors.m3onSurface : Appearance.m3colors.m3onSurfaceVariant
|
|
||||||
renderType: Text.NativeRendering
|
|
||||||
selectedTextColor: Appearance.m3colors.m3onPrimary
|
|
||||||
selectionColor: Appearance.m3colors.m3primary
|
|
||||||
placeholderText: qsTr("Enter tags")
|
|
||||||
placeholderTextColor: Appearance.m3colors.m3outline
|
|
||||||
|
|
||||||
Keys.onPressed: (event) => {
|
Keys.onPressed: (event) => {
|
||||||
if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) {
|
if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) {
|
||||||
if (event.modifiers & Qt.ShiftModifier) {
|
if (event.modifiers & Qt.ShiftModifier) {
|
||||||
// Insert newline
|
// Insert newline
|
||||||
tagInputField.insert(tagInputField.cursorPosition, "\n")
|
tagInputField.insert(tagInputField.cursorPosition, "\n")
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
} else {
|
} else { // Accept text
|
||||||
const inputText = tagInputField.text
|
const inputText = tagInputField.text
|
||||||
if (inputText.startsWith("/")) {
|
root.handleInput(inputText)
|
||||||
// Handle special commands
|
tagInputField.clear()
|
||||||
const command = inputText.split(" ")[0].substring(1);
|
event.accepted = true
|
||||||
if (command === "clear") {
|
}
|
||||||
Booru.clearResponses();
|
}
|
||||||
}
|
}
|
||||||
else if (command === "mode") {
|
}
|
||||||
const newProvider = inputText.split(" ")[1];
|
|
||||||
Booru.setProvider(newProvider);
|
RowLayout { // Controls
|
||||||
Booru.addSystemMessage(`Provider set to ${Booru.providers[newProvider].name}`);
|
id: commandButtonsRow
|
||||||
|
spacing: 5
|
||||||
|
Layout.bottomMargin: 5
|
||||||
|
Layout.leftMargin: 5
|
||||||
|
Layout.rightMargin: 5
|
||||||
|
|
||||||
|
property var commands: [
|
||||||
|
{
|
||||||
|
name: "/mode",
|
||||||
|
sendDirectly: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "/clear",
|
||||||
|
sendDirectly: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
implicitWidth: switchesRow.implicitWidth
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: switchesRow
|
||||||
|
spacing: 5
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.leftMargin: 10
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.smaller
|
||||||
|
color: Appearance.colors.coloOnLayer1
|
||||||
|
text: qsTr("NSFW")
|
||||||
|
}
|
||||||
|
StyledSwitch {
|
||||||
|
id: nsfwSwitch
|
||||||
|
scale: 0.75
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
checked: ConfigOptions.sidebar.booru.allowNsfw
|
||||||
|
onCheckedChanged: {
|
||||||
|
ConfigOptions.sidebar.booru.allowNsfw = checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
// Create tag list
|
}
|
||||||
const tagList = inputText.split(/\s+/);
|
|
||||||
let pageIndex = 1;
|
Item { Layout.fillWidth: true }
|
||||||
for (let i = 0; i < tagList.length; ++i) { // Detect page number
|
|
||||||
if (/^\d+$/.test(tagList[i])) {
|
Repeater { // Command buttons
|
||||||
pageIndex = parseInt(tagList[i], 10);
|
id: commandRepeater
|
||||||
tagList.splice(i, 1);
|
model: commandButtonsRow.commands
|
||||||
break;
|
delegate: BooruTagButton {
|
||||||
|
id: tagButton
|
||||||
|
buttonText: modelData.name
|
||||||
|
background: Rectangle {
|
||||||
|
radius: Appearance.rounding.small
|
||||||
|
color: (tagButton.down ? Appearance.colors.colLayer1Active :
|
||||||
|
tagButton.hovered ? Appearance.colors.colLayer1Hover :
|
||||||
|
Appearance.transparentize(Appearance.colors.colLayer1, 1))
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.animation.elementDecel.duration
|
||||||
|
easing.type: Appearance.animation.elementDecel.type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Booru.makeRequest(tagList, ConfigOptions.sidebar.booru.allowNsfw, ConfigOptions.sidebar.booru.limit, pageIndex);
|
|
||||||
}
|
}
|
||||||
tagInputField.clear()
|
onClicked: {
|
||||||
event.accepted = true
|
if(modelData.sendDirectly) {
|
||||||
|
root.handleInput(modelData.name)
|
||||||
|
} else {
|
||||||
|
tagInputField.text = modelData.name + " "
|
||||||
|
tagInputField.cursorPosition = tagInputField.text.length
|
||||||
|
tagInputField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,9 +90,16 @@ Scope { // Scope
|
|||||||
if (event.modifiers === Qt.ControlModifier) {
|
if (event.modifiers === Qt.ControlModifier) {
|
||||||
if (event.key === Qt.Key_PageDown) {
|
if (event.key === Qt.Key_PageDown) {
|
||||||
sidebarRoot.currentTab = Math.min(sidebarRoot.currentTab + 1, root.tabButtonList.length - 1)
|
sidebarRoot.currentTab = Math.min(sidebarRoot.currentTab + 1, root.tabButtonList.length - 1)
|
||||||
} else if (event.key === Qt.Key_PageUp) {
|
}
|
||||||
|
else if (event.key === Qt.Key_PageUp) {
|
||||||
sidebarRoot.currentTab = Math.max(sidebarRoot.currentTab - 1, 0)
|
sidebarRoot.currentTab = Math.max(sidebarRoot.currentTab - 1, 0)
|
||||||
}
|
}
|
||||||
|
else if (event.key === Qt.Key_Tab) {
|
||||||
|
sidebarRoot.currentTab = (sidebarRoot.currentTab + 1) % root.tabButtonList.length;
|
||||||
|
}
|
||||||
|
else if (event.key === Qt.Key_Backtab) {
|
||||||
|
sidebarRoot.currentTab = (sidebarRoot.currentTab - 1 + root.tabButtonList.length) % root.tabButtonList.length;
|
||||||
|
}
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,13 @@ Button {
|
|||||||
property var imageData
|
property var imageData
|
||||||
property var rowHeight
|
property var rowHeight
|
||||||
|
|
||||||
|
// onImageDataChanged: {
|
||||||
|
// console.log("Image data changed:", imageData)
|
||||||
|
// }
|
||||||
|
|
||||||
padding: 0
|
padding: 0
|
||||||
|
implicitWidth: imageObject.width
|
||||||
|
implicitHeight: imageObject.height
|
||||||
|
|
||||||
PointingHandInteraction {}
|
PointingHandInteraction {}
|
||||||
|
|
||||||
@@ -21,27 +27,27 @@ Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
implicitWidth: imageData.width
|
implicitWidth: imageObject.width
|
||||||
implicitHeight: imageData.height
|
implicitHeight: imageObject.height
|
||||||
radius: Appearance.rounding.small
|
radius: Appearance.rounding.small
|
||||||
color: Appearance.colors.colLayer2
|
color: Appearance.colors.colLayer2
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Image {
|
contentItem: Image {
|
||||||
id: imageData
|
id: imageObject
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
sourceSize.width: imageRow.rowHeight * modelData.aspect_ratio
|
sourceSize.width: root.rowHeight * modelData.aspect_ratio
|
||||||
sourceSize.height: imageRow.rowHeight
|
sourceSize.height: root.rowHeight
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
source: modelData.preview_url
|
source: modelData.preview_url
|
||||||
width: imageRow.rowHeight * modelData.aspect_ratio
|
width: root.rowHeight * modelData.aspect_ratio
|
||||||
height: imageRow.rowHeight
|
height: root.rowHeight
|
||||||
|
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.effect: OpacityMask {
|
layer.effect: OpacityMask {
|
||||||
maskSource: Rectangle {
|
maskSource: Rectangle {
|
||||||
width: imageData.width
|
width: imageObject.width
|
||||||
height: imageData.height
|
height: imageObject.height
|
||||||
radius: Appearance.rounding.small
|
radius: Appearance.rounding.small
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,13 @@ import Qt5Compat.GraphicalEffects
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
property var responseData
|
property var responseData: {}
|
||||||
property var tagInputField
|
property var tagInputField
|
||||||
|
|
||||||
|
onResponseDataChanged: {
|
||||||
|
console.log("Response data changed:", responseData)
|
||||||
|
}
|
||||||
|
|
||||||
property real availableWidth: parent?.width
|
property real availableWidth: parent?.width
|
||||||
property real rowTooShortThreshold: 100
|
property real rowTooShortThreshold: 100
|
||||||
property real imageSpacing: 5
|
property real imageSpacing: 5
|
||||||
@@ -38,9 +42,8 @@ Rectangle {
|
|||||||
anchors.margins: responsePadding
|
anchors.margins: responsePadding
|
||||||
spacing: root.imageSpacing
|
spacing: root.imageSpacing
|
||||||
|
|
||||||
// Provider name
|
RowLayout { // Header
|
||||||
RowLayout {
|
Rectangle { // Provider name
|
||||||
Rectangle {
|
|
||||||
id: providerNameWrapper
|
id: providerNameWrapper
|
||||||
color: Appearance.m3colors.m3secondaryContainer
|
color: Appearance.m3colors.m3secondaryContainer
|
||||||
radius: Appearance.rounding.small
|
radius: Appearance.rounding.small
|
||||||
@@ -52,31 +55,33 @@ Rectangle {
|
|||||||
id: providerName
|
id: providerName
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
font.pixelSize: Appearance.font.pixelSize.large
|
font.pixelSize: Appearance.font.pixelSize.large
|
||||||
|
font.weight: Font.DemiBold
|
||||||
color: Appearance.m3colors.m3onSecondaryContainer
|
color: Appearance.m3colors.m3onSecondaryContainer
|
||||||
text: Booru.providers[root.responseData.provider].name
|
text: Booru.providers[root.responseData.provider].name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item { Layout.fillWidth: true }
|
Item { Layout.fillWidth: true }
|
||||||
Rectangle {
|
Rectangle { // Page number
|
||||||
|
visible: root.responseData.page != "" && root.responseData.page > 0
|
||||||
color: Appearance.colors.colLayer2
|
color: Appearance.colors.colLayer2
|
||||||
radius: Appearance.rounding.small
|
radius: Appearance.rounding.small
|
||||||
implicitWidth: Math.max(pageNumber.implicitWidth + 10 * 2, 20)
|
implicitWidth: Math.max(pageNumber.implicitWidth + 10 * 2, 30)
|
||||||
implicitHeight: pageNumber.implicitHeight + 5 * 2
|
implicitHeight: pageNumber.implicitHeight + 5 * 2
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignTop
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: pageNumber
|
id: pageNumber
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
font.pixelSize: Appearance.font.pixelSize.small
|
font.pixelSize: Appearance.font.pixelSize.smaller
|
||||||
color: Appearance.colors.colOnLayer2
|
color: Appearance.colors.colOnLayer2
|
||||||
text: `Page ${root.responseData.page}`
|
text: `Page ${root.responseData.page}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tags
|
Flickable { // Tag strip
|
||||||
Flickable {
|
|
||||||
id: tagsFlickable
|
id: tagsFlickable
|
||||||
|
visible: root.responseData.tags.length > 0
|
||||||
Layout.alignment: Qt.AlignLeft
|
Layout.alignment: Qt.AlignLeft
|
||||||
Layout.fillWidth: {
|
Layout.fillWidth: {
|
||||||
console.log(root.responseData)
|
console.log(root.responseData)
|
||||||
@@ -128,6 +133,28 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StyledText { // Message
|
||||||
|
id: messageText
|
||||||
|
Layout.fillWidth: true
|
||||||
|
visible: root.responseData.message.length > 0
|
||||||
|
font.pixelSize: Appearance.font.pixelSize.small
|
||||||
|
color: Appearance.colors.colOnLayer1
|
||||||
|
text: root.responseData.message
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
Layout.margins: responsePadding
|
||||||
|
textFormat: Text.MarkdownText
|
||||||
|
onLinkActivated: (link) => {
|
||||||
|
Qt.openUrlExternally(link)
|
||||||
|
Hyprland.dispatch("global quickshell:sidebarLeftClose")
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton // Only for hover
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: parent.hoveredLink !== "" ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: {
|
model: {
|
||||||
// Group two images every row, ensuring they are of the same height
|
// Group two images every row, ensuring they are of the same height
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ Button {
|
|||||||
color: (button.down ? Appearance.colors.colSurfaceContainerHighestActive :
|
color: (button.down ? Appearance.colors.colSurfaceContainerHighestActive :
|
||||||
button.hovered ? Appearance.colors.colSurfaceContainerHighestHover :
|
button.hovered ? Appearance.colors.colSurfaceContainerHighestHover :
|
||||||
Appearance.m3colors.m3surfaceContainerHighest)
|
Appearance.m3colors.m3surfaceContainerHighest)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: StyledText {
|
contentItem: StyledText {
|
||||||
|
|||||||
@@ -28,6 +28,14 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
|
if (event.modifiers === Qt.ControlModifier) {
|
||||||
|
if (event.key === Qt.Key_Tab) {
|
||||||
|
root.currentTab = (root.currentTab + 1) % root.tabButtonList.length;
|
||||||
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
|
root.currentTab = (root.currentTab - 1 + root.tabButtonList.length) % root.tabButtonList.length;
|
||||||
|
}
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Placeholder when list is empty
|
|
||||||
Item {
|
Item { // Placeholder when list is empty
|
||||||
visible: taskList.length === 0
|
visible: taskList.length === 0
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ import QtQuick;
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ConfigOptions.sidebar.booru
|
||||||
|
function onAllowNsfwChanged() {
|
||||||
|
root.addSystemMessage(ConfigOptions.sidebar.booru.allowNsfw ? qsTr("Tiddies enabled") : qsTr("No horny"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property var responses: []
|
property var responses: []
|
||||||
property var getWorkingImageSource: (url) => {
|
property var getWorkingImageSource: (url) => {
|
||||||
if (url.includes('pximg.net')) {
|
if (url.includes('pximg.net')) {
|
||||||
@@ -42,7 +49,7 @@ Singleton {
|
|||||||
"sample_url": item.sample_url ?? item.file_url,
|
"sample_url": item.sample_url ?? item.file_url,
|
||||||
"file_url": item.file_url,
|
"file_url": item.file_url,
|
||||||
"file_ext": item.file_ext,
|
"file_ext": item.file_ext,
|
||||||
"source": getWorkingImageSource(item.source),
|
"source": getWorkingImageSource(item.source) ?? item.file_url,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -67,7 +74,7 @@ Singleton {
|
|||||||
"sample_url": item.sample_url ?? item.file_url,
|
"sample_url": item.sample_url ?? item.file_url,
|
||||||
"file_url": item.file_url,
|
"file_url": item.file_url,
|
||||||
"file_ext": item.file_ext,
|
"file_ext": item.file_ext,
|
||||||
"source": getWorkingImageSource(item.source),
|
"source": getWorkingImageSource(item.source) ?? item.file_url,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -92,7 +99,7 @@ Singleton {
|
|||||||
"sample_url": item.thumbnail,
|
"sample_url": item.thumbnail,
|
||||||
"file_url": item.thumbnail,
|
"file_url": item.thumbnail,
|
||||||
"file_ext": "avif",
|
"file_ext": "avif",
|
||||||
"source": getWorkingImageSource(item.source),
|
"source": getWorkingImageSource(item.source) ?? item.thumbnail,
|
||||||
"character": item.tag
|
"character": item.tag
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -118,7 +125,7 @@ Singleton {
|
|||||||
"sample_url": item.file_url ?? item.large_file_url,
|
"sample_url": item.file_url ?? item.large_file_url,
|
||||||
"file_url": item.large_file_url,
|
"file_url": item.large_file_url,
|
||||||
"file_ext": item.file_ext,
|
"file_ext": item.file_ext,
|
||||||
"source": getWorkingImageSource(item.source),
|
"source": getWorkingImageSource(item.source) ?? item.file_url,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -143,7 +150,7 @@ Singleton {
|
|||||||
"sample_url": item.sample_url ?? item.file_url,
|
"sample_url": item.sample_url ?? item.file_url,
|
||||||
"file_url": item.file_url,
|
"file_url": item.file_url,
|
||||||
"file_ext": item.file_url.split('.').pop(),
|
"file_ext": item.file_url.split('.').pop(),
|
||||||
"source": getWorkingImageSource(item.source),
|
"source": getWorkingImageSource(item.source) ?? item.file_url,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -155,8 +162,11 @@ Singleton {
|
|||||||
function setProvider(provider) {
|
function setProvider(provider) {
|
||||||
if (providerList.indexOf(provider) !== -1) {
|
if (providerList.indexOf(provider) !== -1) {
|
||||||
currentProvider = provider
|
currentProvider = provider
|
||||||
|
root.addSystemMessage(qsTr("Provider set to ") + providers[provider].name
|
||||||
|
+ (provider == "zerochan" ? qsTr(". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!") : ""))
|
||||||
} else {
|
} else {
|
||||||
console.log("[Booru] Invalid provider: " + provider)
|
console.log("[Booru] Invalid provider: " + provider)
|
||||||
|
root.addSystemMessage(qsTr("Invalid provider. Supported providers: \n- ") + providerList.join("\n- "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,13 +175,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addSystemMessage(message) {
|
function addSystemMessage(message) {
|
||||||
responses.push({
|
responses = [...responses, {
|
||||||
"provider": "system",
|
"provider": "system",
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"page": 1,
|
"page": -1,
|
||||||
"images": [],
|
"images": [],
|
||||||
"message": `${message}`
|
"message": `${message}`
|
||||||
})
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
function constructRequestUrl(tags, nsfw=true, limit=20, page=1) {
|
function constructRequestUrl(tags, nsfw=true, limit=20, page=1) {
|
||||||
@@ -214,7 +224,7 @@ Singleton {
|
|||||||
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
|
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
|
||||||
try {
|
try {
|
||||||
// console.log("[Booru] Raw response length: " + xhr.responseText.length)
|
// console.log("[Booru] Raw response length: " + xhr.responseText.length)
|
||||||
console.log("[Booru] Raw response: " + xhr.responseText)
|
// console.log("[Booru] Raw response: " + xhr.responseText)
|
||||||
var response = JSON.parse(xhr.responseText)
|
var response = JSON.parse(xhr.responseText)
|
||||||
|
|
||||||
// Access nested properties based on listAccess
|
// Access nested properties based on listAccess
|
||||||
@@ -227,16 +237,14 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
response = providers[currentProvider].mapFunc(response)
|
response = providers[currentProvider].mapFunc(response)
|
||||||
console.log("[Booru] Scoped & mapped response: " + JSON.stringify(response))
|
// console.log("[Booru] Scoped & mapped response: " + JSON.stringify(response))
|
||||||
var newResponses = root.responses.slice() // make a shallow copy
|
root.responses = [...root.responses, {
|
||||||
newResponses.push({
|
|
||||||
"provider": currentProvider,
|
"provider": currentProvider,
|
||||||
"tags": tags,
|
"tags": tags,
|
||||||
"page": page,
|
"page": page,
|
||||||
"images": response,
|
"images": response,
|
||||||
"message": ""
|
"message": ""
|
||||||
})
|
}]
|
||||||
root.responses = newResponses
|
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("[Booru] Failed to parse response: " + e)
|
console.log("[Booru] Failed to parse response: " + e)
|
||||||
|
|||||||
Reference in New Issue
Block a user