diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user index e0fc734..ab32e35 100644 --- a/CMakeLists.txt.user +++ b/CMakeLists.txt.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -106,15 +106,15 @@ 2 false - -DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} -DCMAKE_BUILD_TYPE:STRING=Debug --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_GENERATOR:STRING=Ninja 0 /Users/talksik/Documents/code/llink/build/Qt_6_8_6_for_macOS-Debug @@ -164,15 +164,15 @@ 2 false - -DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} -DCMAKE_BUILD_TYPE:STRING=Release --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_GENERATOR:STRING=Ninja /Users/talksik/Documents/code/llink/build/Qt_6_8_6_for_macOS-Release @@ -219,15 +219,15 @@ 2 false - -DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_GENERATOR:STRING=Ninja /Users/talksik/Documents/code/llink/build/Qt_6_8_6_for_macOS-RelWithDebInfo @@ -274,15 +274,15 @@ 2 false - -DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_GENERATOR:STRING=Ninja 0 /Users/talksik/Documents/code/llink/build/Qt_6_8_6_for_macOS-Profile @@ -330,15 +330,15 @@ 2 false - -DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON --DCMAKE_GENERATOR:STRING=Ninja --DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} + -DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} -DCMAKE_BUILD_TYPE:STRING=MinSizeRel --DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} --DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} --DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} -DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake --DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_COLOR_DIAGNOSTICS:BOOL=ON +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_GENERATOR:STRING=Ninja /Users/talksik/Documents/code/llink/build/Qt_6_8_6_for_macOS-MinSizeRel diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index d7332ca..f51f5ff 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -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); + } +} diff --git a/src/MainWindow.h b/src/MainWindow.h index 6c648d4..c9ee184 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -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(); diff --git a/src/data.cpp b/src/data.cpp index 4c632a1..a918a2d 100644 --- a/src/data.cpp +++ b/src/data.cpp @@ -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", "viet@flowy.com", "Meeting notes from standup", true}); + m_particles[stream1.id].append({"p2", "link", "viet@flowy.com", "API documentation for new endpoint", false}); + m_particles[stream1.id].append({"p3", "image", "stephen@flowy.com", "Screenshot of bug in login flow", true}); + m_particles[stream1.id].append({"p4", "text", "stephen@flowy.com", "Quick thought about architecture refactor", false}); + m_particles[stream1.id].append({"p5", "link", "anthony@flowy.com", "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", "alice@flowy.com", "Remember to follow up on client feedback", true}); + m_particles[stream2.id].append({"p7", "image", "bob@flowy.com", "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", "charlie@flowy.com", "Sprint planning notes for Q1", false}); + m_particles[stream3.id].append({"p9", "link", "dave@flowy.com", "GitHub PR for authentication refactor", true}); + m_particles[stream3.id].append({"p10", "text", "eve@flowy.com", "Performance optimization opportunities", false}); + m_particles[stream3.id].append({"p11", "image", "frank@flowy.com", "Architecture diagram for new service", true}); + m_particles[stream3.id].append({"p12", "text", "grace@flowy.com", "Code review feedback summary", false}); + m_particles[stream3.id].append({"p13", "link", "henry@flowy.com", "Documentation for API v2 endpoints", false}); + m_particles[stream3.id].append({"p14", "text", "ivy@flowy.com", "Bug report from production", true}); + m_particles[stream3.id].append({"p15", "image", "jack@flowy.com", "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", "karen@flowy.com", "UI mockup for mobile dashboard", false}); + m_particles[stream4.id].append({"p17", "text", "leo@flowy.com", "Design system color palette updates", true}); + m_particles[stream4.id].append({"p18", "link", "maya@flowy.com", "Figma file for user onboarding flow", false}); + m_particles[stream4.id].append({"p19", "image", "nathan@flowy.com", "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", "oliver@flowy.com", "Old project requirements document", true}); + m_particles[stream5.id].append({"p21", "text", "patricia@flowy.com", "Archived meeting notes from Q4", true}); + m_particles[stream5.id].append({"p22", "link", "quinn@flowy.com", "Deprecated API documentation", true}); + m_particles[stream5.id].append({"p23", "text", "rachel@flowy.com", "Legacy feature specification", true}); + m_particles[stream5.id].append({"p24", "image", "sam@flowy.com", "Old design mockups", true}); + m_particles[stream5.id].append({"p25", "text", "tina@flowy.com", "Historical performance metrics", true}); + m_particles[stream5.id].append({"p26", "link", "uma@flowy.com", "Archive of old blog posts", true}); + m_particles[stream5.id].append({"p27", "text", "victor@flowy.com", "Sunset project final report", true}); + m_particles[stream5.id].append({"p28", "image", "wendy@flowy.com", "Previous branding assets", true}); + m_particles[stream5.id].append({"p29", "text", "xavier@flowy.com", "Completed milestone summary", true}); + m_particles[stream5.id].append({"p30", "link", "yara@flowy.com", "Old repository backup link", true}); + m_particles[stream5.id].append({"p31", "text", "zack@flowy.com", "Archived customer feedback", true}); + m_particles[stream5.id].append({"p32", "image", "alice@flowy.com", "Previous UI iteration screenshots", true}); + m_particles[stream5.id].append({"p33", "text", "bob@flowy.com", "Legacy code documentation", true}); + m_particles[stream5.id].append({"p34", "link", "charlie@flowy.com", "Historical release notes", true}); } const QList& Data::networks() const diff --git a/src/data.h b/src/data.h index ea298f5..0af4d56 100644 --- a/src/data.h +++ b/src/data.h @@ -30,6 +30,8 @@ struct Particle { QString id; QString type; + QString createdBy; + QString summary; bool seen; }; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index a4e2980..c439bdc 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -171,19 +171,91 @@ 0 - - - - 140 - 300 - 111 - 16 - - - - Main content area - - + + + + + + 0 + 2 + + + + QFrame::Shape::StyledPanel + + + QFrame::Shadow::Raised + + + + + + + 0 + 2 + + + + + 36 + + + + <html><head/><body><p>hey I'll take a look later today</p></body></html> + + + Qt::AlignmentFlag::AlignCenter + + + true + + + + + + + + + + + 0 + 1 + + + + + + 10 + 0 + 376 + 31 + + + + + true + + + + mike@inra.com + + + + + + 10 + 30 + 376 + 31 + + + + acked by: arthur, ed, sam + + + + + diff --git a/src/particlelistmodel.cpp b/src/particlelistmodel.cpp index 1c01ed2..04cbf7b 100644 --- a/src/particlelistmodel.cpp +++ b/src/particlelistmodel.cpp @@ -1,4 +1,6 @@ #include "particlelistmodel.h" +#include +#include 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 &particles = m_data->particlesForStream(m_currentStreamId); + if (row >= 0 && row < particles.size()) + return &particles.at(row); + + return nullptr; } diff --git a/src/particlelistmodel.h b/src/particlelistmodel.h index be0c5df..af1c53a 100644 --- a/src/particlelistmodel.h +++ b/src/particlelistmodel.h @@ -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;