Selectable show/hide planned activities (#4811)

This commit is contained in:
Paul Johnson
2026-01-22 20:49:55 +00:00
committed by GitHub
parent 1a4dd1d10f
commit 07e673d5d5
7 changed files with 93 additions and 6 deletions

View File

@@ -303,6 +303,8 @@
#define GC_NAVGROUPBY "<athlete-preferences>navigator/groupby"
#define GC_SORTBY "<athlete-preferences>navigator/sortby"
#define GC_SORTBYORDER "<athlete-preferences>navigator/sortbyorder"
#define GC_NAVDISPLAYFILTER "<athlete-preferences>navigator/displayfilter"
// Calendar sync
#define GC_WEBCAL_URL "<athlete-preferences>webcal_url"

View File

@@ -151,6 +151,21 @@ AnalysisSidebar::AnalysisSidebar(Context *context) : QWidget(context->mainWindow
splitter->addWidget(activityItem);
splitter->addWidget(intervalItem);
// create the ride navs display filter
activityFilter = new QComboBox(this);
activityFilter->addItem(tr("All"), static_cast<int>(RideNavFilter::ALL));
activityFilter->addItem(tr("Actual"), static_cast<int>(RideNavFilter::COMPLETED));
activityFilter->addItem(tr("Planned"), static_cast<int>(RideNavFilter::PLANNED));
int index = appsettings->cvalue(context->athlete->cyclist, GC_NAVDISPLAYFILTER, "0").toInt();
activityFilter->setCurrentIndex(index);
setDisplayFilter(index);
// add ride navs display filter to splitter's banner
QHBoxLayout* splitterBanner = activityItem->splitterHandle->getTitleLayout();
splitterBanner->insertStretch(2);
splitterBanner->insertWidget(2, activityFilter);
splitterBanner->insertStretch(2);
splitter->prepare(context->athlete->cyclist, "analysis");
// GC signal
@@ -164,11 +179,19 @@ AnalysisSidebar::AnalysisSidebar(Context *context) : QWidget(context->mainWindow
connect(intervalTree,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(clickZoomInterval(QTreeWidgetItem*)));
connect(intervalTree,SIGNAL(itemSelectionChanged()), this, SLOT(itemSelectionChanged()));
connect(activityFilter, &QComboBox::currentIndexChanged, this, &AnalysisSidebar::setDisplayFilter);
connect (context, SIGNAL(filterChanged()), this, SLOT(filterChanged()));
configChanged(CONFIG_APPEARANCE);
}
void
AnalysisSidebar::setDisplayFilter(int index)
{
appsettings->setCValue(context->athlete->cyclist, GC_NAVDISPLAYFILTER, index);
rideNavigator->setDisplayFilter(static_cast<RideNavFilter>(index));
}
void
AnalysisSidebar::intervalItemSelectionChanged(IntervalItem*x)
{
@@ -332,6 +355,15 @@ AnalysisSidebar::configChanged(qint32)
//intervalSummaryWindow->setStyleSheet(GCColor::stylesheet());
splitter->setPalette(GCColor::palette());
// mimic the perspective selector colors for the activity filter
QColor selected;
if (GCColor::invertColor(GColor(CTOOLBAR)) == Qt::white) selected = QColor(Qt::lightGray);
else selected = QColor(Qt::darkGray);
activityFilter->setStyleSheet(
QString("QComboBox { background: %1; color: %2; border: 1px solid rgba(127,127,127,127); border-radius: 3; }")
.arg(GColor(CTOOLBAR).name()).arg(selected.name()));
activityHistory->setStyleSheet(QString("background: %1;").arg(GColor(CPLOTBACKGROUND).name()));
rideNavigator->tableView->viewport()->setPalette(GCColor::palette());
rideNavigator->tableView->viewport()->setStyleSheet(QString("background: %1;").arg(GColor(CPLOTBACKGROUND).name()));

View File

@@ -43,6 +43,7 @@ class AnalysisSidebar : public QWidget
AnalysisSidebar(Context *context);
void close();
void setWidth(int x) { rideNavigator->setWidth(x); }
RideNavigator *rideNavigator;
signals:
@@ -89,6 +90,10 @@ class AnalysisSidebar : public QWidget
void perfTestIntervalSelected();
void createPerfTestIntervalSelected();
protected slots:
void setDisplayFilter(int index);
private:
Context *context;
@@ -97,6 +102,7 @@ class AnalysisSidebar : public QWidget
QWidget *activityHistory;
GcSplitterItem *activityItem;
QSignalMapper *groupByMapper;
QComboBox* activityFilter;
GcSplitterItem *calendarItem;
GcMultiCalendar *calendarWidget;

View File

@@ -109,6 +109,8 @@ public:
void addAction(QAction *action);
void addActions(QList<QAction*> actions);
QHBoxLayout* getTitleLayout() { return titleLayout; }
protected:
void paintEvent(QPaintEvent *);
GcSubSplitter *gcSplitter;

View File

@@ -371,6 +371,13 @@ void RideNavigator::clearSearch()
setWidth(geometry().width()); // before we update column sizes!
}
void
RideNavigator::setDisplayFilter(RideNavFilter filter)
{
searchFilter->setDisplayFilter(filter);
QApplication::processEvents(); // repaint/resize list view - scrollbar..
}
void RideNavigator::setWidth(int x)
{
// use helper function

View File

@@ -51,6 +51,9 @@ class EditUserSeriesDialog;
class OverviewItemConfig;
class RideMetric;
// Ride Navigator activity list display filter options
enum class RideNavFilter { ALL=0, COMPLETED, PLANNED };
//
// The RideNavigator
//
@@ -158,6 +161,8 @@ class RideNavigator : public GcChartWindow
void resetView(); // when columns/width changes
void setDisplayFilter(RideNavFilter filter);
void searchStrings(QStringList);
void clearSearch();

View File

@@ -629,7 +629,7 @@ class SearchFilter : public QSortFilterProxyModel
public:
SearchFilter(QWidget *p) : QSortFilterProxyModel(p), searchActive(false) {}
SearchFilter(QWidget *p) : QSortFilterProxyModel(p), searchActive(false), rideNavFilter(RideNavFilter::ALL) {}
void setSourceModel(QAbstractItemModel *model) {
QAbstractProxyModel::setSourceModel(model);
@@ -637,11 +637,15 @@ class SearchFilter : public QSortFilterProxyModel
// find the filename column
fileIndex = -1;
plannedIndex = -1;
for(int i=0; i<model->columnCount(); i++) {
if (model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString() == "filename"
|| model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString() == tr("File")) {
fileIndex = i;
}
if (model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString() == "planned") {
plannedIndex = i;
}
}
// make sure changes are propogated upstream
@@ -654,18 +658,45 @@ class SearchFilter : public QSortFilterProxyModel
bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const {
if (fileIndex == -1 || searchActive == false) return true; // nothing to do
if (fileIndex == -1 || plannedIndex == -1) return true; // nothing to do
bool keyFound = true;
bool display = true;
// lets get the ride nav display filter first
QModelIndex planned_index = model->index(source_row, plannedIndex, source_parent);
if (planned_index.isValid()) {
if (model->data(planned_index, Qt::DisplayRole).toBool()) {
if (rideNavFilter == RideNavFilter::COMPLETED) display = false; // planned row, hide if completed only
} else {
if (rideNavFilter == RideNavFilter::PLANNED) display = false; // completed activity, hide if planned only
}
}
// lets get the filename
QModelIndex source_index = model->index(source_row, fileIndex, source_parent);
if (!source_index.isValid()) return true;
if (searchActive) {
QString key = model->data(source_index, Qt::DisplayRole).toString();
return strings.contains(key);
QModelIndex source_index = model->index(source_row, fileIndex, source_parent);
if (source_index.isValid()) {
QString key = model->data(source_index, Qt::DisplayRole).toString();
keyFound = strings.contains(key);
}
}
// combine the two filters
return keyFound && display;
}
public slots:
void setDisplayFilter(RideNavFilter filter) {
beginResetModel();
rideNavFilter = filter;
endResetModel();
}
void setStrings(QStringList list) {
beginResetModel();
strings = list;
@@ -684,6 +715,8 @@ class SearchFilter : public QSortFilterProxyModel
QAbstractItemModel *model;
QStringList strings;
int fileIndex;
int plannedIndex;
bool searchActive;
RideNavFilter rideNavFilter;
};
#endif