Compare commits

...

5 Commits

Author SHA1 Message Date
Alejandro Martinez
ff4f46ed91 Trigger v3.8-DEV2603
VERSION 3.8 DEVELOPMENT MAR 2026
2026-03-31 19:25:30 -03:00
Joachim Kohlhammer
30a9155b20 Reworked the repeat schedule wizard (#4850)
* Simplified design and concept
* Sticking closer to the original schedule
* Added option to keep gap days (front and back)
* Added option to use originally planned dates
* Removed options to insert rest days or spread same day activities
* Improved source range preselection
2026-03-31 11:48:55 -03:00
Joachim Kohlhammer
e30ce69ef2 Calendar summary was missing homeFilter (#4853)
Calendar summary only used filter, not homeFilter, thus showing wrong
values. This fix adds support for both filters
2026-03-30 19:32:52 -03:00
Alejandro Martinez
f89e8bbb74 Deprecate RouteWindow and add Segments chart
RouteWindows has beeen inactivated for years,
Replaced by a more flexible Python chart added
to default layout.
Required Jinja2 package added to included Python.
[publish binaries]
2026-03-30 15:02:24 -03:00
Alejandro Martinez
753758f893 Don't update intervals when metadata changes
It may be to expensive in some cases making the
user interfase too slow when updating fields
for little benefit, intervals are updated on save.
2026-03-29 13:16:37 -03:00
14 changed files with 849 additions and 311 deletions

View File

@@ -1089,6 +1089,7 @@ CalendarWindow::getSummaries
const RideMetricFactory &factory = RideMetricFactory::instance();
FilterSet filterSet(context->isfiltered, context->filters);
filterSet.addFilter(context->ishomefiltered, context->homeFilters);
Specification spec;
spec.setFilterSet(filterSet);
PlanFilterType planFilterType = PlanFilterType::IncludeAll;

View File

@@ -114,6 +114,7 @@
// 5005 - V3.7 RELEASE (March 2025)
// 5006 - V3.7 SP1 RELEASE (November 2025)
// 5010 - V3.8 DEVELOPMENT 2601 (JAN 2026)
// 5011 - V3.8 DEVELOPMENT 2603 (MAR 2026)
#define VERSION3_BUILD 3010 // released
#define VERSION3_SP1 3030 // released
@@ -127,14 +128,14 @@
#define VERSION36_BUILD 5000 // released 5/8/23
#define VERSION37_BUILD 5005 // released 28/3/25
#define VERSION37_SP1 5006 // released 20/11/25
#define VERSION38_DEV2601 5010 // (Jan 2026) - latest snapshot 7/2/26
#define VERSION38_DEV2603 5011 // (MAR 2026) - latest snapshot 31/3/26
// will keep changing during testing and before final release
#define VERSION31_BUILD VERSION31_UPG
// the next two will with each build/release
#define VERSION_LATEST 5010
#define VERSION_STRING "V3.8-DEV2601"
#define VERSION_LATEST 5011
#define VERSION_STRING "V3.8-DEV2603"
//#define GC_VERSION VERSION_STRING // To force version string on non-tagged ci builds
// default config for this release cycle

View File

@@ -584,7 +584,7 @@ bool RideItem::hasLinkedActivity() const
}
void
RideItem::refresh()
RideItem::refresh(bool bUpdateIntervals)
{
if (!isstale) return;
@@ -685,7 +685,7 @@ RideItem::refresh()
}
// Update auto intervals AFTER ridefilecache as used for bests
updateIntervals();
if (bUpdateIntervals) updateIntervals();
// update fingerprints etc, crc done above
fingerprint = static_cast<unsigned long>(context->athlete->zones(sport)->getFingerprint(dateTime.date()))

View File

@@ -223,7 +223,7 @@ class RideItem : public QObject
bool hasLinkedActivity() const;
// refresh when stale
void refresh();
void refresh(bool bUpdateIntervals=true);
// get/set
void setRide(RideFile *);

View File

@@ -57,8 +57,6 @@
#include "Overview.h"
#endif
#include "UserChartWindow.h"
// Not until v4.0
//#include "RouteWindow.h"
// GcWindows initialization is done in initialize method to enable translations
GcWindowRegistry* GcWindows;
@@ -231,11 +229,7 @@ GcWindowRegistry::newGcWindow(GcWinID id, Context *context)
case GcWindowTypes::WebPageWindow: returning = new WebPageWindow(context); break;
case GcWindowTypes::LiveMapWebPageWindow: returning = new LiveMapWebPageWindow(context); break;
case GcWindowTypes::ElevationChart: returning = new ElevationChartWindow(context); break;
#if 0 // not till v4.0
case GcWindowTypes::RouteSegment: returning = new RouteWindow(context); break;
#else
case GcWindowTypes::RouteSegment: returning = new GcChartWindow(context); break;
#endif
case GcWindowTypes::RouteSegment: returning = new GcChartWindow(context); break; // Deprecated
// summary and old ride summary charts now replaced with an Overview - note id gets reset
case GcWindowTypes::Summary:

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,76 @@
#include <QWizardPage>
#include <QLabel>
#include <QTreeWidget>
#include <QCheckBox>
#include <QRadioButton>
#include <QStyledItemDelegate>
struct SourceRide {
RideItem *rideItem = nullptr;
QDate sourceDate;
QDate targetDate;
bool selected = false;
int conflictGroup = -1;
bool targetBlocked = false;
};
class TargetRangeBar : public QFrame
{
Q_OBJECT
Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor)
public:
explicit TargetRangeBar(QString errorMsg, QWidget *parent = nullptr);
void setResult(const QDate &start, const QDate &end, int activityCount, int deletedCount);
void setFlashEnabled(bool enabled);
private:
enum class State {
Neutral,
Warning,
Error
};
QLabel *iconLabel;
QLabel *textLabel;
QColor baseColor;
QColor borderColor;
QColor hlColor;
State currentState;
const QString errorMsg;
bool flashEnabled = true;
void applyStateStyle(State state);
QString formatDuration(const QDate &start, const QDate &end) const;
QColor highlightColor() const;
void setHighlightColor(const QColor& color);
void flash();
};
class IndicatorDelegate : public QStyledItemDelegate
{
public:
enum Roles {
IndicatorTypeRole = Qt::UserRole + 1, // [IndicatorType] Whether this item has an indicator
IndicatorStateRole // [bool] Whether this items indicator is checked
};
enum IndicatorType {
NoIndicator = 0,
RadioIndicator = 1,
CheckIndicator = 2
};
explicit IndicatorDelegate(QObject *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
class RepeatScheduleWizard : public QWizard
@@ -42,12 +112,34 @@ class RepeatScheduleWizard : public QWizard
RepeatScheduleWizard(Context *context, const QDate &when, QWidget *parent = nullptr);
QList<SourceRide> sourceRides;
QDate getTargetRangeStart() const;
QDate getTargetRangeEnd() const;
int getPlannedInTargetRange() const;
const QList<RideItem*> &getDeletionList() const;
void updateTargetRange();
void updateTargetRange(QDate sourceStart, QDate sourceEnd, bool keepGap, bool preferOriginal);
signals:
void targetRangeChanged();
protected:
virtual void done(int result) override;
private:
Context *context;
QDate when;
QDate sourceRangeStart;
QDate sourceRangeEnd;
QDate targetRangeStart;
QDate targetRangeEnd;
int frontGap = 0;
QList<RideItem*> deletionList;
bool keepGap = false;
bool preferOriginal = false;
QDate getDate(RideItem const * const rideItem, bool preferOriginal) const;
};
@@ -59,9 +151,20 @@ class RepeatSchedulePageSetup : public QWizardPage
RepeatSchedulePageSetup(Context *context, const QDate &when, QWidget *parent = nullptr);
int nextId() const override;
void initializePage() override;
bool isComplete() const override;
private:
Context *context;
QDateEdit *startDate;
QDateEdit *endDate;
QCheckBox *keepGapCheck;
QRadioButton *originalRadio;
QRadioButton *currentRadio;
TargetRangeBar *targetRangeBar;
private slots:
void refresh();
};
@@ -76,12 +179,12 @@ class RepeatSchedulePageActivities : public QWizardPage
void initializePage() override;
bool isComplete() const override;
QList<RideItem*> getSelectedRideItems() const;
private:
Context *context;
QTreeWidget *activityTree;
TargetRangeBar *targetRangeBar;
int numSelected = 0;
QMetaObject::Connection dataChangedConnection;
};
@@ -90,28 +193,19 @@ class RepeatSchedulePageSummary : public QWizardPage
Q_OBJECT
public:
RepeatSchedulePageSummary(Context *context, const QDate &when, QWidget *parent = nullptr);
RepeatSchedulePageSummary(Context *context, QWidget *parent = nullptr);
int nextId() const override;
void initializePage() override;
bool isComplete() const override;
QList<RideItem*> getDeletionList() const;
QList<std::pair<RideItem*, QDate>> getScheduleList() const;
private:
Context *context;
QDate when;
bool failed = false;
QList<RideItem*> deletionList; // was: preexistingPlanned
QList<std::pair<RideItem*, QDate>> scheduleList; // was: targetMap
QLabel *failedLabel;
QLabel *scheduleLabel;
QTreeWidget *scheduleTree;
QLabel *deletionLabel;
QTreeWidget *deletionTree;
TargetRangeBar *targetRangeBar;
};
#endif // _GC_ManualActivityWizard_h
#endif

View File

@@ -9,6 +9,7 @@ scipy
lmfit
plotly
importlib_metadata
Jinja2
#
# Nice to have
#

File diff suppressed because one or more lines are too long

View File

@@ -789,12 +789,6 @@ win32-msvc* {
SOURCES += Core/WindowsCrashHandler.cpp
}
###======================================
### PENDING SOURCE FILES [not active yet]
###======================================
DEFERRES += Core/RouteWindow.h Core/RouteWindow.cpp Core/RouteItem.h Core/RouteItem.cpp
###====================
### MISCELLANEOUS FILES
###====================