chore: tweak ux for particles

This commit is contained in:
talksik
2026-01-28 16:20:49 -08:00
parent d9cd882e3b
commit 458a26b84a
8 changed files with 230 additions and 81 deletions
+32 -2
View File
@@ -23,7 +23,7 @@ MainWindow::MainWindow(QWidget *parent)
ui = new Ui::MainWindow;
ui->setupUi(this);
this->setWindowFlags(Qt::FramelessWindowHint);
// this->setWindowFlags(Qt::FramelessWindowHint);
ui->splitter->setStretchFactor(0, 1);
ui->splitter->setStretchFactor(1, 1);
@@ -121,11 +121,21 @@ void MainWindow::setupModels()
m_particleListModel = new ParticleListModel(m_data, this);
ui->particlesView->setModel(m_particleListModel);
// Configure particle list view to use ellipses for long text
ui->particlesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->particlesView->setTextElideMode(Qt::ElideRight);
// Connect selection changes
connect(ui->topLevelParticlesView->selectionModel(),
&QItemSelectionModel::selectionChanged,
this,
&MainWindow::onTreeSelectionChanged);
// Connect particle selection changes
connect(ui->particlesView->selectionModel(),
&QItemSelectionModel::selectionChanged,
this,
&MainWindow::onParticleSelectionChanged);
}
void MainWindow::onTreeSelectionChanged(
@@ -160,8 +170,28 @@ void MainWindow::onTreeSelectionChanged(
ui->particlesView->setFocus();
}
}
else
else // network selected
{
m_particleListModel->setStreamId(QString());
}
}
void MainWindow::onParticleSelectionChanged(
const QItemSelection &selected,
const QItemSelection &deselected)
{
Q_UNUSED(deselected);
if (selected.indexes().isEmpty())
{
ui->label->setText("");
return;
}
QModelIndex index = selected.indexes().first();
const Particle *particle = m_particleListModel->particleAtRow(index.row());
if (particle)
{
ui->label->setText(particle->summary);
}
}
+1
View File
@@ -38,6 +38,7 @@ public:
void on_settingsButton_clicked();
void onTreeSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void onParticleSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
private:
void setupTrayIcon();
+34 -23
View File
@@ -25,11 +25,11 @@ void Data::initializeFakeData()
m_streams[net1.id].append(stream1);
// Particles for Personal Notes
m_particles[stream1.id].append({"p1", "text", true});
m_particles[stream1.id].append({"p2", "link", false});
m_particles[stream1.id].append({"p3", "image", true});
m_particles[stream1.id].append({"p4", "text", false});
m_particles[stream1.id].append({"p5", "link", true});
m_particles[stream1.id].append({"p1", "text", "[email protected]", "Meeting notes from standup", true});
m_particles[stream1.id].append({"p2", "link", "[email protected]", "API documentation for new endpoint", false});
m_particles[stream1.id].append({"p3", "image", "[email protected]", "Screenshot of bug in login flow", true});
m_particles[stream1.id].append({"p4", "text", "[email protected]", "Quick thought about architecture refactor", false});
m_particles[stream1.id].append({"p5", "link", "[email protected]", "Design inspiration board from Dribbble", true});
// Stream: Quick Captures
Stream stream2;
@@ -40,8 +40,8 @@ void Data::initializeFakeData()
m_streams[net1.id].append(stream2);
// Particles for Quick Captures
m_particles[stream2.id].append({"p6", "text", true});
m_particles[stream2.id].append({"p7", "image", true});
m_particles[stream2.id].append({"p6", "text", "[email protected]", "Remember to follow up on client feedback", true});
m_particles[stream2.id].append({"p7", "image", "[email protected]", "Mockup for new feature dashboard", true});
// Network 2: Flowy Labs, Inc
Network net2;
@@ -61,14 +61,14 @@ void Data::initializeFakeData()
m_streams[net2.id].append(stream3);
// Particles for Engineering
m_particles[stream3.id].append({"p8", "text", false});
m_particles[stream3.id].append({"p9", "link", true});
m_particles[stream3.id].append({"p10", "text", false});
m_particles[stream3.id].append({"p11", "image", true});
m_particles[stream3.id].append({"p12", "text", false});
m_particles[stream3.id].append({"p13", "link", false});
m_particles[stream3.id].append({"p14", "text", true});
m_particles[stream3.id].append({"p15", "image", false});
m_particles[stream3.id].append({"p8", "text", "[email protected]", "Sprint planning notes for Q1", false});
m_particles[stream3.id].append({"p9", "link", "[email protected]", "GitHub PR for authentication refactor", true});
m_particles[stream3.id].append({"p10", "text", "[email protected]", "Performance optimization opportunities", false});
m_particles[stream3.id].append({"p11", "image", "[email protected]", "Architecture diagram for new service", true});
m_particles[stream3.id].append({"p12", "text", "[email protected]", "Code review feedback summary", false});
m_particles[stream3.id].append({"p13", "link", "[email protected]", "Documentation for API v2 endpoints", false});
m_particles[stream3.id].append({"p14", "text", "[email protected]", "Bug report from production", true});
m_particles[stream3.id].append({"p15", "image", "[email protected]", "Database schema migration plan", false});
// Stream: Design
Stream stream4;
@@ -79,10 +79,10 @@ void Data::initializeFakeData()
m_streams[net2.id].append(stream4);
// Particles for Design
m_particles[stream4.id].append({"p16", "image", false});
m_particles[stream4.id].append({"p17", "text", true});
m_particles[stream4.id].append({"p18", "link", false});
m_particles[stream4.id].append({"p19", "image", true});
m_particles[stream4.id].append({"p16", "image", "[email protected]", "UI mockup for mobile dashboard", false});
m_particles[stream4.id].append({"p17", "text", "[email protected]", "Design system color palette updates", true});
m_particles[stream4.id].append({"p18", "link", "[email protected]", "Figma file for user onboarding flow", false});
m_particles[stream4.id].append({"p19", "image", "[email protected]", "Wireframes for settings page", true});
// Stream: Archive
Stream stream5;
@@ -93,10 +93,21 @@ void Data::initializeFakeData()
m_streams[net2.id].append(stream5);
// Particles for Archive
for (int i = 20; i < 35; i++)
{
m_particles[stream5.id].append({QString("p%1").arg(i), "text", true});
}
m_particles[stream5.id].append({"p20", "text", "[email protected]", "Old project requirements document", true});
m_particles[stream5.id].append({"p21", "text", "[email protected]", "Archived meeting notes from Q4", true});
m_particles[stream5.id].append({"p22", "link", "[email protected]", "Deprecated API documentation", true});
m_particles[stream5.id].append({"p23", "text", "[email protected]", "Legacy feature specification", true});
m_particles[stream5.id].append({"p24", "image", "[email protected]", "Old design mockups", true});
m_particles[stream5.id].append({"p25", "text", "[email protected]", "Historical performance metrics", true});
m_particles[stream5.id].append({"p26", "link", "[email protected]", "Archive of old blog posts", true});
m_particles[stream5.id].append({"p27", "text", "[email protected]", "Sunset project final report", true});
m_particles[stream5.id].append({"p28", "image", "[email protected]", "Previous branding assets", true});
m_particles[stream5.id].append({"p29", "text", "[email protected]", "Completed milestone summary", true});
m_particles[stream5.id].append({"p30", "link", "[email protected]", "Old repository backup link", true});
m_particles[stream5.id].append({"p31", "text", "[email protected]", "Archived customer feedback", true});
m_particles[stream5.id].append({"p32", "image", "[email protected]", "Previous UI iteration screenshots", true});
m_particles[stream5.id].append({"p33", "text", "[email protected]", "Legacy code documentation", true});
m_particles[stream5.id].append({"p34", "link", "[email protected]", "Historical release notes", true});
}
const QList<Network>& Data::networks() const
+2
View File
@@ -30,6 +30,8 @@ struct Particle
{
QString id;
QString type;
QString createdBy;
QString summary;
bool seen;
};
+85 -13
View File
@@ -171,19 +171,91 @@
<height>0</height>
</size>
</property>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>140</x>
<y>300</y>
<width>111</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Main content area</string>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>36</pointsize>
</font>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;hey I'll take a look later today&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_3" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>376</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>[email protected]</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>376</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>acked by: arthur, ed, sam</string>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
+39 -7
View File
@@ -1,4 +1,6 @@
#include "particlelistmodel.h"
#include <QApplication>
#include <QStyle>
ParticleListModel::ParticleListModel(Data *data, QObject *parent)
: QAbstractListModel(parent), m_data(data), m_currentStreamId()
@@ -22,7 +24,7 @@ int ParticleListModel::rowCount(const QModelIndex &parent) const
QVariant ParticleListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || role != Qt::DisplayRole)
if (!index.isValid())
{
return QVariant();
}
@@ -41,15 +43,33 @@ QVariant ParticleListModel::data(const QModelIndex &index, int role) const
const Particle &particle = particles.at(index.row());
// Show dot (•) for unseen, nothing for seen
if (particle.seen)
if (role == Qt::DisplayRole)
{
return particle.type;
QString emailPrefix = particle.createdBy.split("@")[0];
QString display = QString("[%1] - %2").arg(emailPrefix, particle.summary);
if (!particle.seen)
{
display += "";
}
return display;
}
else
else if (role == Qt::DecorationRole)
{
return QString("%1 •").arg(particle.type);
// Return icon based on type
QStyle::StandardPixmap pixmap;
if (particle.type == "text")
pixmap = QStyle::SP_FileIcon;
else if (particle.type == "link")
pixmap = QStyle::SP_CommandLink;
else if (particle.type == "image")
pixmap = QStyle::SP_FileDialogContentsView;
else
return QVariant();
return qApp->style()->standardIcon(pixmap);
}
return QVariant();
}
void ParticleListModel::setStreamId(const QString &streamId)
@@ -75,5 +95,17 @@ int ParticleListModel::firstUnseenRow() const
}
}
return -1; // All seen or empty
return -1; // All seen or empty
}
const Particle *ParticleListModel::particleAtRow(int row) const
{
if (m_currentStreamId.isEmpty())
return nullptr;
const QList<Particle> &particles = m_data->particlesForStream(m_currentStreamId);
if (row >= 0 && row < particles.size())
return &particles.at(row);
return nullptr;
}
+1
View File
@@ -16,6 +16,7 @@ public:
void setStreamId(const QString &streamId);
int firstUnseenRow() const; // Returns -1 if none unseen
const Particle* particleAtRow(int row) const;
private:
Data *m_data;