diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63d51f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +arm/Makefile +arm/Makefile.Debug +arm/Makefile.Release \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..e427606 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +QMAKE_TARGET = Exporter +PROJECT_DIR := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))) +I18N_DIR := $(PROJECT_DIR)/translations + +include mk/cs-base.mk + diff --git a/arm/o.le-v7/Exporter-1_8_5_0.bar b/arm/o.le-v7/Exporter-1_8_5_0.bar new file mode 100644 index 0000000..0aaf7e1 Binary files /dev/null and b/arm/o.le-v7/Exporter-1_8_5_0.bar differ diff --git a/assets/.gitignore b/assets/.gitignore deleted file mode 100644 index 22b3572..0000000 --- a/assets/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/.DS_Store -/.assets.index diff --git a/assets/BasePage.qml b/assets/BasePage.qml index 7f88890..6370e2e 100644 --- a/assets/BasePage.qml +++ b/assets/BasePage.qml @@ -9,7 +9,7 @@ Page { attachedObjects: [ ImagePaintDefinition { id: back - imageSource: "asset:///images/background.amd" + imageSource: "images/background.amd" } ] @@ -23,7 +23,7 @@ Page { verticalAlignment: VerticalAlignment.Top ImageView { - imageSource: "asset:///images/title_bg.amd" + imageSource: "images/title_bg.amd" topMargin: 0 leftMargin: 0 rightMargin: 0 @@ -56,7 +56,7 @@ Page { leftPadding: 45; bottomPadding: 20 ImageView { - imageSource: "asset:///images/logo.png" + imageSource: "images/logo.png" topMargin: 0 leftMargin: 0 rightMargin: 0 diff --git a/assets/ConversationView.qml b/assets/ConversationView.qml index 37cf79f..ab28817 100644 --- a/assets/ConversationView.qml +++ b/assets/ConversationView.qml @@ -5,10 +5,20 @@ BasePage property variant contact onContactChanged: { - label.text = qsTr("Conversation with %1").arg(contact.name) - var messages = app.getMessagesFor(contact.conversationId) - theDataModel.clear() - theDataModel.append(messages) + label.text = qsTr("Conversation with %1").arg(contact.name); + var messages = app.getMessagesFor(contact.conversationId); + theDataModel.clear(); + theDataModel.append(messages); + } + + function onSettingChanged(key) { + if (key == "latestFirst" || key == "timeFormat" || key == "userName") { + contactChanged(contact); + } + } + + onCreationCompleted: { + persist.settingChanged.connect(onSettingChanged); } function concatenate() @@ -34,7 +44,7 @@ BasePage actions: [ ActionItem { - imageSource: "asset:///images/selectAll.png" + imageSource: "images/selectAll.png" ActionBar.placement: ActionBarPlacement.OnBar title: qsTr("Select All") + Retranslate.onLanguageChanged @@ -46,7 +56,7 @@ BasePage ActionItem { id: copyAction title: qsTr("Copy") + Retranslate.onLanguageChanged - imageSource: "asset:///images/ic_copy.png" + imageSource: "images/ic_copy.png" ActionBar.placement: ActionBarPlacement.OnBar enabled: false @@ -83,7 +93,7 @@ BasePage listView.first = listView.last = undefined listView.rangeSelect = true } - } + } ] contentContainer: Container @@ -99,7 +109,6 @@ BasePage horizontalAlignment: HorizontalAlignment.Fill verticalAlignment: VerticalAlignment.Fill textStyle.textAlign: TextAlign.Center - bottomMargin: 65 animations: [ FadeTransition { @@ -117,11 +126,8 @@ BasePage } } - Container - { - horizontalAlignment: HorizontalAlignment.Fill - preferredHeight: 1 - background: Color.LightGray + Divider { + bottomMargin: 0; topMargin: 0; } ListView { @@ -136,7 +142,7 @@ BasePage attachedObjects: [ ImagePaintDefinition { id: back - imageSource: "asset:///images/listitem.amd" + imageSource: "images/listitem.amd" } ] @@ -221,7 +227,7 @@ BasePage ActionSet { ActionItem { title: qsTr("Copy") + Retranslate.onLanguageChanged - imageSource: "asset:///images/ic_copy.png" + imageSource: "images/ic_copy.png" onTriggered: { listItemRoot.ListItem.view.copyToClipboard(ListItemData) diff --git a/assets/Cover.qml b/assets/Cover.qml index c7aff3a..4075eba 100644 --- a/assets/Cover.qml +++ b/assets/Cover.qml @@ -14,12 +14,12 @@ Container attachedObjects: [ ImagePaintDefinition { id: back - imageSource: "asset:///images/title_bg.png" + imageSource: "images/title_bg.png" } ] ImageView { - imageSource: "asset:///images/logo.png" + imageSource: "images/logo.png" horizontalAlignment: HorizontalAlignment.Center verticalAlignment: VerticalAlignment.Center } diff --git a/assets/SettingsPage.qml b/assets/SettingsPage.qml index ebaf763..44eed3f 100644 --- a/assets/SettingsPage.qml +++ b/assets/SettingsPage.qml @@ -19,10 +19,10 @@ BasePage { persist.saveValueFor("animations", checked ? 1 : 0) if (checked) { - infoText.text = qsTr("Controls will be animated whenever they are loaded.") - } else { - infoText.text = qsTr("Controls will be snapped into position without animations.") - } + infoText.text = qsTr("Controls will be animated whenever they are loaded.") + Retranslate.onLanguageChanged; + } else { + infoText.text = qsTr("Controls will be snapped into position without animations.") + Retranslate.onLanguageChanged; + } } } @@ -75,18 +75,18 @@ BasePage { persist.saveValueFor("timeFormat", selectedIndex); if (selectedIndex == 2) { - infoText.text = qsTr("The time will not be appended to the messages.") - } else if (selectedIndex == 0) { - infoText.text = qsTr("The time will will be appended in front of the messages with a format like Jan 4/13 10:15:03.") - } else { - infoText.text = qsTr("The time will will be appended in front of the messages with a format like 10:15:03.") - } + infoText.text = qsTr("The time will not be appended to the messages.") + Retranslate.onLanguageChanged; + } else if (selectedIndex == 0) { + infoText.text = qsTr("The time will will be appended in front of the messages with a format like Jan 4/13 10:15:03.") + Retranslate.onLanguageChanged; + } else { + infoText.text = qsTr("The time will will be appended in front of the messages with a format like 10:15:03.") + Retranslate.onLanguageChanged; + } } } Label { - text: qsTr("Your name shows up as:"); - textStyle.fontSize: FontSize.XSmall + text: qsTr("Your name shows up as:") + Retranslate.onLanguageChanged; + textStyle.fontSize: FontSize.XSmall textStyle.textAlign: TextAlign.Center } @@ -95,8 +95,8 @@ BasePage { onTextChanged: { persist.saveValueFor("userName", text); - infoText.text = qsTr("In the output, messages you sent will be prefixed by: %1").arg(text) - } + infoText.text = qsTr("In the output, messages you sent will be prefixed by: %1").arg(text) + Retranslate.onLanguageChanged + } text: persist.getValueFor("userName") @@ -107,21 +107,38 @@ BasePage { { topPadding: 20 - title: qsTr("Double-space") + title: qsTr("Double-space") + Retranslate.onLanguageChanged toggle.checked: persist.getValueFor("doubleSpace") == 1 toggle.onCheckedChanged: { persist.saveValueFor("doubleSpace", checked ? 1 : 0) if (checked) { - infoText.text = qsTr("Each message will be double-spaced for better readability.") + infoText.text = qsTr("Each message will be double-spaced for better readability.") + Retranslate.onLanguageChanged } else { - infoText.text = qsTr("Each message will be single-spaced.") + infoText.text = qsTr("Each message will be single-spaced.") + Retranslate.onLanguageChanged } } - } - - Label { + } + + SettingPair { + topPadding: 20 + + title: qsTr("Latest Message First") + Retranslate.onLanguageChanged; + toggle.checked: persist.getValueFor("latestFirst") == 1 + + toggle.onCheckedChanged: { + persist.saveValueFor("latestFirst", checked ? 1 : 0) + + if (checked) { + infoText.text = qsTr("Messages will be ordered from most recent to least recent."); + } else { + infoText.text = qsTr("Messages will be ordered from oldest to newest ."); + } + } + } + + Label { topMargin: 40 id: infoText multiline: true diff --git a/assets/images/title_bg.png b/assets/images/title_bg.png index d71fa1c..023d59d 100644 Binary files a/assets/images/title_bg.png and b/assets/images/title_bg.png differ diff --git a/assets/main.qml b/assets/main.qml index 568cb1f..7708081 100755 --- a/assets/main.qml +++ b/assets/main.qml @@ -52,7 +52,7 @@ NavigationPane { actions: [ ActionItem { - imageSource: "asset:///images/selectAll.png" + imageSource: "images/selectAll.png" ActionBar.placement: ActionBarPlacement.OnBar title: qsTr("Select All") + Retranslate.onLanguageChanged @@ -77,7 +77,6 @@ NavigationPane horizontalAlignment: HorizontalAlignment.Fill verticalAlignment: VerticalAlignment.Fill textStyle.textAlign: TextAlign.Center - bottomMargin: 65 animations: [ FadeTransition { @@ -95,11 +94,8 @@ NavigationPane } } - Container - { - horizontalAlignment: HorizontalAlignment.Fill - preferredHeight: 1 - background: Color.LightGray + Divider { + bottomMargin: 0; topMargin: 0; } ListView { @@ -207,7 +203,7 @@ NavigationPane onSelectionChanged: { var n = selectionList().length - multiSelectHandler.status = qsTr("%1 elements selected").arg(n) + multiSelectHandler.status = qsTr("%1 conversations selected").arg(n) multiExportAction.enabled = n > 0 } diff --git a/bar-descriptor.xml b/bar-descriptor.xml index f3d7442..c2c6fe2 100755 --- a/bar-descriptor.xml +++ b/bar-descriptor.xml @@ -35,11 +35,11 @@ - 1.7.0 + 1.8.5 - 5 + 0 diff --git a/precompiled.h b/precompiled.h index adba6a9..9bcfe8a 100755 --- a/precompiled.h +++ b/precompiled.h @@ -1,2 +1,21 @@ -// This file is used to store precompiled headers. -// It is intentionally left blank. It is up to you to decide which headers should be included here. +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include diff --git a/src/ApplicationUI.cpp b/src/ApplicationUI.cpp index b0d37a9..40f822d 100755 --- a/src/ApplicationUI.cpp +++ b/src/ApplicationUI.cpp @@ -1,18 +1,27 @@ +#include "precompiled.h" + #include "applicationui.hpp" #include "ExportSMS.h" #include "ImportSMS.h" #include "Logger.h" -#include - -#include -#include -#include +namespace { -#include -#include +void appendIfValid(bb::pim::message::Message const& m, QVariantList& variants) +{ + if ( !m.isDraft() && m.attachmentCount() > 0 && m.attachmentAt(0).mimeType() == "text/plain" ) + { + QVariantMap qvm; + qvm.insert( "inbound", m.isInbound() ); + qvm.insert( "id", m.id() ); + qvm.insert( "text", QString::fromLocal8Bit( m.attachmentAt(0).data() ) ); + qvm.insert( "sender", m.sender().displayableName() ); + qvm.insert( "time", m.serverTimestamp() ); + variants << qvm; + } +} -#include +} namespace exportui { @@ -20,14 +29,14 @@ using namespace bb::cascades; using namespace bb::system; using namespace bb::pim::message; -ApplicationUI::ApplicationUI(bb::cascades::Application *app) : QObject(app), m_cover("Cover.qml"), m_progress(NULL), m_adm(this) +ApplicationUI::ApplicationUI(bb::cascades::Application *app) : QObject(app), m_cover("Cover.qml"), m_adm(this) { INIT_SETTING("animations", 1); INIT_SETTING( "userName", tr("You") ); INIT_SETTING("timeFormat", 0); INIT_SETTING("duplicateAction", 0); - INIT_SETTING("separator", 1); INIT_SETTING("doubleSpace", 0); + INIT_SETTING("latestFirst", 1); if ( m_persistance.getValueFor("output").isNull() ) { // first run QString sdDirectory("/accounts/1000/removable/sdcard/documents"); @@ -70,19 +79,14 @@ QVariantList ApplicationUI::getMessagesFor(QString const& conversationKey) QList messages = messageService.messagesInConversation( m_accountId, conversationKey, MessageFilter() ); QVariantList variants; - for (int i = 0; i < messages.size(); i++) + if ( m_persistance.getValueFor("latestFirst") == 0 ) { - Message m = messages[i]; - - if ( !m.isDraft() && m.attachmentCount() > 0 && m.attachmentAt(0).mimeType() == "text/plain" ) - { - QVariantMap qvm; - qvm.insert( "inbound", m.isInbound() ); - qvm.insert( "id", m.id() ); - qvm.insert( "text", QString::fromLocal8Bit( m.attachmentAt(0).data() ) ); - qvm.insert( "sender", m.sender().displayableName() ); - qvm.insert( "time", m.serverTimestamp() ); - variants << qvm; + for (int i = 0; i < messages.size(); i++) { + appendIfValid(messages[i], variants); + } + } else { + for (int i = messages.size()-1; i >= 0; i--) { + appendIfValid(messages[i], variants); } } @@ -90,10 +94,8 @@ QVariantList ApplicationUI::getMessagesFor(QString const& conversationKey) } -void ApplicationUI::onExportCompleted() -{ +void ApplicationUI::onExportCompleted() { m_persistance.showToast( tr("Export complete") ); - m_progress->cancel(); } @@ -101,25 +103,11 @@ void ApplicationUI::exportSMS(QStringList const& conversationIds) { ExportSMS* sms = new ExportSMS(conversationIds, m_accountId); connect( sms, SIGNAL( exportCompleted() ), this, SLOT( onExportCompleted() ) ); - connect( sms, SIGNAL( progress(int) ), this, SLOT( onProgressChanged(int) ) ); - - if (m_progress == NULL) { - m_progress = new SystemProgressDialog(this); - m_progress->setTitle( tr("Exporting...") ); - } - - m_progress->setProgress(0); - m_progress->show(); startThread(sms); } -void ApplicationUI::onProgressChanged(int progress) { - m_progress->setProgress(progress); -} - - void ApplicationUI::startThread(QRunnable* qr) { qr->setAutoDelete(true); diff --git a/src/ExportSMS.cpp b/src/ExportSMS.cpp index 88cc684..ec18391 100644 --- a/src/ExportSMS.cpp +++ b/src/ExportSMS.cpp @@ -1,22 +1,25 @@ +#include "precompiled.h" + #include "ExportSMS.h" #include "Logger.h" -#include -#include - -#include -#include - namespace exportui { using namespace bb::pim::message; +using namespace bb::system; ExportSMS::ExportSMS(QStringList const& keys, qint64 const& accountId) : m_accountId(accountId), m_keys(keys) { + m_progress.setState(SystemUiProgressState::Inactive); } void ExportSMS::run() { + m_progress.setState(SystemUiProgressState::Active); + m_progress.setStatusMessage( tr("0% complete...") ); + m_progress.setProgress(0); + m_progress.show(); + QMap map; QSettings settings; @@ -124,10 +127,16 @@ void ExportSMS::run() LOGGER("Could not open " << key << "for writing!"); } - emit progress( (double)i/total * 100 ); + int progress = (double)i/total * 100; + m_progress.setProgress(progress); + m_progress.setStatusMessage( tr("%1% complete...").arg(progress) ); + m_progress.show(); } emit exportCompleted(); + + m_progress.cancel(); + m_progress.setState(SystemUiProgressState::Inactive); } } /* namespace exportui */ diff --git a/src/ExportSMS.h b/src/ExportSMS.h index df629e0..3435e84 100644 --- a/src/ExportSMS.h +++ b/src/ExportSMS.h @@ -1,10 +1,11 @@ #ifndef EXPORTSMS_H_ #define EXPORTSMS_H_ -#include #include #include +#include + namespace exportui { class ExportSMS : public QObject, public QRunnable @@ -13,10 +14,10 @@ class ExportSMS : public QObject, public QRunnable qint64 m_accountId; QStringList m_keys; + bb::system::SystemProgressToast m_progress; signals: void exportCompleted(); - void progress(int progress); public: ExportSMS(QStringList const& keys, qint64 const& accountId); diff --git a/src/ImportSMS.cpp b/src/ImportSMS.cpp index cfe44c9..117d1e5 100644 --- a/src/ImportSMS.cpp +++ b/src/ImportSMS.cpp @@ -1,12 +1,8 @@ +#include "precompiled.h" + #include "ImportSMS.h" #include "Logger.h" -#include - -#include -#include -#include - using namespace bb::pim::account; using namespace bb::pim::contacts; using namespace bb::pim::message; @@ -31,13 +27,24 @@ bool lessThan(const Conversation &c1, const Conversation &c2) namespace exportui { +using namespace bb::system; + +ImportSMS::ImportSMS() { + m_progress.setState(SystemUiProgressState::Inactive); +} + void ImportSMS::run() { LOGGER("ImportSMS::run()"); + m_progress.setState(SystemUiProgressState::Active); + m_progress.setStatusMessage( tr("0% complete...") ); + m_progress.setProgress(0); + m_progress.show(); + AccountService as; QList accounts = as.accounts(Service::Messages, "sms-mms"); - AccountKey accountKey; + AccountKey accountKey = 0; if ( !accounts.isEmpty() ) { accountKey = accounts[0].id(); @@ -50,7 +57,9 @@ void ImportSMS::run() ContactService cs; QVariantList qvl; - for (int i = 0; i < conversations.size(); i++) + int total = conversations.size(); + + for (int i = 0; i < total; i++) { Conversation c = conversations[i]; @@ -68,10 +77,18 @@ void ImportSMS::run() qvl.append(qvm); } + + int progress = (double)i/total * 100; + m_progress.setProgress(progress); + m_progress.setStatusMessage( tr("%1% complete...").arg(progress) ); + m_progress.show(); } LOGGER( "Elements generated:" << qvl.size() ); emit importCompleted(accountKey, qvl); + + m_progress.cancel(); + m_progress.setState(SystemUiProgressState::Inactive); } } /* namespace secret */ diff --git a/src/ImportSMS.h b/src/ImportSMS.h index f7198bb..552bc23 100644 --- a/src/ImportSMS.h +++ b/src/ImportSMS.h @@ -2,15 +2,18 @@ #define IMPORTSMS_H_ #include -#include #include +#include + namespace exportui { class ImportSMS : public QObject, public QRunnable { Q_OBJECT + bb::system::SystemProgressToast m_progress; + signals: /** * Emitted once all the SMS messages have been imported. @@ -20,6 +23,7 @@ class ImportSMS : public QObject, public QRunnable void importCompleted(qint64 accountId, QVariantList const& qvl); public: + ImportSMS(); void run(); }; diff --git a/src/LazySceneCover.cpp b/src/LazySceneCover.cpp index ef12c25..6bc371c 100644 --- a/src/LazySceneCover.cpp +++ b/src/LazySceneCover.cpp @@ -1,11 +1,8 @@ +#include "precompiled.h" + #include "LazySceneCover.h" #include "Logger.h" -#include -#include -#include -#include - namespace canadainc { using namespace bb::cascades; diff --git a/src/Persistance.cpp b/src/Persistance.cpp index e5db1a8..ed373e5 100644 --- a/src/Persistance.cpp +++ b/src/Persistance.cpp @@ -1,8 +1,7 @@ -#include "Persistance.h" -#include "Logger.h" +#include "precompiled.h" -#include -#include +#include "Persistance.h" +#include "Logger.h"> namespace canadainc { @@ -69,9 +68,23 @@ QVariant Persistance::getValueFor(const QString &objectName) void Persistance::saveValueFor(const QString &objectName, const QVariant &inputValue) { LOGGER("saveValueFor: " << objectName << inputValue); - m_settings.setValue(objectName, inputValue); - emit settingChanged(objectName); + if ( m_settings.value(objectName) != inputValue ) { + m_settings.setValue(objectName, inputValue); + emit settingChanged(objectName); + } else { + LOGGER("Duplicate value, ignoring"); + } +} + + +void Persistance::remove(QString const& key) { + m_settings.remove(key); +} + + +void Persistance::clear() { + m_settings.clear(); } diff --git a/src/Persistance.h b/src/Persistance.h index ee0e6e2..b4ab08a 100644 --- a/src/Persistance.h +++ b/src/Persistance.h @@ -39,6 +39,8 @@ private slots: Q_INVOKABLE QVariant getValueFor(QString const& objectName); Q_INVOKABLE void saveValueFor(QString const& objectName, QVariant const& inputValue); + Q_INVOKABLE void remove(QString const& key); + Q_INVOKABLE void clear(); Q_INVOKABLE void copyToClipboard(QString const& text); Q_INVOKABLE void showToast(QString const& text, QString const& buttonLabel=QString()); Q_INVOKABLE static QByteArray convertToUtf8(QString const& text); diff --git a/src/applicationui.hpp b/src/applicationui.hpp index a3852f7..726a81f 100755 --- a/src/applicationui.hpp +++ b/src/applicationui.hpp @@ -12,10 +12,6 @@ namespace bb { namespace cascades { class Application; } - - namespace system { - class SystemProgressDialog; - } } namespace exportui { @@ -30,7 +26,6 @@ class ApplicationUI : public QObject Persistance m_persistance; LazySceneCover m_cover; - SystemProgressDialog* m_progress; qint64 m_accountId; ArrayDataModel m_adm; @@ -40,7 +35,6 @@ class ApplicationUI : public QObject private slots: void onExportCompleted(); void onImportCompleted(qint64 accountId, QVariantList const& qvl); - void onProgressChanged(int progress); public: static void create(bb::cascades::Application *app); diff --git a/src/main.cpp b/src/main.cpp index cf43335..961f673 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,4 @@ -#include - -#include +#include "precompiled.h" #include "applicationui.hpp" #include "Logger.h" diff --git a/translations/Exporter.ts b/translations/Exporter.ts index bb70be4..296ab5e 100755 --- a/translations/Exporter.ts +++ b/translations/Exporter.ts @@ -9,35 +9,35 @@ - + Select All - + Share - + Range Select - + This mode allows you to select a range of messages. Tap the first message, then tap the last message and all of the ones in between will then be selected. - + OK - - + + Copy @@ -65,29 +65,29 @@ This app makes it really easy to select which conversations you want to share an QObject - + %1 %2 - + %1 - + %1: %2 - + %1 - %2: %3 - + %1/%2.txt @@ -95,135 +95,150 @@ This app makes it really easy to select which conversations you want to share an SettingsPage - + Animations - + Controls will be animated whenever they are loaded. - + Controls will be snapped into position without animations. - + Duplicate File Behaviour - + Append - + If a file already exists, then export to the tail of the file. - + Overwrite - + If a file already exists, then overwrite it with the new information - + Message Time Format - + Date & Time - + ie: Jan 4/13 10:15:03 - + Time Only - + ie: 10:15:03 - + Off - + No date or time will be shown on messages. - + The time will not be appended to the messages. - + The time will will be appended in front of the messages with a format like Jan 4/13 10:15:03. - + The time will will be appended in front of the messages with a format like 10:15:03. - + Your name shows up as: - + The name that shows for messages you sent. - + In the output, messages you sent will be prefixed by: %1 - + Double-space - + Each message will be double-spaced for better readability. - + Each message will be single-spaced. + + + Latest Message First + + + + + Messages will be ordered from most recent to least recent. + + + + + Messages will be ordered from oldest to newest . + + canadainc::Persistance - + OK - + Copied: %1 to clipboard @@ -231,33 +246,51 @@ This app makes it really easy to select which conversations you want to share an exportui::ApplicationUI - + You - + Export complete - - - Exporting... - - exportui::ExportSMS - + + 0% complete... + + + + MMM d/yy, hh:mm:ss - + hh:mm:ss + + + %1% complete... + + + + + exportui::ImportSMS + + + 0% complete... + + + + + %1% complete... + + main @@ -272,29 +305,29 @@ This app makes it really easy to select which conversations you want to share an - + %1 messages - - + + Export TXT - + Select Folder - + None selected - - %1 elements selected + + %1 conversations selected