Skip to content

Commit

Permalink
Merge pull request #336 from ioriayane/add_jetstream_status_display
Browse files Browse the repository at this point in the history
リアルタイムフィードの状態を表示する機能の追加
  • Loading branch information
ioriayane authored Jan 14, 2025
2 parents 49400ac + 196fd91 commit 1bdf126
Show file tree
Hide file tree
Showing 19 changed files with 802 additions and 163 deletions.
1 change: 1 addition & 0 deletions app/app.pro
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ QML_FILES = \
qml/parts/ProfileTabButton.qml \
qml/parts/QuoteRecord.qml \
qml/parts/ReactionAuthor.qml \
qml/parts/RealtimeFeedStatus.qml \
qml/parts/SelectorDelegate.qml \
qml/parts/SelfLabelPopup.qml \
qml/parts/SideBar.qml \
Expand Down
Binary file modified app/i18n/app_ja.qm
Binary file not shown.
161 changes: 83 additions & 78 deletions app/i18n/app_ja.ts

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
#include "qtquick/controls/calendartablemodel.h"
#include "qtquick/realtime/realtimefeedlistmodel.h"
#include "qtquick/realtime/editselectorlistmodel.h"
#include "qtquick/realtime/realtimefeedstatuslistmodel.h"
#include "qtquick/realtime/realtimefeedstatusgraph.h"

#include "tools/encryption.h"
#include "tools/translatorchanger.h"
Expand Down Expand Up @@ -193,6 +195,11 @@ int main(int argc, char *argv[])
0, "RealtimeFeedListModel");
qmlRegisterType<EditSelectorListModel>("tech.relog.hagoromo.realtime.editselectorlistmodel", 1,
0, "EditSelectorListModel");
qmlRegisterType<RealtimeFeedStatusListModel>(
"tech.relog.hagoromo.realtime.realtimefeedstatuslistmodel", 1, 0,
"RealtimeFeedStatusListModel");
qmlRegisterType<RealtimeFeedStatusGraph>("tech.relog.hagoromo.realtime.realtimefeedstatusgraph",
1, 0, "RealtimeFeedStatusGraph");

qmlRegisterType<CalendarTableModel>("tech.relog.hagoromo.controls.calendartablemodel", 1, 0,
"CalendarTableModel");
Expand Down
21 changes: 16 additions & 5 deletions app/qml/dialogs/SettingDialog.qml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Dialog {
property string translateApiKey: ""
property string translateTargetLanguage: "JA"
// About
property bool displayRealtimeFeedStatus: false
property bool displayVersionInfoInMainArea: true

Component.onCompleted: load()
Expand Down Expand Up @@ -85,6 +86,7 @@ Dialog {
translateTargetLanguageCombo.currentIndex = -1
translateTargetLanguageCombo.setByValue(settings.translateTargetLanguage)
// About
displayRealtimeFeedStatusCheckBox.checked = settings.displayRealtimeFeedStatus
displayVersionInfoInMainAreaCheckBox.checked = settings.displayVersionInfoInMainArea
}

Expand Down Expand Up @@ -766,13 +768,21 @@ Dialog {
text: "© 2023 Iori Ayane"
}
}
CheckBox {
id: displayVersionInfoInMainAreaCheckBox
ColumnLayout {
anchors.right: parent.right
anchors.bottom: parent.bottom
font.pointSize: AdjustedValues.f8
bottomPadding: 1
text: qsTr("Display version info in main area")
CheckBox {
id: displayRealtimeFeedStatusCheckBox
font.pointSize: AdjustedValues.f8
bottomPadding: 1
text: qsTr("Display the status of Realtime feed")
}
CheckBox {
id: displayVersionInfoInMainAreaCheckBox
font.pointSize: AdjustedValues.f8
bottomPadding: 1
text: qsTr("Display version info in main area")
}
}
}
}
Expand Down Expand Up @@ -824,6 +834,7 @@ Dialog {
settings.translateApiKey = encryption.encrypt(translateApiKeyText.text)
settings.translateTargetLanguage = translateTargetLanguageCombo.currentValue
// About
settings.displayRealtimeFeedStatus = displayRealtimeFeedStatusCheckBox.checked
settings.displayVersionInfoInMainArea = displayVersionInfoInMainAreaCheckBox.checked

settingDialog.accept()
Expand Down
46 changes: 28 additions & 18 deletions app/qml/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -1054,30 +1054,40 @@ ApplicationWindow {
}
}

Frame {
// 何かの読み込み中の表示
id: globalProgressFrame
ColumnLayout {
anchors.right: rootLayout.right
anchors.bottom: rootLayout.bottom
anchors.rightMargin: 5
anchors.bottomMargin: scrollView.ScrollBar.horizontal.height + 5
visible: globalProgressFrame.text.length > 0
background: Rectangle {
radius: 3
border.width: 1
border.color: Material.frameColor
color: Material.backgroundColor

RealtimeFeedStatus {
id: realtimeFeedStatus
Layout.alignment: Qt.AlignRight
visible: settingDialog.settings.displayRealtimeFeedStatus
theme: settingDialog.settings.theme
}
property string text: ""
RowLayout {
BusyIndicator {
Layout.preferredWidth: AdjustedValues.i24
Layout.preferredHeight: AdjustedValues.i24
// running: globalProgressFrame.visible
Frame {
// 何かの読み込み中の表示
id: globalProgressFrame
Layout.alignment: Qt.AlignRight
visible: globalProgressFrame.text.length > 0
background: Rectangle {
radius: 3
border.width: 1
border.color: Material.frameColor
color: Material.backgroundColor
}
Label {
font.pointSize: AdjustedValues.f10
text: globalProgressFrame.text
property string text: ""
RowLayout {
BusyIndicator {
Layout.preferredWidth: AdjustedValues.i24
Layout.preferredHeight: AdjustedValues.i24
// running: globalProgressFrame.visible
}
Label {
font.pointSize: AdjustedValues.f10
text: globalProgressFrame.text
}
}
}
}
Expand Down
69 changes: 69 additions & 0 deletions app/qml/parts/RealtimeFeedStatus.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls.Material 2.15

import tech.relog.hagoromo.realtime.realtimefeedstatuslistmodel 1.0
import tech.relog.hagoromo.realtime.realtimefeedstatusgraph 1.0
import tech.relog.hagoromo.singleton 1.0

Frame {
id: realtimeFeedStatusFrame
property int theme: 0

background: Rectangle {
radius: 3
border.width: 1
border.color: Material.frameColor
color: Material.backgroundColor
}

RowLayout {
spacing: 10
RealtimeFeedStatusGraph {
Layout.preferredWidth: paramLayout.implicitWidth * 1.5
Layout.preferredHeight: paramLayout.implicitHeight
visible: graphControlLabel.checked
theme: realtimeFeedStatusFrame.theme
}
ColumnLayout {
id: paramLayout
Repeater {
model: RealtimeFeedStatusListModel {
theme: realtimeFeedStatusFrame.theme
}
RowLayout {
Label {
Layout.minimumWidth: 100 * AdjustedValues.ratio
font.pointSize: AdjustedValues.f8
text: model.name
color: model.useColor ? model.color : Material.foreground
}
Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
font.pointSize: AdjustedValues.f8
text: model.value
}
Label {
font.pointSize: AdjustedValues.f6
text: model.unit
}
}
}
Label {
id: graphControlLabel
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
font.pointSize: AdjustedValues.f8
text: (checked ? "" : "")+"History"
color: Material.color(Material.Blue)
property bool checked: false
MouseArea {
anchors.fill: parent
onClicked: graphControlLabel.checked = !graphControlLabel.checked
}
}
}
}
}
4 changes: 4 additions & 0 deletions app/qtquick/qtquick.pri
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ SOURCES += \
$$PWD/operation/translator.cpp \
$$PWD/realtime/editselectorlistmodel.cpp \
$$PWD/realtime/realtimefeedlistmodel.cpp \
$$PWD/realtime/realtimefeedstatusgraph.cpp \
$$PWD/realtime/realtimefeedstatuslistmodel.cpp \
$$PWD/systemtool.cpp \
$$PWD/timeline/actorlikelistmodel.cpp \
$$PWD/timeline/anyfeedlistmodel.cpp \
Expand Down Expand Up @@ -102,6 +104,8 @@ HEADERS += \
$$PWD/operation/translator.h \
$$PWD/realtime/editselectorlistmodel.h \
$$PWD/realtime/realtimefeedlistmodel.h \
$$PWD/realtime/realtimefeedstatusgraph.h \
$$PWD/realtime/realtimefeedstatuslistmodel.h \
$$PWD/systemtool.h \
$$PWD/thumbnailprovider.h \
$$PWD/timeline/actorlikelistmodel.h \
Expand Down
144 changes: 144 additions & 0 deletions app/qtquick/realtime/realtimefeedstatusgraph.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include "realtimefeedstatusgraph.h"

#include "realtime/firehosereceiver.h"

#include <QPainter>
#include <QPainterPath>

using namespace RealtimeFeed;

constexpr int GRAPH_POINT_COUNT = 60; // 2以上にすること

RealtimeFeedStatusGraph::RealtimeFeedStatusGraph(QQuickPaintedItem *parent)
: QQuickPaintedItem(parent), m_maxValue { 0 }, m_theme { 0 }
{
appendGraphData("app.bsky.feed.post", QColor(255, 255, 0));
appendGraphData("app.bsky.feed.repost", QColor(255, 0, 255));
appendGraphData("app.bsky.feed.like", QColor(0, 255, 255));
appendGraphData("app.bsky.graph.follow", QColor(255, 0, 0));
appendGraphData("app.bsky.graph.listitem", QColor(0, 255, 0));

updateColorByTheme();

FirehoseReceiver *receiver = FirehoseReceiver::getInstance();
connect(receiver, &FirehoseReceiver::analysisChanged, this,
&RealtimeFeedStatusGraph::receiverAnalysisChanged);
}

RealtimeFeedStatusGraph::~RealtimeFeedStatusGraph()
{
FirehoseReceiver *receiver = FirehoseReceiver::getInstance();
disconnect(receiver, &FirehoseReceiver::analysisChanged, this,
&RealtimeFeedStatusGraph::receiverAnalysisChanged);
}

void RealtimeFeedStatusGraph::paint(QPainter *painter)
{
QElapsedTimer timer;
timer.start();

qreal d = boundingRect().width() / static_cast<qreal>(GRAPH_POINT_COUNT - 1);

painter->setPen(QColor(128, 128, 128));
painter->drawRect(boundingRect());

QHashIterator<QString, QList<int>> i(m_graphData);
int max_value = m_maxValue + 1;
int height = boundingRect().height();
while (i.hasNext()) {
i.next();
painter->setPen(m_graphColor.value(i.key(), QColor(128, 128, 128)));

QPainterPath path;
qreal x = 0;
for (const auto &value : i.value()) {
if (x == 0) {
path.moveTo(x, height - height * value / max_value);
} else {
path.lineTo(x, height - height * value / max_value);
}
x += d;
}
painter->drawPath(path);
}
}

void RealtimeFeedStatusGraph::receiverAnalysisChanged()
{

FirehoseReceiver *receiver = FirehoseReceiver::getInstance();
const QHash<QString, QString> nsids_rps = receiver->nsidsReceivePerSecond();

QHashIterator<QString, QString> i(nsids_rps);
m_maxValue = 0;
int max = 0;
while (i.hasNext()) {
i.next();
const int value = i.value().toInt();
max = updateGraphData(i.key(), value);
m_maxValue = qMax(max, m_maxValue);
}

// 再描画
update();
}

void RealtimeFeedStatusGraph::appendGraphData(const QString &id, const QColor &color)
{
m_graphColor[id] = color;
m_graphData[id].clear();
for (int i = 0; i < GRAPH_POINT_COUNT; i++) {
m_graphData[id].append(0);
}
}

int RealtimeFeedStatusGraph::updateGraphData(const QString &id, const int value)
{
if (m_graphData[id].isEmpty()) {
m_graphData[id].append(value);
} else {
m_graphData[id].pop_front();
m_graphData[id].push_back(value);
}
int max = 0;
if (!id.startsWith("_")) {
for (const auto &v : m_graphData[id]) {
max = qMax(v, max);
}
}
return max;
}

void RealtimeFeedStatusGraph::updateColorByTheme()
{
if (theme() == 0) {
// Light
m_graphColor["app.bsky.feed.post"] = QColor(0x3F, 0x51, 0xB5); // Indigo
m_graphColor["app.bsky.feed.repost"] = QColor(0x4C, 0xAF, 0x50); // Green
m_graphColor["app.bsky.feed.like"] = QColor(0xE9, 0x1E, 0x63); // Pink
m_graphColor["app.bsky.graph.follow"] = QColor(0x03, 0xA9, 0xF4); // LightBlue
m_graphColor["app.bsky.graph.listitem"] = QColor(0xFF, 0x98, 0x0); // Orange
} else {
// Dark
m_graphColor["app.bsky.feed.post"] = QColor(0x9F, 0xA8, 0xDA);
m_graphColor["app.bsky.feed.repost"] = QColor(0xA5, 0xD6, 0xA7);
m_graphColor["app.bsky.feed.like"] = QColor(0xF4, 0x8F, 0xB1);
m_graphColor["app.bsky.graph.follow"] = QColor(0x81, 0xD4, 0xFA);
m_graphColor["app.bsky.graph.listitem"] = QColor(0xFF, 0xCC, 0x80);
}
}

int RealtimeFeedStatusGraph::theme() const
{
return m_theme;
}

void RealtimeFeedStatusGraph::setTheme(int newTheme)
{
if (m_theme == newTheme)
return;
m_theme = newTheme;
emit themeChanged();

updateColorByTheme();
}
Loading

0 comments on commit 1bdf126

Please sign in to comment.