diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..f48122e --- /dev/null +++ b/.cproject @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..2e56c96 --- /dev/null +++ b/.project @@ -0,0 +1,45 @@ + + + RenamedTodo + + + + + + com.rim.tad.tools.qml.core.qmlFileBuilder + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + auto,full,incremental, + + + + + com.qnx.tools.bbt.xml.core.bbtXMLValidationBuilder + + + + + + org.eclipse.wst.jsdt.core.jsNature + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + com.qnx.tools.ide.bbt.core.bbtnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.qt.core.qtNature + com.rim.tad.tools.qml.core.qmlNature + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f034d2b --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +QMAKE_TARGET = RenamedTodo +PROJECT_DIR := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))) +I18N_DIR := $(PROJECT_DIR)/translations + +include mk/cs-base.mk + diff --git a/RenamedTodo.pro b/RenamedTodo.pro new file mode 100644 index 0000000..f895c00 --- /dev/null +++ b/RenamedTodo.pro @@ -0,0 +1,6 @@ +APP_NAME = RenamedTodo + +CONFIG += qt warn_on cascades10 +LIBS += -lbbsystem -lbb + +include(config.pri) diff --git a/assets/.assets.index b/assets/.assets.index new file mode 100644 index 0000000..fba1c37 --- /dev/null +++ b/assets/.assets.index @@ -0,0 +1,50 @@ +1 +48 +AboutPage.qml +AppCover.qml +EditSheet.qml +FilterPage.qml +help.html +HelpPage.qml +humane.js +icons/123.png +icons/abc.png +icons/Add.png +icons/Capitalize.png +icons/Check.png +icons/Clock.png +icons/Clock_a.png +icons/Date.png +icons/Delete.png +icons/DownBox.png +icons/Funnel.png +icons/ic_bbm.png +icons/Info.png +icons/invoke.png +icons/Pencil.png +icons/PriceTag.png +icons/Recycle.png +icons/rtd_512_3-110.png +icons/rtd_512_3-144.png +icons/rtd_512_3-86.png +icons/rtd_512_3-90.png +icons/rtd_512_3-96.png +icons/rtd_splash_1440s.png +icons/rtd_splash_720s.png +icons/rtd_splash_768p.png +icons/Search.png +icons/Sort.png +icons/Undo.png +main.qml +SettingsPage.qml +TaskItem.qml +TaskPage.qml +VisualStyle.bright/Appointment.png +VisualStyle.bright/ArrowCircleAlt.png +VisualStyle.bright/PriceTag.png +VisualStyle.bright/Watch.png +VisualStyle.dark/Appointment.png +VisualStyle.dark/ArrowCircleAlt.png +VisualStyle.dark/PriceTag.png +VisualStyle.dark/Watch.png +Watch_a.png diff --git a/assets/AboutPage.qml b/assets/AboutPage.qml new file mode 100644 index 0000000..f70416a --- /dev/null +++ b/assets/AboutPage.qml @@ -0,0 +1,106 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 + +Page { + ScrollView { + Container { + layout: DockLayout { + } + horizontalAlignment: HorizontalAlignment.Fill + Container { + horizontalAlignment: HorizontalAlignment.Fill + Container { + horizontalAlignment: HorizontalAlignment.Center + preferredHeight: 35.0 + } + Container { + horizontalAlignment: HorizontalAlignment.Center + Label { + text: "Renamed Todo" + textStyle.fontSize: FontSize.Large + } + } + Container { + horizontalAlignment: HorizontalAlignment.Center + Label { + text: "v" + appversion + textStyle.fontSize: FontSize.Small + } + } + Container { + horizontalAlignment: HorizontalAlignment.Center + Label { + text: "Copyright (c) Morgan McMillian 2012-2018" + textStyle.fontSize: FontSize.XSmall + } + } + Container { + horizontalAlignment: HorizontalAlignment.Center + Label { + text: "All rights reserved." + textStyle.fontSize: FontSize.XSmall + } + } + Container { + horizontalAlignment: HorizontalAlignment.Center + preferredHeight: 40.0 + } + Container { + horizontalAlignment: HorizontalAlignment.Center + Label { + text: "https://monkeystew.org/renamed-todo/" + textStyle.fontSize: FontSize.XSmall + content.flags: TextContentFlag.ActiveText + } + } + Container { + horizontalAlignment: HorizontalAlignment.Center + preferredHeight: 30.0 + } + Container { + horizontalAlignment: HorizontalAlignment.Center + preferredHeight: 30.0 + } + Container { + horizontalAlignment: HorizontalAlignment.Center + preferredHeight: 30.0 + } + Divider { + + } + Container { + horizontalAlignment: HorizontalAlignment.Center + preferredHeight: 30.0 + } + Container { + leftPadding: 10.0 + rightPadding: 10.0 + horizontalAlignment: HorizontalAlignment.Fill + Button { + text: "Email Support" + horizontalAlignment: HorizontalAlignment.Center + onClicked: { + _Taskslayer.getSupport(0) + } + } + } + + } + } + } +} diff --git a/assets/AppCover.qml b/assets/AppCover.qml new file mode 100644 index 0000000..add4eaf --- /dev/null +++ b/assets/AppCover.qml @@ -0,0 +1,103 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 +import "humane.js" as HumaneDate + +SceneCover { + // SceneCover + property alias topList: topList + property bool empty + id: appCover + content: Container { + Container { + visible: empty ? false : true + ListView { + dataModel: ArrayDataModel { + id: topList + } + listItemComponents: [ + ListItemComponent { + Container { + layout: StackLayout { + } + Container { + layout: DockLayout { + } + horizontalAlignment: HorizontalAlignment.Fill + leftPadding: 10.0 + rightPadding: 10.0 + topPadding: 10.0 + Container { + layout: StackLayout { + orientation: LayoutOrientation.LeftToRight + } + Container { + minWidth: 50.0 + Label { + text: ListItemData.priority + textStyle.fontSize: FontSize.Medium + textStyle.color: Color.Blue + } + } + } + Container { + layout: StackLayout { + } + leftPadding: 30.0 + Container { + Label { + text: ListItemData.detail + multiline: true + textStyle.fontSize: FontSize.XSmall + textStyle.color: Color.Black + } + } + Container { + Label { + text: HumaneDate.humaneDate(ListItemData.dateCreated) + textStyle.fontSize: FontSize.XXSmall + textStyle.color: Color.Gray + } + } + } + } + Divider { + } + } + } + ] + } + } + Container { + layout: DockLayout { + } + visible: empty + verticalAlignment: VerticalAlignment.Fill + horizontalAlignment: HorizontalAlignment.Fill + opacity: 1.0 + Container { + verticalAlignment: VerticalAlignment.Center + horizontalAlignment: HorizontalAlignment.Center + topPadding: 100.0 + Label { + text: "no tasks" + horizontalAlignment: HorizontalAlignment.Center + } + } + } + } // end content +}// end SceneCover diff --git a/assets/EditSheet.qml b/assets/EditSheet.qml new file mode 100644 index 0000000..04d7a11 --- /dev/null +++ b/assets/EditSheet.qml @@ -0,0 +1,384 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 +import bb.system 1.0 + +Sheet { + id: editSheet + signal saveTask(string text) + signal modifySetting(string setting, variant value) + property alias text: taskText.text + property alias textfield: taskText + property alias title: addBar.title + property alias pri: priority.selectedValue + property alias labels: labels + property bool displayed: false + property bool datenew + property bool newtask + property bool taskitem + Page { + id: addPage + titleBar: TitleBar { + id: addBar + title: "Add" + dismissAction: ActionItem { + title: "Cancel" + onTriggered: { + editSheet.close() + taskText.text = "" + priority.resetSelectedOption() + } + } + acceptAction: ActionItem { + title: "Save" + onTriggered: { + editSheet.close() + editSheet.saveTask(taskText.text) + priority.resetSelectedOption() + } + } + } + Container { + layout: StackLayout { + } + Container { + leftPadding: 10.0 + rightPadding: 10.0 + topPadding: 10.0 + bottomPadding: 10.0 + TextArea { + id: taskText + preferredHeight: 720.0 + } + Container { + id: toolbar + layout: StackLayout { + orientation: LayoutOrientation.LeftToRight + } +// background: Color.create("#262626") +// preferredWidth: 768.0 + Container { + leftPadding: 25.0 + rightPadding: 25.0 + minHeight: 81.0 + ImageButton { + defaultImageSource: "asset:///ArrowCircleAlt.png" + onClicked: { + taskText.preferredHeight = 200.0 + priority.visible = true + priority.expanded = true + toolbar.visible = false + } + } + } + Container { + leftPadding: 25.0 + rightPadding: 25.0 + minHeight: 81.0 + ImageButton { + defaultImageSource: "asset:///PriceTag.png" + onClicked: { + taskText.preferredHeight = 200.0 + labels.visible = true + labels.expanded = true + toolbar.visible = false + } + } + } + Container { + leftPadding: 25.0 + rightPadding: 25.0 + minHeight: 81.0 + ImageButton { + defaultImageSource: "asset:///Appointment.png" + onClicked: { + taskText.preferredHeight = 200.0 + duedate.visible = true + duebtn.visible = true + duedate.expanded = true + toolbar.visible = false + } + } + } + Container { + visible: newtask + leftPadding: 25.0 + rightPadding: 25.0 + minHeight: 81.0 + ImageToggleButton { + imageSourceDefault: "asset:///Watch.png" + imageSourceChecked: "asset:///Watch_a.png" + checked: datenew + onCheckedChanged: { + if (checked) { + modifySetting("datenew", true) + createToggleToast.body = "Date new tasks enabled" + } else { + modifySetting("datenew", false) + createToggleToast.body = "Date new tasks disabled" + } + displayed ? createToggleToast.show() : displayed = true + } + } + } + } + DropDown { + id: priority + title: "Priority" + visible: false + preferredWidth: 720.0 + onSelectedIndexChanged: { + //console.log("priority set to : " + selectedValue); + if (selectedValue == "-") { + taskText.text = taskText.text.replace(/\([A-Z]\)\s/, ""); + } else { + if (taskText.text.match(/\([A-Z]\)/)) { + taskText.text = taskText.text.replace(/\([A-Z]\)/, "(" + + selectedValue + ")"); + } else { + taskText.text = "(" + selectedValue + ") " + taskText.text; + } + } + priority.visible = false + toolbar.visible = true + taskText.preferredHeight = 720.0 + taskText.requestFocus() + } + onExpandedChanged: { + if (expanded === false) { + priority.visible = false + toolbar.visible = true + taskText.preferredHeight = 720.0 + taskText.requestFocus() + } + } + Option { + text: "-" + value: "-" + } + Option { + text: "A" + value: "A" + selected: editSheet.pri == "A" + } + Option { + text: "B" + value: "B" + selected: editSheet.pri == "B" + } + Option { + text: "C" + value: "C" + selected: editSheet.pri == "C" + } + Option { + text: "D" + value: "D" + selected: editSheet.pri == "D" + } + Option { + text: "E" + value: "E" + selected: editSheet.pri == "E" + } + Option { + text: "F" + value: "F" + selected: editSheet.pri == "F" + } + Option { + text: "G" + value: "G" + selected: editSheet.pri == "G" + } + Option { + text: "H" + value: "H" + selected: editSheet.pri == "H" + } + Option { + text: "I" + value: "I" + selected: editSheet.pri == "I" + } + Option { + text: "J" + value: "J" + selected: editSheet.pri == "J" + } + Option { + text: "K" + value: "K" + selected: editSheet.pri == "K" + } + Option { + text: "L" + value: "L" + selected: editSheet.pri == "L" + } + Option { + text: "M" + value: "M" + selected: editSheet.pri == "M" + } + Option { + text: "N" + value: "N" + selected: editSheet.pri == "N" + } + Option { + text: "O" + value: "O" + selected: editSheet.pri == "O" + } + Option { + text: "P" + value: "P" + selected: editSheet.pri == "P" + } + Option { + text: "Q" + value: "Q" + selected: editSheet.pri == "Q" + } + Option { + text: "R" + value: "R" + selected: editSheet.pri == "R" + } + Option { + text: "S" + value: "S" + selected: editSheet.pri == "S" + } + Option { + text: "T" + value: "T" + selected: editSheet.pri == "T" + } + Option { + text: "U" + value: "U" + selected: editSheet.pri == "U" + } + Option { + text: "V" + value: "V" + selected: editSheet.pri == "V" + } + Option { + text: "W" + value: "W" + selected: editSheet.pri == "W" + } + Option { + text: "X" + value: "X" + selected: editSheet.pri == "X" + } + Option { + text: "Y" + value: "Y" + selected: editSheet.pri == "Y" + } + Option { + text: "Z" + value: "Z" + selected: editSheet.pri == "Z" + } + } + DropDown { + id: labels + title: "Project or Context" + visible: false + preferredWidth: 720.0 + onSelectedIndexChanged: { + if (selectedValue != undefined) { + taskText.text = taskText.text + selectedValue + " " + } + labels.visible = false + toolbar.visible = true + taskText.preferredHeight = 720.0 + taskText.requestFocus() + } + onExpandedChanged: { + if (expanded === false) { + labels.visible = false + toolbar.visible = true + taskText.preferredHeight = 720.0 + taskText.requestFocus() + } + } + } + DateTimePicker { + id: duedate + title: "Due date" + visible: false + preferredWidth: 720.0 + } + Container { + id: duebtn + visible: false + layout: StackLayout { + orientation: LayoutOrientation.LeftToRight + } + Button { + text: "Nevermind" + onClicked: { + duedate.visible = false + duebtn.visible = false + toolbar.visible = true + taskText.preferredHeight = 720.0 + taskText.requestFocus() + } + preferredWidth: 350.0 + } + Button { + text: "Add date" + onClicked: { + if (taskitem) { + taskText.text = taskText.text + + "due:" + taskItem.ListItem.view.dataModel.formatDate(duedate.value) + " " + } else { + taskText.text = taskText.text + + "due:" + taskModel.formatDate(duedate.value) + " " + } +// taskText.text = taskText.text + +// "due:" + taskModel.formatDate(duedate.value) + " " + duedate.visible = false + duebtn.visible = false + toolbar.visible = true + taskText.preferredHeight = 720.0 + taskText.requestFocus() + } + preferredWidth: 350.0 + } + } +// Divider { +// } + } + } + onCreationCompleted: { + // TODO this + } + attachedObjects: [ + SystemToast { + id: createToggleToast + } + ] + } +} diff --git a/assets/FilterPage.qml b/assets/FilterPage.qml new file mode 100644 index 0000000..9b6e6ad --- /dev/null +++ b/assets/FilterPage.qml @@ -0,0 +1,105 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 + +Page { + id: filterPage + property alias filterModel: filterModel + property alias warningtext: warningtext + signal resetFilter() + titleBar: TitleBar { + id: titleBar + title: " Filter List" + } + Container { + Container { + id: warningtext + leftPadding: 30.0 + topPadding: 30.0 + rightPadding: 30.0 + bottomPadding: 30.0 + visible: false + Label { + text: "There are no project or context tags in your task list to " + + "filter on. You can define a project tag by prefixing some text " + + "with the + symbol or a context tag with the @ symbol in your tasks." + multiline: true + textStyle.fontStyle: FontStyle.Italic + } + } + ListView { + id: filterList + dataModel: GroupDataModel { + id: filterModel + sortingKeys: [ "type" ] + grouping: ItemGrouping.ByFullValue + signal changeFilter(string filter, bool enabled) + } + listItemComponents: [ + ListItemComponent { + type: "listItem" + Container { + id: filterItem + layout: StackLayout { + } + Container { + layout: DockLayout { + } + horizontalAlignment: HorizontalAlignment.Fill + topPadding: 15.0 + leftPadding: 20.0 + rightPadding: 30.0 + Label { + text: ListItemData.title + } + CheckBox { + id: filterCheck + horizontalAlignment: HorizontalAlignment.Right + // TODO: checked: need it out of the taskModel + checked: ListItemData.checked + onCheckedChanged: { + //console.log(filterCheck.checked) + filterItem.ListItem.view.dataModel.changeFilter(ListItemData.title, filterCheck.checked) + } + } + } + Divider { + } + } + } + ] + function itemType(data, indexPath) { + if (indexPath.length == 1) { + return "header"; + } else { + return "listItem"; + } + } + } + } + actions: [ + ActionItem { + title: "Reset" + imageSource: "icons/Delete.png" + ActionBar.placement: ActionBarPlacement.OnBar + onTriggered: { + resetFilter(); + navi.pop(); + } + } + ] +} diff --git a/assets/HelpPage.qml b/assets/HelpPage.qml new file mode 100644 index 0000000..f06aa4c --- /dev/null +++ b/assets/HelpPage.qml @@ -0,0 +1,35 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 + +Page { + id: helpPage + titleBar: TitleBar { + title: " Help" + } + Container { + layout: DockLayout { + } + ScrollView { + WebView { + id: webView + url: "local:///assets/help.html" + settings.defaultFontSize: 30 + } + } + } +} diff --git a/assets/SettingsPage.qml b/assets/SettingsPage.qml new file mode 100644 index 0000000..1ea50f5 --- /dev/null +++ b/assets/SettingsPage.qml @@ -0,0 +1,272 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 +import bb.cascades.pickers 1.0 + +Page { + id: settingsPage + signal modifySetting(string setting, variant value) + property bool datenew + property bool windowsbreak + property bool autoarchive + property int sort + property string path + property string sync + property string dboxpath + titleBar: TitleBar { + title: " Settings" + } + ScrollView { + Container { + layout: StackLayout {} + Container { + topPadding: 15.0 + } + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + verticalAlignment: VerticalAlignment.Fill + Container { + verticalAlignment: VerticalAlignment.Center + leftPadding: 30.0 + Label { + text: "Date new tasks" + textStyle.fontWeight: FontWeight.Bold + } + } + Container { + rightPadding: 30.0 + horizontalAlignment: HorizontalAlignment.Right + ToggleButton { + checked: datenew + onCheckedChanged: { + if (checked) { + modifySetting("datenew", true) + } else { + modifySetting("datenew", false) + } + } + } + } + } + Divider {} + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + verticalAlignment: VerticalAlignment.Fill + Container { + leftPadding: 30.0 + verticalAlignment: VerticalAlignment.Center + Label { + text: "Windows line breaks" + textStyle.fontWeight: FontWeight.Bold + } + } + Container { + rightPadding: 30.0 + horizontalAlignment: HorizontalAlignment.Right + ToggleButton { + checked: windowsbreak + onCheckedChanged: { + if (checked) { + modifySetting("windowsbreak", true) + } else { + modifySetting("windowsbreak", false) + } + } + } + } + } + Divider {} + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + verticalAlignment: VerticalAlignment.Fill + Container { + leftPadding: 30.0 + verticalAlignment: VerticalAlignment.Center + Label { + text: "Auto archive" + textStyle.fontWeight: FontWeight.Bold + } + } + Container { + rightPadding: 30.0 + horizontalAlignment: HorizontalAlignment.Right + ToggleButton { + checked: autoarchive + onCheckedChanged: { + if (checked) { + modifySetting("autoarchive", true) + } else { + modifySetting("autoarchive", false) + } + } + } + } + } + Divider {} + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + Container { + leftPadding: 30.0 + rightPadding: 30.0 + DropDown { + title: "Sort by:" + preferredWidth: 1440.0 + onSelectedIndexChanged: { + modifySetting("sort", selectedValue) + } + Option { + text: "Priority" + value: 0 + selected: sort == 0 + } + Option { + text: "Due date" + value: 3 + selected: sort == 3 + } + Option { + text: "Line number" + value: 1 + selected: sort == 1 + } + Option { + text: "Text A>Z" + value: 2 + selected: sort == 2 + } + } + } + } + Divider {} + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + Container { + leftPadding: 30.0 + rightPadding: 30.0 + DropDown { + title: "File location:" + preferredWidth: 1440.0 + onSelectedIndexChanged: { + modifySetting("path", selectedValue) + } + Option { + text: "Local sandbox" + value: "data/todo" + selected: path == "data/todo" + } + Option { + text: "Local shared" + value: "shared/misc/todo" + selected: path == "shared/misc/todo" + } + } + } + } + Divider {} + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + Container { + leftPadding: 30.0 + rightPadding: 30.0 + DropDown { + title: "Storage:" + preferredWidth: 1440.0 + onSelectedIndexChanged: { + if (sync != selectedValue) { + modifySetting("sync", selectedValue) + } + } + Option { + text: "Local only" + value: "local" + selected: sync == "local" + } + } + } + } + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + Container { + leftPadding: 30.0 + rightPadding: 30.0 + topPadding: 10.0 + TextField { + id: dboxPath + hintText: "Dropbox location" + text: dboxpath + visible: sync == "dropbox" + onTextChanged: { + if (dboxPath.text.length > 0) { + modifySetting("dbox_path", dboxPath.text) + } + } + } + } + } + Divider {} + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + leftPadding: 30.0 + rightPadding: 30.0 + Button { + preferredWidth: 1440.0 + text: "Export sandbox files" + onClicked: { + exportPicker.open() + } + } + } + Divider {} + Container { + layout: DockLayout {} + horizontalAlignment: HorizontalAlignment.Fill + leftPadding: 30.0 + rightPadding: 30.0 + Button { + preferredWidth: 1440.0 + text: "Purge local sandbox" + onClicked: { + taskModel.promptPurgeSandbox() + } + } + } + Divider {} + } + } + attachedObjects: [ + FilePicker { + id: exportPicker + title: "Export" + mode: FilePicker.SaverMultiple + type: FileType.Document + viewMode: FilePickerViewMode.ListView + defaultSaveFileNames: ["todo.txt","done.txt"] + onFileSelected: { + console.log("FileSelected signal received : " + selectedFiles); + taskModel.exportFiles(selectedFiles) + } + } + ] +} diff --git a/assets/TaskItem.qml b/assets/TaskItem.qml new file mode 100644 index 0000000..34bafca --- /dev/null +++ b/assets/TaskItem.qml @@ -0,0 +1,179 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 +import "humane.js" as HumaneDate + +Container { + id: taskItem + Container { + layout: StackLayout { + } + Container { + layout: DockLayout { + } + horizontalAlignment: HorizontalAlignment.Fill + leftPadding: 10.0 + rightPadding: 10.0 + topPadding: 10.0 + Container { + layout: StackLayout { + orientation: LayoutOrientation.LeftToRight + } + Container { + minWidth: 50.0 + Label { + text: ListItemData.priority + textStyle.fontSize: FontSize.Large + //textStyle.color: Color.Blue + textStyle.color: getPriorityColor(ListItemData.priority) + } + } + } + Container { + layout: StackLayout { + } + leftPadding: 40.0 + Container { + Label { + text: ListItemData.detail + multiline: true + textStyle.fontSize: FontSize.Medium + //textStyle.color: ListItemData.complete ? Color.Gray : Color.Black + textStyle.color: getDetailColor(ListItemData.complete) + } + } + Container { + layout: StackLayout { + orientation: LayoutOrientation.LeftToRight + } + topPadding: 5.0 + Container { + rightPadding: ListItemData.dateDue.length > 0 ? 10.0 : 0 + Label { + text: ListItemData.dateDue.length > 0 ? "Due " + + HumaneDate.humaneDate(ListItemData.dateDue) : "" + textStyle.fontSize: FontSize.XXSmall + textStyle.color: Color.Gray + textStyle.fontWeight: FontWeight.Bold + } + } + Container { + Label { + text: ListItemData.complete ? "Completed " + + HumaneDate.humaneDate(ListItemData.dateCompleted) : + ListItemData.dateCreated ? "Created " + + HumaneDate.humaneDate(ListItemData.dateCreated) : "" + textStyle.fontSize: FontSize.XXSmall + //textStyle.color: ListItemData.complete ? Color.LightGray : Color.Gray + textStyle.color: Color.Gray + } + } + } + } + } + Divider { + } + } + function getDetailColor(complete) { + if (complete) return Color.Gray; + switch (Application.themeSupport.theme.colorTheme.style) { + case VisualStyle.Bright: + return Color.Black; + case VisualStyle.Dark: + return Color.White; + } + return Color.Black; + } + function getPriorityColor(priority) { + // TODO make each priority a different color + switch (Application.themeSupport.theme.colorTheme.style) { + case VisualStyle.Bright: + return Color.Blue; + case VisualStyle.Dark: + return Color.Yellow; + } + return Color.Gray; + } + contextActions: [ + ActionSet { + title: ListItemData.detail + ActionItem { + title: "Edit" + imageSource: "icons/Pencil.png" + onTriggered: { + editItem.open() + editItem.newtask = false; + editItem.text = ListItemData.text +// editItem.pri = ListItemData.priority + editItem.labels.removeAll(); + for (var i = 0; i < taskItem.ListItem.view.dataModel.filters.length; i ++) { + var o = opt.createObject(); + o.text = taskItem.ListItem.view.dataModel.filters[i].title; + o.value = taskItem.ListItem.view.dataModel.filters[i].title; + editItem.labels.add(o); + } + editItem.textfield.requestFocus(); + } + } + ActionItem { + title: "Complete" + imageSource: "icons/Check.png" + enabled: ListItemData.complete ? false : true + onTriggered: { + taskItem.ListItem.view.dataModel.setValue(taskItem.ListItem.indexPath, "complete", true) + } + } + ActionItem { + title: "Undo Complete" + imageSource: "icons/Undo.png" + enabled: ListItemData.complete + onTriggered: { + taskItem.ListItem.view.dataModel.setValue(taskItem.ListItem.indexPath, "complete", false) + } + } + InvokeActionItem { + title: "Share" + query { + mimeType: "text/plain" + invokeActionId: "bb.action.SHARE" + } + data: ListItemData.text + } + DeleteActionItem { + title: "Delete" + onTriggered: { + taskItem.ListItem.view.dataModel.promptDelete(taskItem.ListItem.indexPath) + } + } + } + ] + attachedObjects: [ + EditSheet { + id: editItem + title: "Edit" + taskitem: true + onSaveTask: { + taskItem.ListItem.view.dataModel.updateTask(taskItem.ListItem.indexPath, text) + } + }, + ComponentDefinition { + id: opt + Option { + } + } + ] +} diff --git a/assets/TaskPage.qml b/assets/TaskPage.qml new file mode 100644 index 0000000..67d1ebe --- /dev/null +++ b/assets/TaskPage.qml @@ -0,0 +1,114 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 + +Page { + id: taskPage + signal itemUpdate(int idx, string text) + signal setValue(int idx, string key, variant value) + signal delTask(int idx) + property alias title: titleBar.title + property string itemtext + property variant idx + property bool complete + titleBar: TitleBar { + id: titleBar + title: " Task" + } + Container { + layout: DockLayout { + } + Container { + topPadding: 30 + leftPadding: 30 + rightPadding: 30 + Label { + id: taskText + multiline: true + text: itemtext + } + } + } + actions: [ + ActionItem { + title: "Edit" + imageSource: "icons/Pencil.png" + ActionBar.placement: ActionBarPlacement.OnBar + onTriggered: { + editItem.open() + editItem.newtask = false + editItem.text = itemtext + editItem.labels.removeAll(); + for (var i = 0; i < taskModel.filters.length; i ++) { + var o = opt.createObject(); + o.text = taskModel.filters[i].title; + o.value = taskModel.filters[i].title; + editItem.labels.add(o); + } + editItem.textfield.requestFocus() + } + }, + ActionItem { + title: "Complete" + imageSource: "icons/Check.png" + enabled: complete ? false : true + onTriggered: { + setValue(idx, "complete", true) + navi.pop() + } + }, + ActionItem { + title: "Undo Complete" + imageSource: "icons/Undo.png" + enabled: complete + onTriggered: { + setValue(idx, "complete", false) + navi.pop() + } + }, + InvokeActionItem { + title: "Share" + query { + mimeType: "text/plain" + invokeActionId: "bb.action.SHARE" + } + data: itemtext + }, + DeleteActionItem { + title: "Delete" + onTriggered: { + delTask(idx) + navi.pop() + } + } + ] + attachedObjects: [ + EditSheet { + id: editItem + title: "Edit" + onSaveTask: { + itemUpdate(idx, text) + itemtext = text + } + }, + ComponentDefinition { + id: opt + Option { + } + } + ] +} diff --git a/assets/VisualStyle.bright/Appointment.png b/assets/VisualStyle.bright/Appointment.png new file mode 100644 index 0000000..7ebf9d2 Binary files /dev/null and b/assets/VisualStyle.bright/Appointment.png differ diff --git a/assets/VisualStyle.bright/ArrowCircleAlt.png b/assets/VisualStyle.bright/ArrowCircleAlt.png new file mode 100644 index 0000000..03ed908 Binary files /dev/null and b/assets/VisualStyle.bright/ArrowCircleAlt.png differ diff --git a/assets/VisualStyle.bright/PriceTag.png b/assets/VisualStyle.bright/PriceTag.png new file mode 100644 index 0000000..e22774d Binary files /dev/null and b/assets/VisualStyle.bright/PriceTag.png differ diff --git a/assets/VisualStyle.bright/Watch.png b/assets/VisualStyle.bright/Watch.png new file mode 100644 index 0000000..071b33f Binary files /dev/null and b/assets/VisualStyle.bright/Watch.png differ diff --git a/assets/VisualStyle.dark/Appointment.png b/assets/VisualStyle.dark/Appointment.png new file mode 100644 index 0000000..b437757 Binary files /dev/null and b/assets/VisualStyle.dark/Appointment.png differ diff --git a/assets/VisualStyle.dark/ArrowCircleAlt.png b/assets/VisualStyle.dark/ArrowCircleAlt.png new file mode 100644 index 0000000..47e8dbf Binary files /dev/null and b/assets/VisualStyle.dark/ArrowCircleAlt.png differ diff --git a/assets/VisualStyle.dark/PriceTag.png b/assets/VisualStyle.dark/PriceTag.png new file mode 100644 index 0000000..ed131b9 Binary files /dev/null and b/assets/VisualStyle.dark/PriceTag.png differ diff --git a/assets/VisualStyle.dark/Watch.png b/assets/VisualStyle.dark/Watch.png new file mode 100644 index 0000000..7fe453c Binary files /dev/null and b/assets/VisualStyle.dark/Watch.png differ diff --git a/assets/Watch_a.png b/assets/Watch_a.png new file mode 100644 index 0000000..250c825 Binary files /dev/null and b/assets/Watch_a.png differ diff --git a/assets/help.html b/assets/help.html new file mode 100644 index 0000000..67cda06 --- /dev/null +++ b/assets/help.html @@ -0,0 +1,81 @@ + + + Renamed Todo Help + + +

 

+
+ Q: What is the todo.txt file format? +
+

+ The todo.txt file is simply a plain text file that follows a specification + created by Gina Trapani and used in applications published by the Todo.txt Community. The todo.txt file is both human and machine readable by following a few simple rules. You can find more information including the specifications here. +

+
+
+
+ Q: How do I add filters? +
+

+ Filters are created automatically by special text identified in the tasks you create. The two kinds of text it looks for are projects and contexts. +

+ Project:  + Denoted by prefixing some text with "+"
+ Context:  + Denoted by prefixing some text with "@"
+

+ So for example the task "Contact Tom by @email to discuss the new +program" results in "@email" and "+program" added to the filter list. +

+
+
+
+ Q: What is the difference between "Local sandbox" and "Local shared" in the file location settings? +
+

+ Local sandbox:  + The todo.txt file is located within the application sandbox + storage space and is only accessible to this app. This is the + default location when you start the app for the first time and the best + option if you do not need or want your file accessible from any other + application or process.
+ Local shared:  + The todo.txt file is located within the shared application storage space + in "Shared/misc/todo". This location is accessible from any other + application. +

+
+
+
+ Q: Can I export my todo.txt list from the local sandbox? +
+

+ You can export the todo.txt and done.txt files from your local sandbox by + opening the "Settings" page in the pull down menu at the top of the screen + and pressing the "Export sandbox files". From there you will be prompted to + select an accessible location. +

+
+
+
+ Q: What happened to Dropbox support? +
+

+ Dropbox support has been temporarily removed from this open source edition. I plan to + rework a large portion of the sync code and re-introduce it along with support for + other cloud providers soon. +

+
+
+
+ Q: How can I get some additional help? +
+

+ For any feedback or questions you can send me email or visit us at monkeystew.org +

+
+

 

+ + \ No newline at end of file diff --git a/assets/humane.js b/assets/humane.js new file mode 100644 index 0000000..87fc202 --- /dev/null +++ b/assets/humane.js @@ -0,0 +1,150 @@ +/* + * Javascript Humane Dates + * Copyright (c) 2008 Dean Landolt (deanlandolt.com) + * Re-write by Zach Leatherman (zachleat.com) + * + * Adopted from the John Resig's pretty.js + * at http://ejohn.org/blog/javascript-pretty-date + * and henrah's proposed modification + * at http://ejohn.org/blog/javascript-pretty-date/#comment-297458 + * + * Licensed under the MIT license. + */ + +function humaneDate(date, compareTo){ + + if(!date) { + return; + } + + var testme = new Date; + compareTo = testme.getFullYear() + "-" + (testme.getMonth()+1) + "-" + testme.getDate(); + + var lang = { + ago: 'ago', + from: 'from now', + now: 'today', + minute: 'minute', + minutes: 'minutes', + hour: 'hour', + hours: 'hours', + today: 'today', + day: 'day', + days: 'days', + week: 'week', + weeks: 'weeks', + month: 'month', + months: 'months', + year: 'year', + years: 'years' + }, + formats = [ + [60, lang.now], + [3600, lang.minute, lang.minutes, 60], // 60 minutes, 1 minute + [86400, lang.hour, lang.hours, 3600], // 24 hours, 1 hour + [604800, lang.day, lang.days, 86400], // 7 days, 1 day + [2628000, lang.week, lang.weeks, 604800], // ~1 month, 1 week + [31536000, lang.month, lang.months, 2628000], // 1 year, ~1 month + [Infinity, lang.year, lang.years, 31536000] // Infinity, 1 year + ], + isString = typeof date == 'string', + date = isString ? + new Date(('' + date).replace(/-/g,"/").replace(/[TZ]/g," ")) : + date, + cIsString = typeof compareTo == 'string', + compareTo = cIsString ? + new Date(('' + compareTo).replace(/-/g,"/").replace(/[TZ]/g," ")) : + compareTo, + seconds = (compareTo - date + + (compareTo.getTimezoneOffset() - + // if we received a GMT time from a string, doesn't include time zone bias + // if we got a date object, the time zone is built in, we need to remove it. + (isString ? 0 : date.getTimezoneOffset()) + ) * 60000 + ) / 1000, + token; + + if(seconds < 0) { + seconds = Math.abs(seconds); + token = lang.from ? ' ' + lang.from : ''; + } else { + token = lang.ago ? ' ' + lang.ago : ''; + } + + /* + * 0 seconds && < 60 seconds Now + * 60 seconds 1 Minute + * > 60 seconds && < 60 minutes X Minutes + * 60 minutes 1 Hour + * > 60 minutes && < 24 hours X Hours + * 24 hours 1 Day + * > 24 hours && < 7 days X Days + * 7 days 1 Week + * > 7 days && < ~ 1 Month X Weeks + * ~ 1 Month 1 Month + * > ~ 1 Month && < 1 Year X Months + * 1 Year 1 Year + * > 1 Year X Years + * + * Single units are +10%. 1 Year shows first at 1 Year + 10% + */ + + function normalize(val, single) + { + var margin = 0.1; + if(val >= single && val <= single * (1+margin)) { + return single; + } + return val; + } + + for(var i = 0, format = formats[0]; formats[i]; format = formats[++i]) { + if(seconds < format[0]) { + if(i === 0) { + // Now + return format[1]; + } + + var val = Math.ceil(normalize(seconds, format[3]) / (format[3])); + + // Since the source is only passing a date don't reference hours, use today + if (format[2] == lang.hours) { return lang.today; } + + // Again, since it's only the date adjust the days value to round down + if (format[2] == lang.days) { + val = Math.floor(normalize(seconds, format[3]) / (format[3])); + } + + return val + + ' ' + + (val != 1 ? format[2] : format[1]) + + (i > 0 ? token : ''); + } + } +}; + +if(typeof jQuery != 'undefined') { + jQuery.fn.humaneDates = function(options) + { + var settings = jQuery.extend({ + 'lowercase': false + }, options); + + return this.each(function() + { + var $t = jQuery(this), + date = $t.attr('datetime') || $t.attr('title'); + + date = humaneDate(date); + + if(date && settings['lowercase']) { + date = date.toLowerCase(); + } + + if(date && $t.html() != date) { + // don't modify the dom if we don't have to + $t.html(date); + } + }); + }; +} diff --git a/assets/icons/123.png b/assets/icons/123.png new file mode 100644 index 0000000..4423557 Binary files /dev/null and b/assets/icons/123.png differ diff --git a/assets/icons/Add.png b/assets/icons/Add.png new file mode 100644 index 0000000..cdae022 Binary files /dev/null and b/assets/icons/Add.png differ diff --git a/assets/icons/Capitalize.png b/assets/icons/Capitalize.png new file mode 100644 index 0000000..29aa3f9 Binary files /dev/null and b/assets/icons/Capitalize.png differ diff --git a/assets/icons/Check.png b/assets/icons/Check.png new file mode 100644 index 0000000..de80c29 Binary files /dev/null and b/assets/icons/Check.png differ diff --git a/assets/icons/Clock.png b/assets/icons/Clock.png new file mode 100644 index 0000000..26fe71f Binary files /dev/null and b/assets/icons/Clock.png differ diff --git a/assets/icons/Clock_a.png b/assets/icons/Clock_a.png new file mode 100644 index 0000000..b843d89 Binary files /dev/null and b/assets/icons/Clock_a.png differ diff --git a/assets/icons/Date.png b/assets/icons/Date.png new file mode 100644 index 0000000..c325b32 Binary files /dev/null and b/assets/icons/Date.png differ diff --git a/assets/icons/Delete.png b/assets/icons/Delete.png new file mode 100644 index 0000000..acfc5d5 Binary files /dev/null and b/assets/icons/Delete.png differ diff --git a/assets/icons/DownBox.png b/assets/icons/DownBox.png new file mode 100644 index 0000000..a3168c6 Binary files /dev/null and b/assets/icons/DownBox.png differ diff --git a/assets/icons/Funnel.png b/assets/icons/Funnel.png new file mode 100644 index 0000000..59b8838 Binary files /dev/null and b/assets/icons/Funnel.png differ diff --git a/assets/icons/Info.png b/assets/icons/Info.png new file mode 100644 index 0000000..1e867c7 Binary files /dev/null and b/assets/icons/Info.png differ diff --git a/assets/icons/Pencil.png b/assets/icons/Pencil.png new file mode 100644 index 0000000..5a55a66 Binary files /dev/null and b/assets/icons/Pencil.png differ diff --git a/assets/icons/PriceTag.png b/assets/icons/PriceTag.png new file mode 100644 index 0000000..df0988d Binary files /dev/null and b/assets/icons/PriceTag.png differ diff --git a/assets/icons/Recycle.png b/assets/icons/Recycle.png new file mode 100644 index 0000000..128abbe Binary files /dev/null and b/assets/icons/Recycle.png differ diff --git a/assets/icons/Search.png b/assets/icons/Search.png new file mode 100644 index 0000000..9224195 Binary files /dev/null and b/assets/icons/Search.png differ diff --git a/assets/icons/Sort.png b/assets/icons/Sort.png new file mode 100644 index 0000000..f4f573b Binary files /dev/null and b/assets/icons/Sort.png differ diff --git a/assets/icons/Undo.png b/assets/icons/Undo.png new file mode 100644 index 0000000..1b8dcd6 Binary files /dev/null and b/assets/icons/Undo.png differ diff --git a/assets/icons/abc.png b/assets/icons/abc.png new file mode 100644 index 0000000..89238e3 Binary files /dev/null and b/assets/icons/abc.png differ diff --git a/assets/icons/ic_bbm.png b/assets/icons/ic_bbm.png new file mode 100644 index 0000000..21c2444 Binary files /dev/null and b/assets/icons/ic_bbm.png differ diff --git a/assets/icons/invoke.png b/assets/icons/invoke.png new file mode 100644 index 0000000..fdea810 Binary files /dev/null and b/assets/icons/invoke.png differ diff --git a/assets/icons/rtd_512_3-110.png b/assets/icons/rtd_512_3-110.png new file mode 100644 index 0000000..5bb186d Binary files /dev/null and b/assets/icons/rtd_512_3-110.png differ diff --git a/assets/icons/rtd_512_3-144.png b/assets/icons/rtd_512_3-144.png new file mode 100644 index 0000000..74ee9eb Binary files /dev/null and b/assets/icons/rtd_512_3-144.png differ diff --git a/assets/icons/rtd_512_3-86.png b/assets/icons/rtd_512_3-86.png new file mode 100644 index 0000000..780d572 Binary files /dev/null and b/assets/icons/rtd_512_3-86.png differ diff --git a/assets/icons/rtd_512_3-90.png b/assets/icons/rtd_512_3-90.png new file mode 100644 index 0000000..a34ac59 Binary files /dev/null and b/assets/icons/rtd_512_3-90.png differ diff --git a/assets/icons/rtd_512_3-96.png b/assets/icons/rtd_512_3-96.png new file mode 100644 index 0000000..97a5705 Binary files /dev/null and b/assets/icons/rtd_512_3-96.png differ diff --git a/assets/icons/rtd_splash_1440s.png b/assets/icons/rtd_splash_1440s.png new file mode 100644 index 0000000..a0331c7 Binary files /dev/null and b/assets/icons/rtd_splash_1440s.png differ diff --git a/assets/icons/rtd_splash_720s.png b/assets/icons/rtd_splash_720s.png new file mode 100644 index 0000000..fba0bc1 Binary files /dev/null and b/assets/icons/rtd_splash_720s.png differ diff --git a/assets/icons/rtd_splash_768p.png b/assets/icons/rtd_splash_768p.png new file mode 100644 index 0000000..0895f24 Binary files /dev/null and b/assets/icons/rtd_splash_768p.png differ diff --git a/assets/main.qml b/assets/main.qml new file mode 100644 index 0000000..6c587b7 --- /dev/null +++ b/assets/main.qml @@ -0,0 +1,398 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import bb.cascades 1.0 +import com.monkeystew.taskmodel 1.0 + +NavigationPane { + id: navi + property string appversion + property variant coverpage + Menu.definition: MenuDefinition { + helpAction: HelpActionItem { + onTriggered: { + var page = helpPage.createObject() + navi.push(page) + } + } + settingsAction: SettingsActionItem { + onTriggered: { + var page = settingsPage.createObject(); + page.modifySetting.connect(taskModel.modifySetting) + page.datenew = taskModel.setting("datenew", false) + page.windowsbreak = taskModel.setting("windowsbreak", false) + page.autoarchive = taskModel.setting("autoarchive", false) + page.sort = taskModel.setting("sort", 0) + page.path = taskModel.setting("path", "data/todo") + page.sync = taskModel.setting("sync", "local") + page.dboxpath = taskModel.setting("dbox_path", "/todo/todo.txt") + navi.push(page) + } + } + actions: [ + ActionItem { + title: "About" + imageSource: "asset:///icons/Info.png" + onTriggered: { + var page = aboutPage.createObject() + navi.push(page) + } + } +// ActionItem { +// title: "Invite" +// imageSource: "asset:///icons/ic_bbm.png" +// onTriggered: { +// _Taskslayer.sendBBMInvite() +// } +// } + ] + } + Page { + id: mainPage + titleBar: TitleBar { + id: titleBar + title: " Renamed Todo" + visibility: ChromeVisibility.Default + } + Container { + Container { + id: searchContainer + visible: false + layout: StackLayout { + orientation: LayoutOrientation.LeftToRight + } + preferredHeight: 120.0 + //background: Color.create("#0098F0") + background: mainPage.getSearchBackground() + Container { + verticalAlignment: VerticalAlignment.Center + leftPadding: 15.0 + rightPadding: 10.0 + TextField { + id: searchField + hintText: "Search" + onTextChanging: { + taskModel.search(searchField.text); + } + } + } + Container { + maxWidth: 220.0 + verticalAlignment: VerticalAlignment.Center + leftPadding: 10.0 + rightPadding: 15.0 + Button { + text: "Cancel" + onClicked: { + titleBar.visibility = ChromeVisibility.Default + searchContainer.visible = false + searchField.text = "" + } + } + } + } + Container { + horizontalAlignment: HorizontalAlignment.Fill + Container { + id: appliedFilters + layout: DockLayout { + } + visible: false + horizontalAlignment: HorizontalAlignment.Fill + Container { + background: Color.create("#333333") + horizontalAlignment: HorizontalAlignment.Fill + Label { + id: filterList + text: taskModel.activeFilters() + textStyle.color: Color.White + textStyle.fontSize: FontSize.XSmall + } + } + } + } + Container { + id: sortdropdown + horizontalAlignment: HorizontalAlignment.Center + visible: false + DropDown { + id: sortselection + title: "Sort" + onSelectedIndexChanged: { + if (selectedValue != undefined) { + taskModel.sort = selectedValue + sortdropdown.visible = false + } + } + Option { + text: "Priority" + value: 0 + } + Option { + text: "Due date" + value: 3 + } + Option { + text: "Line number" + value: 1 + } + Option { + text: "Text A>Z" + value: 2 + } + } + } + ListView { + id: listView + dataModel: taskModel + listItemComponents: [ + ListItemComponent { + TaskItem { + // see TaskItem.qml + } + } + ] + onTriggered: { + var chosenItem = taskModel.data(indexPath) + var page = taskPage.createObject(); + page.itemUpdate.connect(taskModel.updateTask) + page.setValue.connect(taskModel.setValue) + page.delTask.connect(taskModel.promptDelete) + page.itemtext = chosenItem.text + page.complete = chosenItem.complete + page.idx = indexPath + navi.push(page) + } + /*leadingVisual: TextField { + * id: searchField + * onTextChanging: { + * // + * } + * }*/ + } + } + attachedObjects: [ + TaskModel { + id: taskModel + }, + EditSheet { + id: addNew + onSaveTask: { + taskModel.addFullTask(text) + } + }, + ComponentDefinition { + id: taskPage + source: "asset:///TaskPage.qml" + }, + ComponentDefinition { + id: filterPage + source: "asset:///FilterPage.qml" + }, + ComponentDefinition { + id: settingsPage + source: "asset:///SettingsPage.qml" + }, + ComponentDefinition { + id: aboutPage + source: "asset:///AboutPage.qml" + }, + ComponentDefinition { + id: helpPage + source: "asset:///HelpPage.qml" + }, + ComponentDefinition { + id: appCover + source: "asset:///AppCover.qml" + }, + ComponentDefinition { + id: opt + Option {} + } + ] + actions: [ + ActionItem { + title: "Add" + imageSource: "asset:///icons/Add.png" + ActionBar.placement: ActionBarPlacement.OnBar + onTriggered: { + addNew.open(); + addNew.newtask = true; + addNew.datenew = taskModel.setting("datenew", false); + addNew.modifySetting.connect(taskModel.modifySetting); + addNew.text = ""; + addNew.labels.removeAll(); + for (var i=0; i < taskModel.filters.length; i++) { + var o = opt.createObject(); + o.text = taskModel.filters[i].title; + o.value = taskModel.filters[i].title; + addNew.labels.add(o); + } + addNew.textfield.requestFocus(); + } + }, + ActionItem { + id: searchButton + title: "Search" + imageSource: "asset:///icons/Search.png" + ActionBar.placement: ActionBarPlacement.OnBar + onTriggered: { + if (searchContainer.visible) { + titleBar.visibility = ChromeVisibility.Default + searchContainer.visible = false + searchField.text = "" + } else { + searchContainer.visible = true + searchField.requestFocus() + titleBar.visibility = ChromeVisibility.Hidden + } + } + }, + ActionItem { + title: "Filter" + imageSource: "asset:///icons/Funnel.png" + ActionBar.placement: ActionBarPlacement.OnBar + onTriggered: { + var page = filterPage.createObject(); + if (taskModel.filters.length <= 0) { + if (appliedFilters.visible) { + taskModel.resetFilter() + } else { + page.warningtext.visible = true + } + } + page.filterModel.insertList(taskModel.filters); + page.filterModel.changeFilter.connect(taskModel.changeFilter); + page.resetFilter.connect(taskModel.resetFilter); + navi.push(page); + } + }, + ActionItem { + title: "Sort" + imageSource: "asset:///icons/Sort.png" + onTriggered: { + sortdropdown.visible = sortdropdown.visible ? false : true + sortselection.resetSelectedIndex() + } + }, +// ActionItem { +// title: "Sort by priority" +// imageSource: "icons/Capitalize.png" +// onTriggered: { +// taskModel.sort = 0; +// } +// }, +// ActionItem { +// title: "Sort by line" +// imageSource: "icons/123.png" +// onTriggered: { +// taskModel.sort = 1; +// } +// }, +// ActionItem { +// title: "Sort by text (a>z)" +// imageSource: "icons/abc.png" +// onTriggered: { +// taskModel.sort = 2; +// } +// }, +// ActionItem { +// title: "Sort by due date" +// onTriggered: { +// taskModel.sort = 3; +// } +// }, + ActionItem { + title: "Archive" + imageSource: "asset:///icons/DownBox.png" + onTriggered: { + taskModel.archive(); + } + }, + ActionItem { + title: "Reload" + imageSource: "asset:///icons/Recycle.png" + onTriggered: { + taskModel.refresh(); + taskModel.setView(); + } + } + ] + onCreationCompleted: { + taskModel.refresh(); + taskModel.setView(); + _Taskslayer.addNewTask.connect(newTask) + _Taskslayer.searchTaskList.connect(searchTasks) + taskModel.listUpdated.connect(listUpdated) + coverpage = appCover.createObject(); + coverpage.topList.append(taskModel.tododata) + if (taskModel.tododata.length > 0) { + coverpage.empty = false + } else { + coverpage.empty = true + } + Application.cover = coverpage + console.log(themeStyleToString(Application.themeSupport.theme.colorTheme.style)) + } + function searchTasks(data) { + searchContainer.visible = true + searchField.requestFocus() + searchField.text = data + titleBar.visibility = ChromeVisibility.Hidden + } + function newTask(data) { + addNew.open(); + addNew.newtask = true; + addNew.datenew = taskModel.setting("datenew", false); + addNew.modifySetting.connect(taskModel.modifySetting); + addNew.text = data; + addNew.textfield.requestFocus(); + } + function listUpdated() { + coverpage.topList.clear() + coverpage.topList.append(taskModel.tododata) + if (taskModel.tododata.length > 0) { + coverpage.empty = false + } else { + coverpage.empty = true + } + } + function themeStyleToString(style) { + switch (style) { + case VisualStyle.Bright: + return "Theme: Bright" + case VisualStyle.Dark: + return "Theme: Dark" + } + return "Theme: UNKNOWN :(" + } + function getSearchBackground() { + switch (Application.themeSupport.theme.colorTheme.style) { + case VisualStyle.Bright: + return Color.create("#0098F0") + case VisualStyle.Dark: + return Color.create("#262626") + } + return Color.Gray; + } + } + onPopTransitionEnded: { + page.destroy() + taskModel.setView() + filterList.text = taskModel.activeFilters() + appliedFilters.visible = taskModel.activeFilters().length > 0 ? true : false + } +} diff --git a/bar-descriptor.xml b/bar-descriptor.xml new file mode 100644 index 0000000..d0a35e8 --- /dev/null +++ b/bar-descriptor.xml @@ -0,0 +1,118 @@ + + + + + + + + com.monkeystew.RenamedTodo + + armle-v7 + RenamedTodo + + + Qnx/Cascades + armle-v7 + RenamedTodo.so + + + armle-v7 + RenamedTodo + + + x86 + RenamedTodo + + + + Renamed Todo + + + 0.9.0 + + + 1 + + + + + + The RenamedTodo application + + + + + + The Renamed Todo applicationn + + rtd_512_3-86.png + rtd_512_3-90.png + rtd_512_3-96.png + rtd_512_3-110.png + rtd_512_3-144.png + + + rtd_splash_1440s.png + rtd_splash_720s.png + rtd_splash_768p.png + + gYAAgP-_4D6fs0QDWOhZdtQjf2I + Morgan McMillian + + + + + + true + none + + + + + + assets + + + + + + rtd_512_3-86.png + rtd_512_3-90.png + rtd_512_3-96.png + rtd_512_3-110.png + rtd_512_3-144.png + rtd_splash_1440s.png + rtd_splash_720s.png + rtd_splash_768p.png + + + run_native + + + diff --git a/config.pri b/config.pri new file mode 100644 index 0000000..848532f --- /dev/null +++ b/config.pri @@ -0,0 +1,134 @@ +# Config.pri file version 2.0. Auto-generated by IDE. Any changes made by user will be lost! +BASEDIR = $$quote($$_PRO_FILE_PWD_) + +device { + CONFIG(debug, debug|release) { + profile { + CONFIG += \ + config_pri_assets \ + config_pri_source_group1 + } else { + CONFIG += \ + config_pri_assets \ + config_pri_source_group1 + } + + } + + CONFIG(release, debug|release) { + !profile { + CONFIG += \ + config_pri_assets \ + config_pri_source_group1 + } + } +} + +simulator { + CONFIG(debug, debug|release) { + !profile { + CONFIG += \ + config_pri_assets \ + config_pri_source_group1 + } + } +} + +config_pri_assets { + OTHER_FILES += \ + $$quote($$BASEDIR/assets/AboutPage.qml) \ + $$quote($$BASEDIR/assets/AppCover.qml) \ + $$quote($$BASEDIR/assets/EditSheet.qml) \ + $$quote($$BASEDIR/assets/FilterPage.qml) \ + $$quote($$BASEDIR/assets/HelpPage.qml) \ + $$quote($$BASEDIR/assets/SettingsPage.qml) \ + $$quote($$BASEDIR/assets/TaskItem.qml) \ + $$quote($$BASEDIR/assets/TaskPage.qml) \ + $$quote($$BASEDIR/assets/VisualStyle.bright/Appointment.png) \ + $$quote($$BASEDIR/assets/VisualStyle.bright/ArrowCircleAlt.png) \ + $$quote($$BASEDIR/assets/VisualStyle.bright/PriceTag.png) \ + $$quote($$BASEDIR/assets/VisualStyle.bright/Watch.png) \ + $$quote($$BASEDIR/assets/VisualStyle.dark/Appointment.png) \ + $$quote($$BASEDIR/assets/VisualStyle.dark/ArrowCircleAlt.png) \ + $$quote($$BASEDIR/assets/VisualStyle.dark/PriceTag.png) \ + $$quote($$BASEDIR/assets/VisualStyle.dark/Watch.png) \ + $$quote($$BASEDIR/assets/Watch_a.png) \ + $$quote($$BASEDIR/assets/help.html) \ + $$quote($$BASEDIR/assets/humane.js) \ + $$quote($$BASEDIR/assets/icons/123.png) \ + $$quote($$BASEDIR/assets/icons/Add.png) \ + $$quote($$BASEDIR/assets/icons/Capitalize.png) \ + $$quote($$BASEDIR/assets/icons/Check.png) \ + $$quote($$BASEDIR/assets/icons/Clock.png) \ + $$quote($$BASEDIR/assets/icons/Clock_a.png) \ + $$quote($$BASEDIR/assets/icons/Date.png) \ + $$quote($$BASEDIR/assets/icons/Delete.png) \ + $$quote($$BASEDIR/assets/icons/DownBox.png) \ + $$quote($$BASEDIR/assets/icons/Funnel.png) \ + $$quote($$BASEDIR/assets/icons/Info.png) \ + $$quote($$BASEDIR/assets/icons/Pencil.png) \ + $$quote($$BASEDIR/assets/icons/PriceTag.png) \ + $$quote($$BASEDIR/assets/icons/Recycle.png) \ + $$quote($$BASEDIR/assets/icons/Search.png) \ + $$quote($$BASEDIR/assets/icons/Sort.png) \ + $$quote($$BASEDIR/assets/icons/Undo.png) \ + $$quote($$BASEDIR/assets/icons/abc.png) \ + $$quote($$BASEDIR/assets/icons/ic_bbm.png) \ + $$quote($$BASEDIR/assets/icons/invoke.png) \ + $$quote($$BASEDIR/assets/icons/rtd_512_3-110.png) \ + $$quote($$BASEDIR/assets/icons/rtd_512_3-144.png) \ + $$quote($$BASEDIR/assets/icons/rtd_512_3-86.png) \ + $$quote($$BASEDIR/assets/icons/rtd_512_3-90.png) \ + $$quote($$BASEDIR/assets/icons/rtd_512_3-96.png) \ + $$quote($$BASEDIR/assets/icons/rtd_splash_1440s.png) \ + $$quote($$BASEDIR/assets/icons/rtd_splash_720s.png) \ + $$quote($$BASEDIR/assets/icons/rtd_splash_768p.png) \ + $$quote($$BASEDIR/assets/main.qml) +} + +config_pri_source_group1 { + SOURCES += \ + $$quote($$BASEDIR/src/LocalFile.cpp) \ + $$quote($$BASEDIR/src/TaskModel.cpp) \ + $$quote($$BASEDIR/src/applicationui.cpp) \ + $$quote($$BASEDIR/src/main.cpp) + + HEADERS += \ + $$quote($$BASEDIR/src/LocalFile.h) \ + $$quote($$BASEDIR/src/TaskModel.h) \ + $$quote($$BASEDIR/src/applicationui.hpp) +} + +CONFIG += precompile_header + +PRECOMPILED_HEADER = $$quote($$BASEDIR/precompiled.h) + +lupdate_inclusion { + SOURCES += \ + $$quote($$BASEDIR/../src/*.c) \ + $$quote($$BASEDIR/../src/*.c++) \ + $$quote($$BASEDIR/../src/*.cc) \ + $$quote($$BASEDIR/../src/*.cpp) \ + $$quote($$BASEDIR/../src/*.cxx) \ + $$quote($$BASEDIR/../assets/*.qml) \ + $$quote($$BASEDIR/../assets/*.js) \ + $$quote($$BASEDIR/../assets/*.qs) \ + $$quote($$BASEDIR/../assets/VisualStyle.bright/*.qml) \ + $$quote($$BASEDIR/../assets/VisualStyle.bright/*.js) \ + $$quote($$BASEDIR/../assets/VisualStyle.bright/*.qs) \ + $$quote($$BASEDIR/../assets/VisualStyle.dark/*.qml) \ + $$quote($$BASEDIR/../assets/VisualStyle.dark/*.js) \ + $$quote($$BASEDIR/../assets/VisualStyle.dark/*.qs) \ + $$quote($$BASEDIR/../assets/icons/*.qml) \ + $$quote($$BASEDIR/../assets/icons/*.js) \ + $$quote($$BASEDIR/../assets/icons/*.qs) + + HEADERS += \ + $$quote($$BASEDIR/../src/*.h) \ + $$quote($$BASEDIR/../src/*.h++) \ + $$quote($$BASEDIR/../src/*.hh) \ + $$quote($$BASEDIR/../src/*.hpp) \ + $$quote($$BASEDIR/../src/*.hxx) +} + +TRANSLATIONS = $$quote($${TARGET}.ts) diff --git a/precompiled.h b/precompiled.h new file mode 100644 index 0000000..db268e3 --- /dev/null +++ b/precompiled.h @@ -0,0 +1,5 @@ +// This file is used to store precompiled headers. + +#include +#include +#include diff --git a/src/LocalFile.cpp b/src/LocalFile.cpp new file mode 100644 index 0000000..fb02c18 --- /dev/null +++ b/src/LocalFile.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LocalFile.h" + +LocalFile::LocalFile() { + mPath = "data/todo"; + mFile = mPath + "/todo.txt"; + mDone = mPath + "/done.txt"; + if (!dir.exists(mPath)) { + dir.mkdir(mPath); + } +} + +LocalFile::~LocalFile() { + // TODO Auto-generated destructor stub +} + +QStringList LocalFile::load() const { + QStringList data; + QFile file(mFile); + file.open(QIODevice::ReadOnly); + QTextStream in(&file); + while (!in.atEnd()) { + QString line = in.readLine(); + data << line; + } + return data; +} + +QStringList LocalFile::loadArchive() const { + QStringList data; + QFile file(mDone); + file.open(QIODevice::ReadOnly); + QTextStream in(&file); + while (!in.atEnd()) { + QString line = in.readLine(); + data << line; + } + return data; +} + +void LocalFile::save(const QStringList &data) { + QSettings settings; + QString lnend = settings.value("windowsbreak").toBool() ? "\r\n" : "\n"; + QFile file(mFile); + file.open(QIODevice::WriteOnly); + QTextStream out(&file); + foreach (QString line, data) { + out << line << lnend; + } + file.close(); +} + +void LocalFile::saveArchive(const QStringList &data) { + QSettings settings; + QString lnend = settings.value("windowsbreak").toBool() ? "\r\n" : "\n"; + QFile file(mDone); + file.open(QIODevice::WriteOnly); + QTextStream out(&file); + foreach (QString line, data) { + out << line << lnend; + } + file.close(); +} + +void LocalFile::archive(const QStringList &data) { + QSettings settings; + QString lnend = settings.value("windowsbreak").toBool() ? "\r\n" : "\n"; + QFile file(mDone); + file.open(QIODevice::Append); + QTextStream out(&file); + foreach (QString line, data) { + out << line << lnend; + } + file.close(); +} + +QString LocalFile::path() const { + return mPath; +} + +void LocalFile::setPath(const QString &path) { + mPath = path; + if (!dir.exists(mPath)) { + dir.mkdir(mPath); + } + mFile = mPath + "/todo.txt"; + mDone = mPath + "/done.txt"; +} diff --git a/src/LocalFile.h b/src/LocalFile.h new file mode 100644 index 0000000..4e79428 --- /dev/null +++ b/src/LocalFile.h @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOCALFILE_H_ +#define LOCALFILE_H_ + +#include +#include +#include +#include +#include + +class LocalFile { + +public: + LocalFile(); + virtual ~LocalFile(); + + QStringList load() const; + QStringList loadArchive() const; + QString path() const; + void save(const QStringList &data); + void saveArchive(const QStringList &data); + void setPath(const QString &path); + void archive(const QStringList &data); + +private: + QDir dir; + QString mPath; + QString mFile; + QString mDone; + +}; + +#endif /* LOCALFILE_H_ */ diff --git a/src/TaskModel.cpp b/src/TaskModel.cpp new file mode 100644 index 0000000..836a161 --- /dev/null +++ b/src/TaskModel.cpp @@ -0,0 +1,664 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TaskModel.h" + +TaskModel::TaskModel(QObject* parent) { + setParent(parent); + + QSettings settings; + + mOffline = false; + mDelete = -1; + + ts_settings = new QSettings("Morgan McMillian", "RenamedTodo"); + + toast = new SystemToast(this); + + mSort = settings.value("sort").toInt(); + if (!mSort) mSort = PRIORITY; + + QString fpath = settings.value("path").toString(); + if (!fpath.isNull()) { + localfile.setPath(fpath); + } + + regxComp.setPattern("^x "); + regxPri.setPattern("\\(([A-Z])\\) "); + regxDate.setPattern("([0-9]{4}-[0-9]{2}-[0-9]{2}) ?"); + regxProj.setPattern("(\\+[^ ]+)"); + regxCtx.setPattern("(@[^ ]+)"); + + qDebug() << "I am life! " << this; + +} + +TaskModel::~TaskModel() { + delete toast; + qDebug() << "I am death! " << this; +} + +int TaskModel::sort() const { + return mSort; +} + +void TaskModel::setSort(const int &sort) { + QSettings settings; + mSort = sort; + settings.setValue("sort", sort); + setView(); + emit listUpdated(); +} + +QVariant TaskModel::setting(const QString &setting, const QVariant &defVal) const { + QSettings settings; + if (settings.value(setting).isNull()) { + return defVal; + } + return settings.value(setting); +} + +QString TaskModel::activeFilters() { + QString filterlist; + foreach(QString item, mFilters) { + filterlist = filterlist + item + ","; + } + if (filterlist.size() > 0) { + return " Filter: " + filterlist; + } else { + return ""; + } +} + +QString TaskModel::formatDate(const QDateTime &date) const { + return date.toString("yyyy-MM-dd"); +} + +void TaskModel::modifySetting(const QString &setting, const QVariant &value) { + QSettings settings; + settings.setValue(setting, value); + if (setting == "sort") mSort = value.toInt(); + if (setting == "path") { + localfile.setPath(value.toString()); + load(); + } +} + +void TaskModel::onFileDataChanged(QStringList data) { + localfile.save(data); + load(); + setView(); +} + +void TaskModel::onArchiveData(QStringList data) { + localfile.saveArchive(data); + mArchiveData = data; +} + +QVariantList TaskModel::filters() const { + QVariantList filters; + foreach (QString project, mProjects) { + QVariantMap map; + map["type"] = "Projects"; + map["title"] = project; + if (mFilters.indexOf(project) >= 0) { + map["checked"] = true; + } else { + map["checked"] = false; + } + filters.append(map); + } + foreach (QString context, mContexts) { + QVariantMap map; + map["type"] = "Contexts"; + map["title"] = context; + if (mFilters.indexOf(context) >= 0) { + map["checked"] = true; + } else { + map["checked"] = false; + } + filters.append(map); + } + foreach (QString duedate, mDueDates) { + QVariantMap map; + qDebug() << "::" + duedate; + map["type"] = "Due Dates"; + map["title"] = duedate; + if (mFilters.indexOf(duedate) >= 0) { + map["checked"] = true; + } else { + map["checked"] = false; + } + filters.append(map); + } + return filters; +} + +QVariantList TaskModel::tododata() { + QVariantList rData; + foreach (QString item, mTodoList) { + QVariantMap map = parseTask(item); + rData.append(map); + } + return rData; +} + +void TaskModel::refresh() { + QSettings settings; + load(); + emit listUpdated(); +} + +void TaskModel::commit() { + QSettings settings; + QString lnend = settings.value("windowsbreak").toBool() ? "\r\n" : "\n"; + save(); +} + +void TaskModel::load() { + mTodoData.clear(); + QStringList dummy; + dummy = localfile.load(); + foreach (QString item, dummy) { + QVariantMap map = parseTask(item); + mTodoData.append(map); + } + + mArchiveData = localfile.loadArchive(); +} + +void TaskModel::save() { + QStringList data; + foreach (QVariant map, mTodoData) { + QString listitem = buildTask(map.toMap()); + data.append(listitem); + } + localfile.save(data); + load(); + setView(); + emit listUpdated(); +} + +void TaskModel::archive() { + QSettings settings; + QString lnend = settings.value("windowsbreak").toBool() ? "\r\n" : "\n"; + foreach (QVariant map, mTodoData) { + QVariantMap task = map.toMap(); + if (task["complete"].toBool()) { + QString architem = buildTask(task); + mArchiveData.append(architem); + mTodoData.removeAt(mTodoData.indexOf(task)); + } + } + if (mArchiveData.size() > 0) { + localfile.saveArchive(mArchiveData); + commit(); + } else { + load(); + setView(); + } +} + +void TaskModel::search(const QString &text) { + mSearch = text; + setView(); +} + +void TaskModel::setValue(int idx, const QString &key, const QVariant &value) { + //qDebug() << "index: " << idx; + //qDebug() << "key: " << key; + //qDebug() << "value: " << value; + //qDebug() << "check: " << QVariantListDataModel::value(idx).value(); + QSettings settings; + if (idx >=0 && idx < size()) { + QVariantMap current = QVariantListDataModel::value(idx).value(); + QVariantMap updated = current; + updated[key] = value; + if (key == "complete" && value == true) { + updated["priority"] = ""; + updated["dateCompleted"] = QDate::currentDate().toString("yyyy-MM-dd"); + } else if (key == "complete" && value == false) { + updated["dateCompleted"] = ""; + } + QString rtask = buildTask(updated); + updated["text"] = QVariant(rtask); + //qDebug() << "current: " << current; + //qDebug() << "idx: " << idx; + //qDebug() << "orig idx: " << mTodoData.indexOf(current); + //qDebug() << "test0:" << mTodoData.value(0); + //qDebug() << "testX:" << mTodoData.value(mTodoData.size()-1); + int origidx = mTodoData.indexOf(current); + mTodoData.replace(origidx, updated); + //setView(); + commit(); + if (key == "complete" && value == true && settings.value("autoarchive").toBool()) { + archive(); + } + } + //qDebug() << "new: " << QVariantListDataModel::value(idx).value(); +} + +void TaskModel::exportFiles(const QStringList &files) { + + QString epath = files[0]; + QRegExp epathrgx("todo.txt$"); + epath.replace(epathrgx, ""); + + LocalFile exportfrom; + LocalFile exportto; + exportto.setPath(epath); + + QStringList todo = exportfrom.load(); + QStringList done = exportfrom.loadArchive(); + + exportto.save(todo); + exportto.saveArchive(done); +} + +void TaskModel::promptPurgeSandbox() { + dialog = new SystemDialog("PURGE", "CANCEL"); + dialog->setTitle("Purge local sandbox"); + dialog->setBody("Erase local sandbox files? WARNING This cannot be undone."); + + bool success = QObject::connect(dialog, SIGNAL(finished(bb::system::SystemUiResult::Type)), + this, SLOT(onConfirmPurge(bb::system::SystemUiResult::Type))); + + if (success) { + dialog->show(); + } else { + dialog->deleteLater(); + } +} + +void TaskModel::onConfirmPurge(bb::system::SystemUiResult::Type value) { + QStringList empty; + LocalFile sandbox; + switch(value) { + case bb::system::SystemUiResult::ConfirmButtonSelection: + qDebug() << "PURGE"; + sandbox.save(empty); + sandbox.saveArchive(empty); + load(); + setView(); + break; + case bb::system::SystemUiResult::CancelButtonSelection: + qDebug() << "CANCEL"; + break; + default: + break; + } + + dialog->deleteLater(); +} + +void TaskModel::promptDelete(int idx) { + dialog = new SystemDialog("DELETE", "CANCEL"); + dialog->setTitle("Delete Task"); + dialog->setBody("Permanently delete this Entry?"); + + bool success = QObject::connect(dialog, SIGNAL(finished(bb::system::SystemUiResult::Type)), + this, SLOT(onDeleteTask(bb::system::SystemUiResult::Type))); + + if (success) { + mDelete = idx; + dialog->show(); + } else { + mDelete = -1; + dialog->deleteLater(); + } + +} + +void TaskModel::onDeleteTask(bb::system::SystemUiResult::Type value) { + switch(value) { + case bb::system::SystemUiResult::ConfirmButtonSelection: + //qDebug() << "DELETE"; + delTask(mDelete); + break; + case bb::system::SystemUiResult::CancelButtonSelection: + //qDebug() << "CANCEL"; + mDelete = -1; + break; + default: + break; + } + + dialog->deleteLater(); +} + +void TaskModel::delTask(int idx) { + if (idx >=0 && idx < size()) { + QVariantMap current = QVariantListDataModel::value(idx).value(); + int origidx = mTodoData.indexOf(current); + //qDebug() << "idx: " << idx; + //qDebug() << "orig idx: " << mTodoData.indexOf(current); + mTodoData.removeAt(origidx); + //setView(); + commit(); + mDelete = -1; + } +} + +void TaskModel::changeFilter(const QString &filter, const bool &enabled) { + int idx = mFilters.indexOf(filter); + if (enabled) { + if (idx == -1) mFilters.append(filter); + } else { + if (idx >= 0) mFilters.removeAt(idx); + } + //qDebug() << "Filter List: " << mFilters; +} + +void TaskModel::resetFilter() { + mFilters.clear(); + setView(); + toast->setBody("Filters removed."); + toast->show(); +} + +void TaskModel::addFullTask(const QString &task) { + QVariantMap map = parseTask(task); + QSettings settings; + if (settings.value("datenew").toBool()) { + map["dateCreated"] = QDate::currentDate().toString("yyyy-MM-dd"); + } + mTodoData.append(map); + //setView(); + commit(); +} + +void TaskModel::updateTask(int idx, const QString &task) { + if (idx >=0 && idx < size()) { + QVariantMap current = QVariantListDataModel::value(idx).value(); + int origidx = mTodoData.indexOf(current); + QVariantMap map = parseTask(task); + if (origidx >= 0) { + mTodoData.replace(origidx, map); + //setView(); + commit(); + } else { + // TODO produce some error message + qDebug() << "ERROR: origidx = " << origidx; + } + } +} + +QVariantMap TaskModel::parseTask(QString rawTask) { + QVariantMap task; + int pos = 0; + + QString item = rawTask; + bool complete = false; + QString priority = ""; + QString dateCompleted = ""; + QString dateCreated = ""; + QString dateDue = ""; + QString detail = ""; + + //qDebug() << "..parsing projects.."; + QStringList prj; + pos = 0; + while ((pos = regxProj.indexIn(item,pos)) != -1) { + prj << regxProj.cap(1); + pos += regxProj.matchedLength(); + } + if (prj.size() > 0) { + foreach (QString p, prj) { + if (mProjects.indexOf(p) < 0) { + mProjects << p; + } + } + } + //qDebug() << "my projects: " << mProjects; + + //qDebug() << "..parsing contexts.."; + QStringList ctx; + pos = 0; + while ((pos = regxCtx.indexIn(item,pos)) != -1) { + ctx << regxCtx.cap(1); + pos += regxCtx.matchedLength(); + } + if (ctx.size() > 0) { + foreach (QString c, ctx) { + if (mContexts.indexOf(c) < 0) { + mContexts << c; + } + } + } + //qDebug() << "my contexts: " << mContexts; + + QRegExp regxDue("due:([0-9]{4}-[0-9]{2}-[0-9]{2}) ?"); + if (regxDue.indexIn(item,0) != -1) { + dateDue = regxDue.cap(1); + QString duestr = "due:" + dateDue; + if (dateDue.length() > 0) { + if (mDueDates.indexOf(duestr) < 0) { + mDueDates << duestr; + } + } + } + + //qDebug() << "---*****---"; + if (regxComp.indexIn(item) == 0) { + //qDebug() << "complete: true"; + complete = true; + item.replace(regxComp, ""); + pos = 0; + QStringList dates; + while ((pos = regxDate.indexIn(item,pos)) != -1) { + dates << regxDate.cap(1); + pos += regxDate.matchedLength(); + } + if (dates.size() > 0) { + //qDebug() << "completed: " << dates.at(0); + dateCompleted = dates.at(0); + if (dates.size() >= 2) { + //qDebug() << "created: " << dates.at(1); + dateCreated = dates.at(1); + pos = regxDate.indexIn(item,0); + item.replace(QRegExp("^([0-9]{4}-[0-9]{2}-[0-9]{2} )"), ""); + } + } + pos = regxDate.indexIn(item,0); + item.replace(QRegExp("^([0-9]{4}-[0-9]{2}-[0-9]{2} )"), ""); + } else if (regxDate.indexIn(item) >= 0 && regxDate.indexIn(item) < 5) { + dateCreated = regxDate.cap(1); +// item.replace(regxDate.cap(1) + " ", ""); +// item.replace(QRegExp("^([0-9]{4}-[0-9]{2}-[0-9]{2} )"), ""); + item.remove(regxDate.indexIn(item), 11); + } + if (regxPri.indexIn(item) >= 0) { + //qDebug() << "priority: " << regxPri.cap(1); + priority = regxPri.cap(1); + item.replace(regxPri, ""); + } + detail = item; + + task["complete"] = QVariant(complete); + task["priority"] = QVariant(priority); + task["dateCompleted"] = QVariant(dateCompleted); + task["dateCreated"] = QVariant(dateCreated); + task["dateDue"] = QVariant(dateDue); + task["detail"] = QVariant(detail); + task["text"] = QVariant(rawTask); + + return task; +} + +QString TaskModel::buildTask(const QVariantMap &task) { + QString text = ""; + bool complete = task["complete"].toBool(); + QString priority = task["priority"].toString(); + QString dateCompleted = task["dateCompleted"].toString(); + QString dateCreated = task["dateCreated"].toString(); + QString detail = task["detail"].toString(); + if (complete) text = text + "x "; + if (priority.length() > 0) text = text + "(" + priority + ") "; + if (dateCompleted.length() > 0) text = text + dateCompleted + " "; + if (dateCreated.length() > 0) text = text + dateCreated + " "; + if (detail.length() > 0) text = text + detail; + return text; +} + +bool TaskModel::sortByPriority(const QString &a, const QString &b) { + QString matchA; + QString matchB; + + QRegExp pri("\\(([A-Z])\\) "); + QRegExp done("^x "); + QRegExp date("([0-9]{4}-[0-9]{2}-[0-9]{2}) ?"); + QRegExp sca("^@"); + QRegExp scp("^\\+"); + + if (pri.indexIn(a) >= 0) { + matchA = pri.cap(1); + } else if (done.indexIn(a) == 0) { + matchA = "}"; + } else { + matchA = a.toLower(); + matchA.replace(date,""); + matchA.replace(sca,""); + matchA.replace(scp,""); + } + //qDebug() << "a: " << a; + //qDebug() << "matchA: " << matchA; + if (pri.indexIn(b) >= 0) { + matchB = pri.cap(1); + } else if (done.indexIn(b) == 0) { + matchB = "}"; + } else { + matchB = b.toLower(); + matchB.replace(date,""); + matchB.replace(sca,""); + matchB.replace(scp,""); + } + //qDebug() << "b: " << b; + //qDebug() << "matchB: " << matchB; + return matchA < matchB; +} + +bool TaskModel::sortByText(const QString &a, const QString &b) { + QString matchA = a; + QString matchB = b; + + QRegExp pri("\\([A-Z]\\) "); + QRegExp done("^x "); + QRegExp date("([0-9]{4}-[0-9]{2}-[0-9]{2}) ?"); + QRegExp sca("^@"); + QRegExp scp("^\\+"); + + matchA.replace(done, ""); + matchA.replace(pri, ""); + matchA.replace(date, ""); + matchA.replace(sca,""); + matchA.replace(scp,""); + //qDebug() << "A: " << matchA; + matchB.replace(done, ""); + matchB.replace(pri, ""); + matchB.replace(date, ""); + matchB.replace(sca,""); + matchB.replace(scp,""); + //qDebug() << "B: " << matchB; + + return matchA.toLower() < matchB.toLower(); +} + +bool TaskModel::sortByDueDate(const QString &a, const QString &b) { + QString matchA = a; + QString matchB = b; + + QRegExp regxDue("(due:)([0-9]{4}-[0-9]{2}-[0-9]{2}) ?"); + QRegExp pri("\\([A-Z]\\) "); + QRegExp done("^x "); + QRegExp date("([0-9]{4}-[0-9]{2}-[0-9]{2}) ?"); + QRegExp sca("^@"); + QRegExp scp("^\\+"); + + if (regxDue.indexIn(a,0) != -1) { + matchA = regxDue.cap(2); + } else if (done.indexIn(a) == 0) { + matchA = "}"; + } else { + matchA.replace(done, ""); + matchA.replace(pri, ""); + matchA.replace(date, ""); + matchA.replace(sca,""); + matchA.replace(scp,""); + } + + if (regxDue.indexIn(b,0) != -1) { + matchB = regxDue.cap(2); + } else if (done.indexIn(b) == 0) { + matchB = "}"; + } else { + matchB.replace(done, ""); + matchB.replace(pri, ""); + matchB.replace(date, ""); + matchB.replace(sca,""); + matchB.replace(scp,""); + } + + return matchA.toLower() < matchB.toLower(); +} + +void TaskModel::setView() { + + mTodoList.clear(); + mProjects.clear(); + mContexts.clear(); + mDueDates.clear(); + //qDebug() << "::" << mFilters; + foreach (QVariant map, mTodoData) { + QString listitem = buildTask(map.toMap()); + if (mSearch.length() > 0) { + if (listitem.contains(mSearch, Qt::CaseInsensitive)) { + mTodoList.append(listitem); + } + } else if (mFilters.length() > 0) { + // TODO this results in an "or" condition, probably should be "and" instead + foreach (QString filter, mFilters) { + if (listitem.indexOf(filter) >=0) { + mTodoList.append(listitem); + break; + } + } + } else { + mTodoList.append(listitem); + } + } + clear(); + + switch (mSort) { + case PRIORITY: + qSort(mTodoList.begin(), mTodoList.end(), sortByPriority); + break; + case ID: + // this is the default + break; + case TEXT: + qSort(mTodoList.begin(), mTodoList.end(), sortByText); + break; + case DUE: + qSort(mTodoList.begin(), mTodoList.end(), sortByDueDate); + break; + } + + foreach (QString item, mTodoList) { + QVariantMap map = parseTask(item); + append(map); + } + emit listUpdated(); +} diff --git a/src/TaskModel.h b/src/TaskModel.h new file mode 100644 index 0000000..48ee141 --- /dev/null +++ b/src/TaskModel.h @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2018 Morgan McMillian + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TASKMODEL_H_ +#define TASKMODEL_H_ + +#include +#include +#include +#include +#include +#include + +#include "LocalFile.h" + +using namespace bb::cascades; +using namespace bb::system; + +class TaskModel: public bb::cascades::QVariantListDataModel { + Q_OBJECT + + Q_PROPERTY(int sort READ sort WRITE setSort NOTIFY sortChanged) + Q_PROPERTY(QVariantList filters READ filters FINAL) + Q_PROPERTY(QVariantList tododata READ tododata FINAL) + +public: + TaskModel(QObject* parent = 0); + virtual ~TaskModel(); + + enum SortType { PRIORITY, ID, TEXT, DUE }; + Q_ENUMS(SortType); + + int sort() const; + void setSort(const int &sort); + QVariantList filters() const; + QVariantList tododata(); + + Q_INVOKABLE void refresh(); + Q_INVOKABLE void commit(); + Q_INVOKABLE void load(); + Q_INVOKABLE void save(); + Q_INVOKABLE void archive(); + Q_INVOKABLE void search(const QString &text); + Q_INVOKABLE QVariant setting(const QString &setting, const QVariant &defVal) const; + Q_INVOKABLE QString activeFilters(); + Q_INVOKABLE QString formatDate(const QDateTime &date) const; + Q_INVOKABLE void promptPurgeSandbox(); + Q_INVOKABLE void exportFiles(const QStringList &files); + Q_SLOT void setView(); + Q_SLOT void setValue(int idx, const QString &key, const QVariant &value); + Q_SLOT void updateTask(int idx, const QString &task); + Q_SLOT void addFullTask(const QString &task); + Q_SLOT void promptDelete(int idx); + Q_SLOT void delTask(int idx); + Q_SLOT void changeFilter(const QString &filter, const bool &enabled); + Q_SLOT void resetFilter(); + Q_SLOT void modifySetting(const QString &setting, const QVariant &value); + Q_SLOT void onFileDataChanged(QStringList data); + Q_SLOT void onArchiveData(QStringList data); + Q_SLOT void onDeleteTask(bb::system::SystemUiResult::Type value); + Q_SLOT void onConfirmPurge(bb::system::SystemUiResult::Type value); + + Q_SIGNAL void sortChanged(SortType sort); + Q_SIGNAL void listUpdated(); + +private: + + QVariantMap parseTask(QString rawTask); + QString buildTask(const QVariantMap &task); + static bool sortByPriority(const QString &a, const QString &b); + static bool sortByText(const QString &a, const QString &b); + static bool sortByDueDate(const QString &a, const QString &b); + + QRegExp regxComp; + QRegExp regxPri; + QRegExp regxDate; + QRegExp regxProj; + QRegExp regxCtx; + + QSettings *ts_settings; + LocalFile localfile; + SystemDialog *dialog; + SystemToast *toast; + + QStringList mProjects; + QStringList mContexts; + QStringList mDueDates; + QStringList mFilters; + QStringList mTodoList; + QStringList mArchiveData; + QVariantList mTodoData; + QString mSearch; + int mSort; + int mDelete; + bool mOffline; + +}; + +#endif /* TASKMODEL_H_ */ diff --git a/src/applicationui.cpp b/src/applicationui.cpp new file mode 100644 index 0000000..7a23067 --- /dev/null +++ b/src/applicationui.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011-2015 BlackBerry Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "applicationui.hpp" +#include "TaskModel.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace bb::cascades; + +ApplicationUI::ApplicationUI() : + QObject() +{ + // prepare the invoke manager + invokeManager = new bb::system::InvokeManager(this); + connect(invokeManager, SIGNAL(invoked(const bb::system::InvokeRequest&)), + this, SLOT(onInvoke(const bb::system::InvokeRequest&))); + + // prepare the localization + m_pTranslator = new QTranslator(this); + m_pLocaleHandler = new LocaleHandler(this); + + bool res = QObject::connect(m_pLocaleHandler, SIGNAL(systemLanguageChanged()), this, SLOT(onSystemLanguageChanged())); + // This is only available in Debug builds + Q_ASSERT(res); + // Since the variable is not used in the app, this is added to avoid a + // compiler warning + Q_UNUSED(res); + + // initial load + onSystemLanguageChanged(); + + qmlRegisterType("com.monkeystew.taskmodel", 1, 0, "TaskModel"); + qmlRegisterType("bb.cascades", 1, 0, "SceneCover"); + qmlRegisterUncreatableType("bb.cascades", 1, 0, "AbstractCover", + "An AbstractCover cannot be created."); + + // Create scene document from main.qml asset, the parent is set + // to ensure the document gets destroyed properly at shut down. + QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this); + qml->setContextProperty("_Taskslayer", this); + + // Create root object for the UI + AbstractPane *root = qml->createRootObject(); + + // Set created root object as the application scene + Application::instance()->setScene(root); + + bb::ApplicationInfo appinfo; + qDebug() << "APP VER_ " << appinfo.version(); + root->setProperty("appversion", appinfo.version()); +} + +void ApplicationUI::onSystemLanguageChanged() +{ + QCoreApplication::instance()->removeTranslator(m_pTranslator); + // Initiate, load and install the application translation files. + QString locale_string = QLocale().name(); + QString file_name = QString("RenamedTodo_%1").arg(locale_string); + if (m_pTranslator->load(file_name, "app/native/qm")) { + QCoreApplication::instance()->installTranslator(m_pTranslator); + } +} + +void ApplicationUI::onInvoke(const bb::system::InvokeRequest& request) +{ + if (request.action() == "bb.action.SHARE") { + Q_EMIT addNewTask(QString::fromUtf8(request.data())); + } else if (request.action() == "bb.action.SEARCH.EXTENDED") { + Q_EMIT searchTaskList(QString::fromUtf8(request.data())); + } +} + +void ApplicationUI::getSupport(const int target) +{ + bb::system::InvokeRequest request; + + switch(target) + { + case 0: + request.setTarget("sys.pim.uib.email.hybridcomposer"); + request.setAction("bb.action.COMPOSE"); + request.setMimeType("message/rfc822"); + request.setUri(QUrl("mailto:rtd@monkeystew.com?subject=Renamed Todo for BlackBerry 10")); + invokeManager->invoke(request); + break; + } +} diff --git a/src/applicationui.hpp b/src/applicationui.hpp new file mode 100644 index 0000000..bb6f3fc --- /dev/null +++ b/src/applicationui.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011-2015 BlackBerry Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ApplicationUI_HPP_ +#define ApplicationUI_HPP_ + +#include +#include +#include + +namespace bb +{ + namespace cascades + { + class LocaleHandler; + } +} + +class QTranslator; + +/*! + * @brief Application UI object + * + * Use this object to create and init app UI, to create context objects, to register the new meta types etc. + */ +class ApplicationUI : public QObject +{ + Q_OBJECT +public: + ApplicationUI(); + virtual ~ApplicationUI() {} + + Q_INVOKABLE void getSupport(const int target); + +Q_SIGNALS: + void addNewTask(QString data); + void searchTaskList(QString data); +private slots: + void onSystemLanguageChanged(); + void onInvoke(const bb::system::InvokeRequest &request); +private: + QTranslator* m_pTranslator; + bb::cascades::LocaleHandler* m_pLocaleHandler; + bb::system::InvokeManager *invokeManager; +}; + +#endif /* ApplicationUI_HPP_ */ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b955edf --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011-2015 BlackBerry Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "applicationui.hpp" + +#include + +#include +#include + +#include + +using namespace bb::cascades; + +Q_DECL_EXPORT int main(int argc, char **argv) +{ + Application app(argc, argv); + + // Create the Application UI object, this is where the main.qml file + // is loaded and the application scene is set. + ApplicationUI appui; + + // Enter the application main event loop. + return Application::exec(); +} diff --git a/translations/Makefile b/translations/Makefile new file mode 100644 index 0000000..0eeb116 --- /dev/null +++ b/translations/Makefile @@ -0,0 +1,12 @@ +QMAKE_TARGET = RenamedTodo +LUPDATE = $(QNX_HOST)/usr/bin/lupdate +LRELEASE = $(QNX_HOST)/usr/bin/lrelease + +update: $(QMAKE_TARGET).pro FORCE + $(LUPDATE) $(QMAKE_TARGET).pro + +release: $(QMAKE_TARGET).pro $(QMAKE_TARGET).ts + $(LRELEASE) $(QMAKE_TARGET).pro + +FORCE: + diff --git a/translations/RenamedTodo.pro b/translations/RenamedTodo.pro new file mode 100644 index 0000000..2192878 --- /dev/null +++ b/translations/RenamedTodo.pro @@ -0,0 +1 @@ +include (../RenamedTodo.pro) diff --git a/translations/RenamedTodo.ts b/translations/RenamedTodo.ts new file mode 100644 index 0000000..07a7469 --- /dev/null +++ b/translations/RenamedTodo.ts @@ -0,0 +1,4 @@ + + + +