From e1d69f71e1aae9610bf0972deb5808dbd99b0930 Mon Sep 17 00:00:00 2001 From: Justin Knotzke Date: Thu, 8 Jul 2010 19:30:20 -0400 Subject: [PATCH] Tweet your ride. You can now tweet your ride from GC --- src/ConfigDialog.cpp | 14 +++ src/ConfigDialog.h | 1 + src/MainWindow.cpp | 20 ++++ src/MainWindow.h | 1 + src/Pages.cpp | 26 +++++ src/Pages.h | 31 ++++++ src/Settings.h | 2 + src/TwitterDialog.cpp | 226 ++++++++++++++++++++++++++++++++++++++++++ src/TwitterDialog.h | 47 +++++++++ src/application.qrc | 1 + src/src.pro | 2 + 11 files changed, 371 insertions(+) create mode 100644 src/TwitterDialog.cpp create mode 100644 src/TwitterDialog.h diff --git a/src/ConfigDialog.cpp b/src/ConfigDialog.cpp index 2650941fa..26f64945b 100644 --- a/src/ConfigDialog.cpp +++ b/src/ConfigDialog.cpp @@ -45,10 +45,13 @@ ConfigDialog::ConfigDialog(QDir _home, Zones *_zones, MainWindow *mainWindow) : configPage = new ConfigurationPage(mainWindow); devicePage = new DevicePage(this); + twitterPage = new TwitterPage(this); + pagesWidget = new QStackedWidget; pagesWidget->addWidget(configPage); pagesWidget->addWidget(cyclistPage); pagesWidget->addWidget(devicePage); + pagesWidget->addWidget(twitterPage); closeButton = new QPushButton(tr("Close")); saveButton = new QPushButton(tr("Save")); @@ -114,6 +117,12 @@ void ConfigDialog::createIcons() realtimeButton->setTextAlignment(Qt::AlignHCenter); realtimeButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + QListWidgetItem *twitterButton = new QListWidgetItem(contentsWidget); + twitterButton->setIcon(QIcon(":images/twitter.png")); + twitterButton->setText(tr("Twitter")); + twitterButton->setTextAlignment(Qt::AlignHCenter); + twitterButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + connect(contentsWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(changePage(QListWidgetItem *, QListWidgetItem*))); @@ -160,6 +169,11 @@ void ConfigDialog::save_Clicked() settings->setValue(GC_LTS_DAYS, cyclistPage->perfManLTSavg->text()); settings->setValue(GC_SB_TODAY, (int) cyclistPage->showSBToday->isChecked()); + //Save Twitter - Info PASSWORD IS IN CLEAR + settings->setValue(GC_TWITTER_USERNAME, twitterPage->accountName->text()); + settings->setValue(GC_TWITTER_PASSWORD, twitterPage->passwordEdit->text()); + + // set default stress names if not set: settings->setValue(GC_STS_NAME, settings->value(GC_STS_NAME,tr("Short Term Stress"))); settings->setValue(GC_STS_ACRONYM, settings->value(GC_STS_ACRONYM,tr("STS"))); diff --git a/src/ConfigDialog.h b/src/ConfigDialog.h index a6e912ee1..d9a6fd972 100644 --- a/src/ConfigDialog.h +++ b/src/ConfigDialog.h @@ -38,6 +38,7 @@ class ConfigDialog : public QDialog ConfigurationPage *configPage; CyclistPage *cyclistPage; DevicePage *devicePage; + TwitterPage *twitterPage; QPushButton *saveButton; QStackedWidget *pagesWidget; QPushButton *closeButton; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 905ebabf4..0f8237c14 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -66,6 +66,7 @@ #include "SplitRideDialog.h" #include "PerformanceManagerWindow.h" #include "TrainWindow.h" +#include "TwitterDialog.h" #ifndef GC_VERSION #define GC_VERSION "(developer build)" @@ -897,6 +898,8 @@ MainWindow::showTreeContextMenuPopup(const QPoint &pos) QAction *actSplitRide = new QAction(tr("Split Ride"), treeWidget); connect(actSplitRide, SIGNAL(triggered(void)), this, SLOT(splitRide())); + QAction *actTweetRide = new QAction(tr("Tweet Ride"), treeWidget); + connect(actTweetRide, SIGNAL(triggered(void)), this, SLOT(tweetRide())); if (rideItem->isDirty() == true) { @@ -908,6 +911,7 @@ MainWindow::showTreeContextMenuPopup(const QPoint &pos) menu.addAction(actBestInt); menu.addAction(actPowerPeaks); menu.addAction(actSplitRide); + menu.addAction(actTweetRide); menu.exec(treeWidget->mapToGlobal( pos )); } @@ -1425,3 +1429,19 @@ MainWindow::manualProcess(QString name) p->exec(); } } + +void +MainWindow::tweetRide() +{ + QTreeWidgetItem *_item = treeWidget->currentItem(); + if (_item==NULL || _item->type() != RIDE_TYPE) + return; + + RideItem *item = dynamic_cast(_item); + item->computeMetrics(); + + TwitterDialog *twitterDialog = new TwitterDialog(this, item); + twitterDialog->setWindowModality(Qt::ApplicationModal); + twitterDialog->exec(); +} + diff --git a/src/MainWindow.h b/src/MainWindow.h index 06bc9b079..97cadb592 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -158,6 +158,7 @@ class MainWindow : public QMainWindow void frontInterval(); void backInterval(); void intervalEdited(QTreeWidgetItem *, int); + void tweetRide(); protected: diff --git a/src/Pages.cpp b/src/Pages.cpp index 51b33b8eb..d908ede1a 100644 --- a/src/Pages.cpp +++ b/src/Pages.cpp @@ -1819,3 +1819,29 @@ CPPage::zonesChanged() } } } +// +// Twitter Config page +// +TwitterPage::TwitterPage(QWidget *parent) : QWidget(parent) +{ + boost::shared_ptr settings = GetApplicationSettings(); + QTabWidget *tabs = new QTabWidget(this); + QWidget *twitter = new QWidget(this); + tabs->addTab(twitter, tr("Twitter Config")); + QHBoxLayout *twitterlayout = new QHBoxLayout(twitter); + + accountLabel = new QLabel(tr("Twitter User Name"),this); + accountName = new QLineEdit(tr(""), this); + + passwordLabel = new QLabel(tr("Password"),this); + passwordEdit = new QLineEdit(tr(""), this); + passwordEdit->setEchoMode(QLineEdit::Password); + + twitterlayout->addWidget(accountLabel); + twitterlayout->addWidget(accountName); + twitterlayout->addWidget(passwordLabel); + twitterlayout->addWidget(passwordEdit); + + accountName->setText(settings->value(GC_TWITTER_USERNAME).toString()); + passwordEdit->setText(settings->value(GC_TWITTER_PASSWORD).toString()); +} diff --git a/src/Pages.h b/src/Pages.h index 2c9909c4c..ce9e546fe 100644 --- a/src/Pages.h +++ b/src/Pages.h @@ -395,4 +395,35 @@ class ZonePage : public QWidget // local versions for modification }; +class TwitterPage : public QWidget +{ + Q_OBJECT + + public: + + TwitterPage(QWidget *parent = 0); + void saveClicked(); + + // Children talk to each other + SchemePage *schemePage; + CPPage *cpPage; + QLineEdit *accountName; + QLineEdit *passwordEdit; + + public slots: + + + protected: + + MainWindow *main; + bool changed; + + QTabWidget *tabs; + + // local versions for modification + private: + QLabel *accountLabel; + QLabel *passwordLabel; +}; + #endif diff --git a/src/Settings.h b/src/Settings.h index 8f65bd28e..8595c7201 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -61,6 +61,8 @@ #define GC_WORKOUTDIR "workoutDir" #define GC_TRAIN_SPLITTER_SIZES "trainwindow/splitterSizes" #define GC_LTM_SPLITTER_SIZES "ltmwindow/splitterSizes" +#define GC_TWITTER_USERNAME "TwitterUser" +#define GC_TWITTER_PASSWORD "TwitterPass" // device Configurations NAME/SPEC/TYPE/DEFI/DEFR all get a number appended // to them to specify which configured device i.e. devices1 ... devicesn where diff --git a/src/TwitterDialog.cpp b/src/TwitterDialog.cpp new file mode 100644 index 000000000..8ca1d0d85 --- /dev/null +++ b/src/TwitterDialog.cpp @@ -0,0 +1,226 @@ +#include "TwitterDialog.h" +#include "Settings.h" +#include +#include +#include "TimeUtils.h" + +TwitterDialog::TwitterDialog(MainWindow *mainWindow, RideItem *item) : + mainWindow(mainWindow) +{ + ride = item; + settings = GetApplicationSettings(); + setAttribute(Qt::WA_DeleteOnClose); + setWindowTitle("Tweet Your Ride"); + QVBoxLayout *mainLayout = new QVBoxLayout(this); + + QGroupBox *groupBox = new QGroupBox(tr("Choose which metrics you wish to tweet: ")); + + workoutTimeChk = new QCheckBox(tr("Workout Time")); + timeRidingChk = new QCheckBox(tr("Time Riding")); + totalDistanceChk = new QCheckBox(tr("Total Distance")); + elevationGainChk = new QCheckBox(tr("Elevation Gain")); + totalWorkChk = new QCheckBox(tr("Total Work (kj)")); + averageSpeedChk = new QCheckBox(tr("Average Speed")); + averagePowerChk = new QCheckBox(tr("Average Power")); + averageHRMChk = new QCheckBox(tr("Average Heart Rate")); + averageCadenceChk = new QCheckBox(tr("Average Cadence")); + maxPowerChk = new QCheckBox(tr("Max Power")); + maxHRMChk = new QCheckBox(tr("Max Heart Rate")); + + QGridLayout *vbox = new QGridLayout(); + vbox->addWidget(workoutTimeChk,0,0); + vbox->addWidget(timeRidingChk,0,1); + vbox->addWidget(totalWorkChk,1,0); + vbox->addWidget(totalDistanceChk,1,1); + vbox->addWidget(elevationGainChk,2,0); + vbox->addWidget(averageSpeedChk,2,1); + vbox->addWidget(averagePowerChk,3,0); + vbox->addWidget(averageHRMChk,3,1); + vbox->addWidget(averageCadenceChk,4,0); + vbox->addWidget(maxPowerChk,4,1); + vbox->addWidget(maxHRMChk,5,0); + groupBox->setLayout(vbox); + + QHBoxLayout *twitterMetricLayout = new QHBoxLayout; + QLabel *twitterLabel = new QLabel(tr("Twitter Message:")); + twitterMessageEdit = new QLineEdit(); + twitterMetricLayout->addWidget(twitterLabel); + twitterMetricLayout->addWidget(twitterMessageEdit); + twitterLengthLabel = new QLineEdit(tr("Message Length: ")); + twitterLengthLabel->setEnabled(false); + twitterMetricLayout->addWidget(twitterLengthLabel); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + tweetButton = new QPushButton(tr("&Tweet Ride"), this); + buttonLayout->addWidget(tweetButton); + cancelButton = new QPushButton(tr("&Cancel"), this); + buttonLayout->addWidget(cancelButton); + mainLayout->addWidget(groupBox); + mainLayout->addLayout(twitterMetricLayout); + mainLayout->addLayout(buttonLayout); + + connect(tweetButton, SIGNAL(clicked()), this, SLOT(tweetCurrentRide())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + connect(workoutTimeChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(timeRidingChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(totalDistanceChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(elevationGainChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(totalWorkChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(averageSpeedChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(averagePowerChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(averageHRMChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(averageCadenceChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(maxPowerChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(maxHRMChk, SIGNAL(stateChanged(int)), this, SLOT(onCheck(int))); + connect(twitterMessageEdit, SIGNAL(textChanged(QString)), this, SLOT(tweetMsgChange(QString))); +} +void +TwitterDialog::tweetCurrentRide() +{ + setEnabled(false); + QString twitterMsg = getTwitterMessage(); + QString post = "/statuses/update.xml?status="; + QString strUrl = QUrl::toPercentEncoding(twitterMsg + " #goldencheetah"); + qDebug() << post << strUrl; + QHttp *twitter_http_updater = new QHttp(); + twitter_http_updater->setHost("www.twitter.com"); + twitter_http_updater->setUser(settings->value(GC_TWITTER_USERNAME).toString(), settings->value(GC_TWITTER_PASSWORD).toString()); + twitter_http_updater->post(post+strUrl, QByteArray()); + connect(twitter_http_updater, SIGNAL(done(bool)), this, SLOT(updateTwitterStatusFinish(bool))); +} + +void TwitterDialog::updateTwitterStatusFinish(bool error) +{ + if(error == true) + QMessageBox::warning(this, tr("Tweeted Ride"), tr("Tweet Not Sent")); + else + QMessageBox::information(this, tr("Tweeted Ride"), tr("Tweet Sent")); + + accept(); +} + +QString TwitterDialog::getTwitterMessage() +{ + RideMetricPtr m; + double tmp; + QString twitterMsg; + QVariant unit = settings->value(GC_UNIT); + bool useMetricUnits = (unit.toString() == "Metric"); + + if(workoutTimeChk->isChecked()) + { + m = ride->metrics.value("workout_time"); + tmp = round(m->value(true)); + QString msg = QString("Workout Time: %1").arg(time_to_string(tmp)); + twitterMsg.append(msg + " "); + } + + if(timeRidingChk->isChecked()) + { + m = ride->metrics.value("time_riding"); + tmp = round(m->value(true)); + QString msg = QString("Time Riding: %1").arg(time_to_string(tmp)); + twitterMsg.append(msg + " "); + } + + if(totalDistanceChk->isChecked()) + { + m = ride->metrics.value("total_distance"); + tmp = round(m->value(useMetricUnits)); + QString msg = QString("Total Distance: %1 " + (useMetricUnits ? tr("KM") : tr("Miles"))).arg(tmp); + qDebug() << msg; + twitterMsg.append(msg + " "); + } + + if(elevationGainChk->isChecked()) + { + m = ride->metrics.value("elevation_gain"); + tmp = round(m->value(useMetricUnits)); + QString msg = QString("Elevation Gained: %1"+ (useMetricUnits ? tr("Meters") : tr("Feet"))).arg(tmp); + twitterMsg.append(msg + " "); + } + + if(totalWorkChk->isChecked()) + { + m = ride->metrics.value("total_work"); + tmp = round(m->value(true)); + QString msg = QString("Total Work (kj): %1").arg(tmp); + twitterMsg.append(msg + " "); + } + + if(averageSpeedChk->isChecked()) + { + m = ride->metrics.value("average_speed"); + tmp = round(m->value(useMetricUnits)); + QString msg = QString("Average Speed: %1"+ (useMetricUnits ? tr("KM/H") : tr("MPH"))).arg(tmp); + twitterMsg.append(msg + " "); + } + + if(averagePowerChk->isChecked()) + { + m = ride->metrics.value("average_power"); + tmp = round(m->value(true)); + QString msg = QString("Average Power: %1 watts").arg(tmp); + twitterMsg.append(msg + " "); + } + + if(averageHRMChk->isChecked()) + { + m = ride->metrics.value("average_hr"); + tmp = round(m->value(true)); + QString msg = QString("Average Heart Rate: %1").arg(tmp); + twitterMsg.append(msg + " "); + } + + if(averageCadenceChk->isChecked()) + { + m = ride->metrics.value("average_cad"); + tmp = round(m->value(true)); + QString msg = QString("Average Cadence: %1").arg(tmp); + twitterMsg.append(msg + " "); + } + + if(maxPowerChk->isChecked()) + { + m = ride->metrics.value("max_power"); + tmp = round(m->value(true)); + QString msg = QString("Max Power: %1 watts").arg(tmp); + twitterMsg.append(msg + " "); + } + + if(maxHRMChk->isChecked()) + { + m = ride->metrics.value("max_heartrate"); + tmp = round(m->value(true)); + QString msg = QString("Max Heart Rate: %1").arg(tmp); + twitterMsg.append(msg + " "); + } + + QString msg = twitterMessageEdit->text(); + if(!msg.endsWith(" ")) + msg.append(" "); + + QString entireTweet = QString(msg + twitterMsg); + + return entireTweet; + +} + +void TwitterDialog::onCheck(int state) +{ + QString twitterMessage = getTwitterMessage(); + int tweetLength = twitterMessage.length(); + tweetLength += 15; //For the hashtag + QString tweetMsgLength = QString(tr("Message Length: %1")).arg(tweetLength); + twitterLengthLabel->setText(tweetMsgLength); +} + +void TwitterDialog::tweetMsgChange(QString) +{ + QString twitterMessage = getTwitterMessage(); + int tweetLength = twitterMessage.length(); + tweetLength += 15; //For the hashtag + QString tweetMsgLength = QString(tr("Message Length: %1")).arg(tweetLength); + twitterLengthLabel->setText(tweetMsgLength); +} diff --git a/src/TwitterDialog.h b/src/TwitterDialog.h new file mode 100644 index 000000000..b7f94bc9e --- /dev/null +++ b/src/TwitterDialog.h @@ -0,0 +1,47 @@ +#ifndef TWITTERDIALOG_H +#define TWITTERDIALOG_H + +#include +#include +#include "MainWindow.h" +#include "RideItem.h" + +class TwitterDialog : public QDialog +{ + Q_OBJECT +public: + TwitterDialog(MainWindow *mainWindow, RideItem *item); + +signals: + +private slots: + void updateTwitterStatusFinish(bool error); + void onCheck(int state); + void tweetMsgChange(QString); + void tweetCurrentRide(); +private: + + QPushButton *tweetButton; + QPushButton *cancelButton; + MainWindow *mainWindow; + QCheckBox *workoutTimeChk; + QCheckBox *timeRidingChk; + QCheckBox *totalDistanceChk; + QCheckBox *elevationGainChk; + QCheckBox *totalWorkChk; + QCheckBox *averageSpeedChk; + QCheckBox *averagePowerChk; + QCheckBox *averageHRMChk; + QCheckBox *averageCadenceChk; + QCheckBox *maxPowerChk; + QCheckBox *maxHRMChk; + QLineEdit *twitterMessageEdit; + QLineEdit *twitterLengthLabel; + + RideItem *ride; + QString getTwitterMessage(); + boost::shared_ptr settings; + +}; + +#endif // TWITTERDIALOG_H diff --git a/src/application.qrc b/src/application.qrc index 7448f987a..d8e73f467 100644 --- a/src/application.qrc +++ b/src/application.qrc @@ -1,5 +1,6 @@ + images/twitter.png images/cyclist.png images/imetrics.png images/power.png diff --git a/src/src.pro b/src/src.pro index 2ad849741..81008f738 100644 --- a/src/src.pro +++ b/src/src.pro @@ -151,6 +151,7 @@ HEADERS += \ TrainTabs.h \ TrainTool.h \ TrainWindow.h \ + TwitterDialog.h \ Units.h \ ViewSelection.h \ WeeklySummaryWindow.h \ @@ -258,6 +259,7 @@ SOURCES += \ TrainTabs.cpp \ TrainTool.cpp \ TrainWindow.cpp \ + TwitterDialog.cpp \ ViewSelection.cpp \ WeeklySummaryWindow.cpp \ WkoRideFile.cpp \