From 07fb609095291f8d8544441925dea3d60d636f87 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Tue, 16 Feb 2016 23:40:04 +0100 Subject: Moved qml to subdir to unbundle --- rockwork/qml/AppSettingsPage.qml | 78 ++++++++ rockwork/qml/AppStoreDetailsPage.qml | 278 +++++++++++++++++++++++++++++ rockwork/qml/AppStorePage.qml | 266 +++++++++++++++++++++++++++ rockwork/qml/ContentPeerPickerPage.qml | 41 +++++ rockwork/qml/DeveloperToolsPage.qml | 157 ++++++++++++++++ rockwork/qml/FirmwareUpgradePage.qml | 58 ++++++ rockwork/qml/HealthSettingsDialog.qml | 115 ++++++++++++ rockwork/qml/ImportPackagePage.qml | 32 ++++ rockwork/qml/InfoPage.qml | 86 +++++++++ rockwork/qml/InstalledAppDelegate.qml | 88 +++++++++ rockwork/qml/InstalledAppsPage.qml | 201 +++++++++++++++++++++ rockwork/qml/Main.qml | 53 ++++++ rockwork/qml/MainMenuPage.qml | 317 +++++++++++++++++++++++++++++++++ rockwork/qml/NotificationsPage.qml | 88 +++++++++ rockwork/qml/PebbleModels.qml | 28 +++ rockwork/qml/PebblesPage.qml | 69 +++++++ rockwork/qml/ScreenshotsPage.qml | 107 +++++++++++ rockwork/qml/SettingsPage.qml | 80 +++++++++ rockwork/qml/SystemAppIcon.qml | 67 +++++++ 19 files changed, 2209 insertions(+) create mode 100644 rockwork/qml/AppSettingsPage.qml create mode 100644 rockwork/qml/AppStoreDetailsPage.qml create mode 100644 rockwork/qml/AppStorePage.qml create mode 100644 rockwork/qml/ContentPeerPickerPage.qml create mode 100644 rockwork/qml/DeveloperToolsPage.qml create mode 100644 rockwork/qml/FirmwareUpgradePage.qml create mode 100644 rockwork/qml/HealthSettingsDialog.qml create mode 100644 rockwork/qml/ImportPackagePage.qml create mode 100644 rockwork/qml/InfoPage.qml create mode 100644 rockwork/qml/InstalledAppDelegate.qml create mode 100644 rockwork/qml/InstalledAppsPage.qml create mode 100644 rockwork/qml/Main.qml create mode 100644 rockwork/qml/MainMenuPage.qml create mode 100644 rockwork/qml/NotificationsPage.qml create mode 100644 rockwork/qml/PebbleModels.qml create mode 100644 rockwork/qml/PebblesPage.qml create mode 100644 rockwork/qml/ScreenshotsPage.qml create mode 100644 rockwork/qml/SettingsPage.qml create mode 100644 rockwork/qml/SystemAppIcon.qml (limited to 'rockwork/qml') diff --git a/rockwork/qml/AppSettingsPage.qml b/rockwork/qml/AppSettingsPage.qml new file mode 100644 index 0000000..d8d865b --- /dev/null +++ b/rockwork/qml/AppSettingsPage.qml @@ -0,0 +1,78 @@ +import QtQuick 2.4 +import Ubuntu.Web 0.2 +import Ubuntu.Components 1.3 +import com.canonical.Oxide 1.0 as Oxide + +Page { + id: settings + + property string uuid; + property string url; + property var pebble; + + title: i18n.tr("App Settings") + + WebContext { + id: webcontext + userAgent: "Mozilla/5.0 (Linux; Android 5.0; Nexus 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36 Ubuntu Touch (RockWork)" + } + + WebView { + id: webview + anchors { + fill: parent + bottom: parent.bottom + } + width: parent.width + height: parent.height + + context: webcontext + url: settings.url + preferences.localStorageEnabled: true + preferences.appCacheEnabled: true + preferences.javascriptCanAccessClipboard: true + + function navigationRequestedDelegate(request) { + //The pebblejs:// protocol is handeled by the urihandler, as it appears we can't intercept it + + var url = request.url.toString(); + console.log(url, url.substring(0, 16)); + if (url.substring(0, 16) == 'pebblejs://close') { + pebble.configurationClosed(settings.uuid, url); + request.action = Oxide.NavigationRequest.ActionReject; + pageStack.pop(); + } + } + + Component.onCompleted: { + preferences.localStorageEnabled = true; + } + } + + ProgressBar { + height: units.dp(3) + anchors { + left: parent.left + right: parent.right + top: parent.top + } + + showProgressPercentage: false + value: (webview.loadProgress / 100) + visible: (webview.loading && !webview.lastLoadStopped) + } + + Connections { + target: UriHandler + onOpened: { + if (uris && uris[0] && uris[0].length) { + var url = uris[0]; + + if (url.substring(0, 16) == 'pebblejs://close') { + pebble.configurationClosed(settings.uuid, url); + pageStack.pop(); + } + } + } + } +} diff --git a/rockwork/qml/AppStoreDetailsPage.qml b/rockwork/qml/AppStoreDetailsPage.qml new file mode 100644 index 0000000..696e3c6 --- /dev/null +++ b/rockwork/qml/AppStoreDetailsPage.qml @@ -0,0 +1,278 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import Ubuntu.Components.ListItems 1.3 +import QtGraphicalEffects 1.0 + +Page { + id: root + title: i18n.tr("App details") + + property var pebble: null + property var app: null + + ColumnLayout { + anchors.fill: parent + spacing: units.gu(1) + + Item { + Layout.fillWidth: true + height: headerColumn.height + units.gu(1) + + RowLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + spacing: units.gu(1) + height: headerColumn.height + + UbuntuShape { + id: iconShape + Layout.fillHeight: true + Layout.preferredWidth: height + + source: Image { + height: iconShape.height + width: iconShape.width + source: root.app.icon + } + } + + ColumnLayout { + id: headerColumn + Layout.fillWidth: true + Label { + text: root.app.name + fontSize: "large" + Layout.fillWidth: true + elide: Text.ElideRight + } + Label { + text: root.app.vendor + Layout.fillWidth: true + } + } + + Button { + id: installButton + text: enabled ? i18n.tr("Install") : (installing && !installed ? i18n.tr("Installing...") : i18n.tr("Installed")) + color: UbuntuColors.green + enabled: !installed && !installing + property bool installing: false + property bool installed: root.pebble.installedApps.contains(root.app.storeId) || root.pebble.installedWatchfaces.contains(root.app.storeId) + Connections { + target: root.pebble.installedApps + onChanged: { + installButton.installed = root.pebble.installedApps.contains(root.app.storeId) || root.pebble.installedWatchfaces.contains(root.app.storeId) + } + } + + Connections { + target: root.pebble.installedWatchfaces + onChanged: { + installButton.installed = root.pebble.installedApps.contains(root.app.storeId) || root.pebble.installedWatchfaces.contains(root.app.storeId) + } + } + + onClicked: { + root.pebble.installApp(root.app.storeId) + installButton.installing = true + } + } + } + } + + Flickable { + Layout.fillHeight: true + Layout.fillWidth: true + contentHeight: contentColumn.height + bottomMargin: units.gu(1) + clip: true + + Column { + id: contentColumn + width: parent.width + height: childrenRect.height + + Image { + width: parent.width + // ss.w : ss.h = w : h + height: sourceSize.height * width / sourceSize.width + fillMode: Image.PreserveAspectFit + source: root.app.headerImage + } + + RowLayout { + anchors { + left: parent.left + right: parent.right + } + height: units.gu(6) + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Row { + anchors.centerIn: parent + spacing: units.gu(1) + Icon { + name: "like" + height: parent.height + width: height + } + Label { + text: root.app.hearts + } + } + } + + Rectangle { + Layout.preferredHeight: parent.height - units.gu(2) + Layout.preferredWidth: units.dp(1) + color: UbuntuColors.lightGrey + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Row { + anchors.centerIn: parent + spacing: units.gu(1) + Icon { + name: root.app.isWatchFace ? "clock-app-symbolic" : "stock_application" + height: parent.height + width: height + } + Label { + text: root.app.isWatchFace ? "Watchface" : "Watchapp" + } + } + } + } + + ColumnLayout { + anchors { left: parent.left; right: parent.right; margins: units.gu(1) } + spacing: units.gu(1) + + PebbleModels { + id: modelModel + } + + + Item { + id: screenshotsItem + Layout.preferredHeight: units.gu(20) + Layout.fillWidth: true + + property bool isRound: modelModel.get(root.pebble.model).shape === "round" + + ListView { + id: screenshotsListView + anchors.centerIn: parent + width: parent.width + height: screenshotsItem.isRound ? units.gu(10) : units.gu(9.5) + orientation: ListView.Horizontal + spacing: units.gu(1) + snapMode: ListView.SnapToItem + preferredHighlightBegin: (screenshotsListView.width - height * .95) / 2 + preferredHighlightEnd: (screenshotsListView.width + height * .95) / 2 + highlightRangeMode: ListView.StrictlyEnforceRange + + model: root.app.screenshotImages + delegate: AnimatedImage { + height: screenshotsListView.height + width: height * 0.95 + fillMode: Image.PreserveAspectFit + source: modelData + } + } + Image { + id: watchImage + // ssw : ssh = w : h + height: parent.height + width: height * sourceSize.width / sourceSize.height + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + source: modelModel.get(root.pebble.model).image + Rectangle { + anchors.centerIn: parent + height: units.gu(10) + width: height + color: "black" + radius: screenshotsItem.isRound ? height / 2 : 0 + } + } + + OpacityMask { + anchors.fill: screenshotsListView + source: screenshotsListView + maskSource: maskRect + } + + Rectangle { + id: maskRect + anchors.fill: screenshotsListView + color: "transparent" + visible: false + + Rectangle { + color: "blue" + anchors.centerIn: parent + height: screenshotsListView.height + width: screenshotsItem.isRound ? height : height * 0.9 + radius: screenshotsItem.isRound ? height / 2 : units.gu(.5) +// anchors.fill: watchImage +// anchors.margins: units.gu(5) +// radius: modelModel.get(root.pebble.model).shape === "rectangle" ? units.gu(.5) : height / 2 +// visible: false + } + } + + } + + Label { + Layout.fillWidth: true + font.bold: true + text: i18n.tr("Description") + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: units.dp(1) + color: UbuntuColors.lightGrey + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + wrapMode: Text.WordWrap + text: root.app.description + } + + GridLayout { + Layout.fillWidth: true + Layout.fillHeight: true + columns: 2 + columnSpacing: units.gu(1) + rowSpacing: units.gu(1) + Label { + text: i18n.tr("Developer") + font.bold: true + } + Label { + text: root.app.vendor + Layout.fillWidth: true + } + Label { + text: i18n.tr("Version") + font.bold: true + } + Label { + text: root.app.version + Layout.fillWidth: true + } + } + } + } + } + } +} diff --git a/rockwork/qml/AppStorePage.qml b/rockwork/qml/AppStorePage.qml new file mode 100644 index 0000000..bb8712b --- /dev/null +++ b/rockwork/qml/AppStorePage.qml @@ -0,0 +1,266 @@ +import QtQuick 2.4 +import Ubuntu.Components 1.3 +import QtQuick.Layouts 1.1 +import RockWork 1.0 + +Page { + id: root + title: showWatchApps ? i18n.tr("Add new watchapp") : i18n.tr("Add new watchface") + + property var pebble: null + property bool showWatchApps: false + property bool showWatchFaces: false + + property string link: "" + + function fetchHome() { + if (showWatchApps) { + client.fetchHome(AppStoreClient.TypeWatchapp) + } else { + client.fetchHome(AppStoreClient.TypeWatchface) + } + } + + head { + actions: [ + Action { + iconName: "search" + onTriggered: { + if (searchField.shown) { + searchField.shown = false; + root.fetchHome(); + } else { + searchField.shown = true; + } + } + } + ] + } + + Component.onCompleted: { + if (root.link) { + client.fetchLink(link) + } else { + root.fetchHome() + } + } + + AppStoreClient { + id: client + hardwarePlatform: pebble.hardwarePlatform + } + + Item { + id: searchField + anchors { left: parent.left; right: parent.right; top: parent.top } + anchors.topMargin: shown ? 0 : -height + Behavior on anchors.topMargin { UbuntuNumberAnimation {} } + opacity: shown ? 1 : 0 + Behavior on opacity { UbuntuNumberAnimation {} } + height: units.gu(6) + + property bool shown: false + onShownChanged: { + if (shown) { + searchTextField.focus = true; + } + } + + TextField { + id: searchTextField + anchors.centerIn: parent + width: parent.width - units.gu(2) + onDisplayTextChanged: { + searchTimer.restart() + } + + Timer { + id: searchTimer + interval: 300 + onTriggered: { + client.search(searchTextField.displayText, root.showWatchApps ? AppStoreClient.TypeWatchapp : AppStoreClient.TypeWatchface); + } + } + } + } + + Item { + anchors { left: parent.left; top: searchField.bottom; right: parent.right; bottom: parent.bottom } + ListView { + anchors.fill: parent + model: ApplicationsFilterModel { + id: appsFilterModel + model: client.model + } + clip: true + section.property: "groupId" + section.labelPositioning: ViewSection.CurrentLabelAtStart | + ViewSection.InlineLabels + section.delegate: ListItem { + height: section ? label.implicitHeight + units.gu(3) : 0 + + Rectangle { + anchors.fill: parent + color: "white" + } + + RowLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + Label { + id: label + text: client.model.groupName(section) + fontSize: "large" +// font.weight: Font.DemiBold + elide: Text.ElideRight + Layout.fillWidth: true + } + AbstractButton { + Layout.fillHeight: true + implicitWidth: seeAllLabel.implicitWidth + height + Row { + anchors.verticalCenter: parent.verticalCenter + Label { + id: seeAllLabel + text: i18n.tr("See all") + } + Icon { + implicitHeight: parent.height + implicitWidth: height + name: "go-next" + } + } + onClicked: { + pageStack.push(Qt.resolvedUrl("AppStorePage.qml"), {pebble: root.pebble, link: client.model.groupLink(section), title: client.model.groupName(section)}); + } + } + } + } + + footer: Item { + height: client.model.links.length > 0 ? units.gu(6) : 0 + width: parent.width + + RowLayout { + anchors { + fill: parent + margins: units.gu(1) + } + spacing: units.gu(1) + + Repeater { + model: client.model.links + Button { + text: client.model.linkName(client.model.links[index]) + onClicked: client.fetchLink(client.model.links[index]); + color: UbuntuColors.orange + Layout.fillWidth: true + } + } + } + } + + delegate: ListItem { + height: delegateColumn.height + units.gu(2) + + RowLayout { + id: delegateRow + anchors.fill: parent + anchors.margins: units.gu(1) + spacing: units.gu(1) + + AnimatedImage { + Layout.fillHeight: true + Layout.preferredWidth: height + source: model.icon + asynchronous: true +// sourceSize.width: width +// sourceSize.height: height + } + + ColumnLayout { + id: delegateColumn + Layout.fillWidth: true; + Layout.fillHeight: true; + Label { + Layout.fillWidth: true + text: model.name + font.weight: Font.DemiBold + elide: Text.ElideRight + } + Label { + Layout.fillWidth: true + text: model.category + } + RowLayout { + Icon { + name: "like" + Layout.preferredHeight: parent.height + Layout.preferredWidth: height + implicitHeight: parent.height + } + Label { + Layout.fillWidth: true + text: model.hearts + } + Icon { + id: tickIcon + name: "tick" + implicitHeight: parent.height + Layout.preferredWidth: height + visible: root.pebble.installedApps.contains(model.storeId) || root.pebble.installedWatchfaces.contains(model.storeId) + Connections { + target: root.pebble.installedApps + onChanged: { + tickIcon.visible = root.pebble.installedApps.contains(model.storeId) || root.pebble.installedWatchfaces.contains(model.storeId) + } + } + + Connections { + target: root.pebble.installedWatchfaces + onChanged: { + tickIcon.visible = root.pebble.installedApps.contains(model.storeId) || root.pebble.installedWatchfaces.contains(model.storeId) + } + } + + } + } + } + + } + + onClicked: { + client.fetchAppDetails(model.storeId); + pageStack.push(Qt.resolvedUrl("AppStoreDetailsPage.qml"), {app: appsFilterModel.get(index), pebble: root.pebble}) + } + } + } + +// RowLayout { +// id: buttonRow +// anchors { left: parent.left; bottom: parent.bottom; right: parent.right; margins: units.gu(1) } +// spacing: units.gu(1) +// Button { +// text: i18n.tr("Previous") +// Layout.fillWidth: true +// enabled: client.offset > 0 +// onClicked: { +// client.previous() +// } +// } +// Button { +// text: i18n.tr("Next") +// Layout.fillWidth: true +// onClicked: { +// client.next() +// } +// } +// } + } + + ActivityIndicator { + anchors.centerIn: parent + running: client.busy + } +} + diff --git a/rockwork/qml/ContentPeerPickerPage.qml b/rockwork/qml/ContentPeerPickerPage.qml new file mode 100644 index 0000000..7ee9702 --- /dev/null +++ b/rockwork/qml/ContentPeerPickerPage.qml @@ -0,0 +1,41 @@ +import QtQuick 2.4 +import Ubuntu.Components 1.3 +import Ubuntu.Content 1.3 +import RockWork 1.0 + +Page { + id: pickerPage + head { + locked: true + visible: false + } + + property alias contentType: contentPeerPicker.contentType + property string itemName + property alias handler: contentPeerPicker.handler + property string filename + + Component { + id: exportItemComponent + ContentItem { + name: pickerPage.itemName + } + } + ContentPeerPicker { + id: contentPeerPicker + anchors.fill: parent + + onCancelPressed: pageStack.pop() + + onPeerSelected: { + var transfer = peer.request(); + var items = []; + var item = exportItemComponent.createObject(); + item.url = "file://" + pickerPage.filename; + items.push(item) + transfer.items = items; + transfer.state = ContentTransfer.Charged; + pageStack.pop(); + } + } +} diff --git a/rockwork/qml/DeveloperToolsPage.qml b/rockwork/qml/DeveloperToolsPage.qml new file mode 100644 index 0000000..2f77254 --- /dev/null +++ b/rockwork/qml/DeveloperToolsPage.qml @@ -0,0 +1,157 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import Ubuntu.Components.Popups 1.3 +import Ubuntu.Content 1.3 + +Page { + id: root + title: i18n.tr("Developer Tools") + + property var pebble: null + + //Creating the menu list this way to allow the text field to be translatable (http://askubuntu.com/a/476331) + ListModel { + id: devMenuModel + dynamicRoles: true + } + + Component.onCompleted: { + populateDevMenu(); + } + + function populateDevMenu() { + devMenuModel.clear(); + + devMenuModel.append({ + icon: "camera-app-symbolic", + text: i18n.tr("Screenshots"), + page: "ScreenshotsPage.qml", + dialog: "", + color: "gold" + }); + devMenuModel.append({ + icon: "dialog-warning-symbolic", + text: i18n.tr("Report problem"), + page: "", + dialog: sendLogsComponent, + color: UbuntuColors.red + }); + devMenuModel.append({ + icon: "stock_application", + text: i18n.tr("Install app or watchface from file"), + page: "ImportPackagePage.qml", + dialog: null, + color: UbuntuColors.blue + }); + + } + + ColumnLayout { + anchors.fill: parent + + Repeater { + id: menuRepeater + model: devMenuModel + delegate: ListItem { + + RowLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + + UbuntuShape { + Layout.fillHeight: true + Layout.preferredWidth: height + backgroundColor: model.color + Icon { + anchors.fill: parent + anchors.margins: units.gu(.5) + name: model.icon + color: "white" + } + } + + + Label { + text: model.text + Layout.fillWidth: true + } + } + + onClicked: { + if (model.page) { + pageStack.push(Qt.resolvedUrl(model.page), {pebble: root.pebble}) + } + if (model.dialog) { + PopupUtils.open(model.dialog) + } + } + } + } + + Item { + Layout.fillHeight: true + Layout.fillWidth: true + } + } + + Component { + id: sendLogsComponent + Dialog { + id: sendLogsDialog + title: i18n.tr("Report problem") + ActivityIndicator { + id: busyIndicator + visible: false + running: visible + } + Label { + text: i18n.tr("Preparing logs package...") + visible: busyIndicator.visible + horizontalAlignment: Text.AlignHCenter + fontSize: "large" + } + + Connections { + target: root.pebble + onLogsDumped: { + if (success) { + var filename = "/tmp/pebble.log" + pageStack.push(Qt.resolvedUrl("ContentPeerPickerPage.qml"), {itemName: i18n.tr("pebble.log"),handler: ContentHandler.Share, contentType: ContentType.All, filename: filename }) + } + PopupUtils.close(sendLogsDialog) + } + } + + Button { + text: i18n.tr("Send rockworkd.log") + color: UbuntuColors.blue + visible: !busyIndicator.visible + onClicked: { + var filename = homePath + "/.cache/upstart/rockworkd.log" + pageStack.push(Qt.resolvedUrl("ContentPeerPickerPage.qml"), {itemName: i18n.tr("rockworkd.log"),handler: ContentHandler.Share, contentType: ContentType.All, filename: filename }) + PopupUtils.close(sendLogsDialog) + } + } + Button { + text: i18n.tr("Send watch logs") + color: UbuntuColors.blue + visible: !busyIndicator.visible + onClicked: { + busyIndicator.visible = true + root.pebble.dumpLogs("/tmp/pebble.log") + } + } + Button { + text: i18n.tr("Cancel") + color: UbuntuColors.red + visible: !busyIndicator.visible + onClicked: { + PopupUtils.close(sendLogsDialog) + } + } + } + } + +} + diff --git a/rockwork/qml/FirmwareUpgradePage.qml b/rockwork/qml/FirmwareUpgradePage.qml new file mode 100644 index 0000000..3281a12 --- /dev/null +++ b/rockwork/qml/FirmwareUpgradePage.qml @@ -0,0 +1,58 @@ +import QtQuick 2.4 +import Ubuntu.Components 1.3 + +Page { + id: root + title: i18n.tr("Firmware upgrade") + + property var pebble: null + + Column { + anchors.fill: parent + anchors.margins: units.gu(1) + spacing: units.gu(2) + + Label { + text: i18n.tr("A new firmware upgrade is available for your Pebble smartwatch.") + fontSize: "large" + width: parent.width + wrapMode: Text.WordWrap + } + + Label { + text: i18n.tr("Currently installed firmware: %1").arg("" + root.pebble.softwareVersion + "") + width: parent.width + wrapMode: Text.WordWrap + } + + Label { + text: i18n.tr("Candidate firmware version: %1").arg("" + root.pebble.candidateVersion + "") + width: parent.width + wrapMode: Text.WordWrap + } + + Label { + text: "" + i18n.tr("Release Notes: %1").arg("
" + root.pebble.firmwareReleaseNotes) + width: parent.width + wrapMode: Text.WordWrap + } + + Label { + text: "" + i18n.tr("Important:") + " " + i18n.tr("This update will also upgrade recovery data. Make sure your Pebble smartwarch is connected to a power adapter.") + width: parent.width + wrapMode: Text.WordWrap + visible: root.pebble.candidateVersion.indexOf("mig") > 0 + } + + Button { + text: "Upgrade now" + anchors.horizontalCenter: parent.horizontalCenter + color: UbuntuColors.blue + onClicked: { + root.pebble.performFirmwareUpgrade(); + pageStack.pop(); + } + } + } +} + diff --git a/rockwork/qml/HealthSettingsDialog.qml b/rockwork/qml/HealthSettingsDialog.qml new file mode 100644 index 0000000..94e5d22 --- /dev/null +++ b/rockwork/qml/HealthSettingsDialog.qml @@ -0,0 +1,115 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import Ubuntu.Components.Popups 1.3 +import Ubuntu.Components.ListItems 1.3 + +Dialog { + id: root + title: i18n.tr("Health settings") + + property var healthParams: null + + signal accepted(); + + RowLayout { + Label { + text: i18n.tr("Health app enabled") + Layout.fillWidth: true + } + Switch { + id: enabledSwitch + checked: healthParams["enabled"] + } + } + + ItemSelector { + id: genderSelector + model: [i18n.tr("Female"), i18n.tr("Male")] + selectedIndex: root.healthParams["gender"] === "female" ? 0 : 1 + } + + RowLayout { + Label { + text: i18n.tr("Age") + Layout.fillWidth: true + } + TextField { + id: ageField + inputMethodHints: Qt.ImhDigitsOnly + text: healthParams["age"] + Layout.preferredWidth: units.gu(10) + } + } + + RowLayout { + Label { + text: i18n.tr("Height (cm)") + Layout.fillWidth: true + } + TextField { + id: heightField + inputMethodHints: Qt.ImhDigitsOnly + text: healthParams["height"] + Layout.preferredWidth: units.gu(10) + } + } + + RowLayout { + Label { + text: i18n.tr("Weight") + Layout.fillWidth: true + } + TextField { + id: weightField + inputMethodHints: Qt.ImhDigitsOnly + text: healthParams["weight"] + Layout.preferredWidth: units.gu(10) + } + } + + RowLayout { + Label { + text: i18n.tr("I want to be more active") + Layout.fillWidth: true + } + Switch { + id: moreActiveSwitch + checked: healthParams["moreActive"] + } + } + + RowLayout { + Label { + text: i18n.tr("I want to sleep more") + Layout.fillWidth: true + } + Switch { + id: sleepMoreSwitch + checked: healthParams["sleepMore"] + } + } + + + Button { + text: i18n.tr("OK") + color: UbuntuColors.green + onClicked: { + root.healthParams["enabled"] = enabledSwitch.checked; + root.healthParams["gender"] = genderSelector.selectedIndex == 0 ? "female" : "male" + root.healthParams["age"] = ageField.text; + root.healthParams["height"] = heightField.text; + root.healthParams["weight"] = weightField.text; + root.healthParams["moreActive"] = moreActiveSwitch.checked; + root.healthParams["sleepMore"] = sleepMoreSwitch.checked; + root.accepted(); + PopupUtils.close(root); + } + } + Button { + text: i18n.tr("Cancel") + color: UbuntuColors.red + onClicked: PopupUtils.close(root) + } +} + diff --git a/rockwork/qml/ImportPackagePage.qml b/rockwork/qml/ImportPackagePage.qml new file mode 100644 index 0000000..4f86f78 --- /dev/null +++ b/rockwork/qml/ImportPackagePage.qml @@ -0,0 +1,32 @@ +import QtQuick 2.4 +import Ubuntu.Components 1.3 +import Ubuntu.Content 1.3 + +Page { + id: root + title: i18n.tr("Import watchapp or watchface") + + property var pebble: null + + ContentPeerPicker { + anchors.fill: parent + handler: ContentHandler.Source + contentType: ContentType.All + showTitle: false + + onPeerSelected: { + var transfer = peer.request(); + + transfer.stateChanged.connect(function() { + if (transfer.state == ContentTransfer.Charged) { + for (var i = 0; i < transfer.items.length; i++) { + print("sideloading package", transfer.items[i].url) + root.pebble.sideloadApp(transfer.items[i].url) + } + pageStack.pop(); + } + }) + } + } +} + diff --git a/rockwork/qml/InfoPage.qml b/rockwork/qml/InfoPage.qml new file mode 100644 index 0000000..3eec387 --- /dev/null +++ b/rockwork/qml/InfoPage.qml @@ -0,0 +1,86 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import Ubuntu.Components.ListItems 1.3 + +Page { + title: "About RockWork" + + Flickable { + anchors.fill: parent + contentHeight: contentColumn.height + units.gu(4) + + ColumnLayout { + id: contentColumn + anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(2) } + spacing: units.gu(2) + + RowLayout { + Layout.fillWidth: true + spacing: units.gu(2) + UbuntuShape { + source: Image { + anchors.fill: parent + source: "artwork/rockwork.svg" + } + height: units.gu(6) + width: height + } + + Label { + text: i18n.tr("Version %1").arg(version) + Layout.fillWidth: true + fontSize: "large" + } + } + + ThinDivider {} + + Label { + text: i18n.tr("Contributors") + Layout.fillWidth: true + font.bold: true + } + Label { + text: "Michael Zanetti
Brian Douglas
Katharine Berry" + Layout.fillWidth: true + } + + ThinDivider {} + + Label { + text: i18n.tr("Legal") + Layout.fillWidth: true + font.bold: true + } + + Label { + text: "This program is free software: you can redistribute it and/or modify" + + "it under the terms of the GNU General Public License as published by" + + "the Free Software Foundation, version 3 of the License.
" + + + "This program is distributed in the hope that it will be useful," + + "but WITHOUT ANY WARRANTY; without even the implied warranty of" + + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" + + "GNU General Public License for more details.
" + + + "You should have received a copy of the GNU General Public License" + + "along with this program. If not, see ." + Layout.fillWidth: true + wrapMode: Text.WordWrap + } + + Label { + text: i18n.tr("This application is neither affiliated with nor endorsed by Pebble Technology Corp.") + Layout.fillWidth: true + wrapMode: Text.WordWrap + } + Label { + text: i18n.tr("Pebble is a trademark of Pebble Technology Corp.") + Layout.fillWidth: true + wrapMode: Text.WordWrap + } + } + } +} + diff --git a/rockwork/qml/InstalledAppDelegate.qml b/rockwork/qml/InstalledAppDelegate.qml new file mode 100644 index 0000000..89f6ba8 --- /dev/null +++ b/rockwork/qml/InstalledAppDelegate.qml @@ -0,0 +1,88 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import RockWork 1.0 + +ListItem { + id: root + + property string uuid: "" + property string name: "" + property string iconSource: "" + property string vendor: "" + property bool hasSettings: false + property alias hasGrip: grip.visible + property bool isSystemApp: false + + signal deleteApp(); + signal configureApp(); + + leadingActions: ListItemActions { + actions: [ + Action { + visible: !root.isSystemApp + iconName: "delete" + onTriggered: { + root.deleteApp(); + } + } + ] + } + + trailingActions: ListItemActions { + actions: [ + Action { + visible: root.hasSettings + iconName: "settings" + onTriggered: { + print("settings triggered") + root.configureApp(); + } + } + ] + } + + RowLayout { + anchors { + fill: parent + margins: units.gu(1) + } + spacing: units.gu(1) + + SystemAppIcon { + Layout.fillHeight: true + Layout.preferredWidth: height + isSystemApp: root.isSystemApp + uuid: root.uuid + iconSource: root.iconSource + } + + ColumnLayout { + Layout.fillWidth: true + Label { + text: root.name + Layout.fillWidth: true + } + + Label { + text: root.vendor + Layout.fillWidth: true + fontSize: "small" + } + } + + Item { + id: grip + Layout.fillHeight: true + Layout.preferredWidth: height + opacity: (root.contentMoving || root.swiped || root.dragging) ? 0 : 1 + Behavior on opacity { UbuntuNumberAnimation {} } + Icon { + width: units.gu(3) + height: width + anchors.centerIn: parent + name: "grip-large" + } + } + } +} diff --git a/rockwork/qml/InstalledAppsPage.qml b/rockwork/qml/InstalledAppsPage.qml new file mode 100644 index 0000000..a18cd3f --- /dev/null +++ b/rockwork/qml/InstalledAppsPage.qml @@ -0,0 +1,201 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import Ubuntu.Components.Popups 1.3 +import RockWork 1.0 + +Page { + id: root + title: showWatchApps ? (showWatchFaces ? i18n.tr("Apps & Watchfaces") : i18n.tr("Apps")) : i18n.tr("Watchfaces") + + property var pebble: null + property bool showWatchApps: false + property bool showWatchFaces: false + + head { + actions: [ + Action { + iconName: "add" + onTriggered: pageStack.push(Qt.resolvedUrl("AppStorePage.qml"), {pebble: root.pebble, showWatchApps: root.showWatchApps, showWatchFaces: root.showWatchFaces}) + } + ] + } + + function configureApp(uuid) { + // The health app is special :/ + if (uuid == "{36d8c6ed-4c83-4fa1-a9e2-8f12dc941f8c}") { + var popup = PopupUtils.open(Qt.resolvedUrl("HealthSettingsDialog.qml"), root, {healthParams: pebble.healthParams}); + popup.accepted.connect(function() { + pebble.healthParams = popup.healthParams + }) + } else { + pebble.requestConfigurationURL(uuid); + } + } + + Item { + anchors.fill: parent + ListView { + id: listView + anchors.fill: parent + model: root.showWatchApps ? root.pebble.installedApps : root.pebble.installedWatchfaces + clip: true + property real realContentY: contentY + originY + + delegate: InstalledAppDelegate { + id: delegate + uuid: model.uuid + name: model.name + iconSource: model.icon + vendor: model.vendor + visible: dndArea.draggedIndex !== index + hasGrip: index > 0 + isSystemApp: model.isSystemApp + hasSettings: model.hasSettings + + onDeleteApp: { + pebble.removeApp(model.uuid) + } + onConfigureApp: { + root.configureApp(model.uuid) + } + onClicked: { + PopupUtils.open(dialogComponent, root, {app: listView.model.get(index)}) + } + } + } + MouseArea { + id: dndArea + anchors { + top: parent.top + bottom: parent.bottom + right: parent.right + } + drag.axis: Drag.YAxis + propagateComposedEvents: true + width: units.gu(5) + + property int startY: 0 + property int draggedIndex: -1 + + + onPressAndHold: { + startY = mouseY; + draggedIndex = Math.floor((listView.realContentY + mouseY) / fakeDragItem.height) + if (draggedIndex == 0) { + print("cannot drag settings app"); + return; + } + + var draggedItem = listView.model.get(draggedIndex); + fakeDragItem.uuid = draggedItem.uuid; + fakeDragItem.name = draggedItem.name; + fakeDragItem.vendor = draggedItem.vendor; + fakeDragItem.iconSource = draggedItem.icon; + fakeDragItem.isSystemApp = draggedItem.isSystemApp; + fakeDragItem.y = (fakeDragItem.height * draggedIndex) - listView.realContentY + drag.target = fakeDragItem; + } + + onMouseYChanged: { + var newIndex = Math.floor((listView.realContentY + mouseY) / fakeDragItem.height) + + if (newIndex > draggedIndex) { + newIndex = draggedIndex + 1; + } else if (newIndex < draggedIndex) { + newIndex = draggedIndex - 1; + } else { + return; + } + + if (newIndex >= 1 && newIndex < listView.count) { + listView.model.move(draggedIndex, newIndex); + draggedIndex = newIndex; + } + } + + onReleased: { + if (draggedIndex > -1) { + listView.model.commitMove(); + draggedIndex = -1; + drag.target = null; + } + } + } + } + + + + InstalledAppDelegate { + id: fakeDragItem + visible: dndArea.draggedIndex != -1 + + } + + Component { + id: dialogComponent + Dialog { + id: dialog + property var app: null + + RowLayout { + SystemAppIcon { + height: titleCol.height + width: height + isSystemApp: app.isSystemApp + uuid: app.uuid + iconSource: app.icon + } + + ColumnLayout { + id: titleCol + Layout.fillWidth: true + + Label { + Layout.fillWidth: true + text: app.name + fontSize: "large" + } + Label { + Layout.fillWidth: true + text: app.vendor + } + } + } + + Button { + text: i18n.tr("Launch") + color: UbuntuColors.green + onClicked: { + pebble.launchApp(app.uuid); + PopupUtils.close(dialog); + } + } + + Button { + text: i18n.tr("Configure") + color: UbuntuColors.blue + visible: app.hasSettings + onClicked: { + root.configureApp(app.uuid); + PopupUtils.close(dialog); + } + } + + Button { + text: i18n.tr("Delete") + color: UbuntuColors.red + visible: !app.isSystemApp + onClicked: { + pebble.removeApp(app.uuid); + PopupUtils.close(dialog); + } + } + + Button { + text: i18n.tr("Close") + onClicked: PopupUtils.close(dialog) + } + } + } +} diff --git a/rockwork/qml/Main.qml b/rockwork/qml/Main.qml new file mode 100644 index 0000000..2bdece3 --- /dev/null +++ b/rockwork/qml/Main.qml @@ -0,0 +1,53 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import RockWork 1.0 + +/*! + \brief MainView with a Label and Button elements. +*/ + +MainView { + applicationName: "rockwork.mzanetti" + + width: units.gu(40) + height: units.gu(70) + + ServiceController { + id: serviceController + serviceName: "rockworkd" + Component.onCompleted: { + if (!serviceController.serviceFileInstalled) { + print("Service file not installed. Installing now.") + serviceController.installServiceFile(); + } + if (!serviceController.serviceRunning) { + print("Service not running. Starting now.") + serviceController.startService(); + } + if (pebbles.version !== version) { + print("Service file version (", version, ") is not equal running service version (", pebbles.version, "). Restarting service.") + serviceController.restartService(); + } + } + } + + Pebbles { + id: pebbles + onCountChanged: loadStack() + } + + function loadStack() { + pageStack.clear() + if (pebbles.count == 1) { + pageStack.push(Qt.resolvedUrl("MainMenuPage.qml"), {pebble: pebbles.get(0)}) + } else { + pageStack.push(Qt.resolvedUrl("PebblesPage.qml")) + } + } + + PageStack { + id: pageStack + Component.onCompleted: loadStack(); + } +} diff --git a/rockwork/qml/MainMenuPage.qml b/rockwork/qml/MainMenuPage.qml new file mode 100644 index 0000000..32c7b96 --- /dev/null +++ b/rockwork/qml/MainMenuPage.qml @@ -0,0 +1,317 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 + +Page { + id: root + title: pebble.name + + property var pebble: null + + head { + actions: [ + Action { + iconName: "info" + text: i18n.tr("About") + onTriggered: { + pageStack.push(Qt.resolvedUrl("InfoPage.qml")) + } + }, + Action { + iconName: "ubuntu-sdk-symbolic" + text: i18n.tr("Developer tools") + onTriggered: { + pageStack.push(Qt.resolvedUrl("DeveloperToolsPage.qml"), {pebble: root.pebble}) + } + } + ] + } + + //Creating the menu list this way to allow the text field to be translatable (http://askubuntu.com/a/476331) + ListModel { + id: mainMenuModel + dynamicRoles: true + } + + Component.onCompleted: { + populateMainMenu(); + } + + Connections { + target: root.pebble + onFirmwareUpgradeAvailableChanged: { + populateMainMenu(); + } + } + + function populateMainMenu() { + mainMenuModel.clear(); + + mainMenuModel.append({ + icon: "stock_notification", + text: i18n.tr("Manage notifications"), + page: "NotificationsPage.qml", + color: "blue" + }); + + mainMenuModel.append({ + icon: "stock_application", + text: i18n.tr("Manage Apps"), + page: "InstalledAppsPage.qml", + showWatchApps: true, + color: UbuntuColors.green + }); + + mainMenuModel.append({ + icon: "clock-app-symbolic", + text: i18n.tr("Manage Watchfaces"), + page: "InstalledAppsPage.qml", + showWatchFaces: true, + color: "black" + }); + + mainMenuModel.append({ + icon: "settings", + text: i18n.tr("Settings"), + page: "SettingsPage.qml", + showWatchFaces: true, + color: "gold" + }); + + if (root.pebble.firmwareUpgradeAvailable) { + mainMenuModel.append({ + icon: "preferences-system-updates-symbolic", + text: i18n.tr("Firmware upgrade"), + page: "FirmwareUpgradePage.qml", + color: "red" + }); + } + + } + + PebbleModels { + id: modelModel + } + + GridLayout { + anchors.fill: parent + columns: parent.width > parent.height ? 2 : 1 + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumHeight: units.gu(30) + + RowLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + spacing: units.gu(1) + + Item { + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: true + Layout.fillWidth: true + Layout.minimumWidth: watchImage.width + Image { + id: watchImage + width: implicitWidth * height / implicitHeight + height: parent.height + anchors.horizontalCenter: parent.horizontalCenter + + source: modelModel.get(root.pebble.model).image + fillMode: Image.PreserveAspectFit + + Item { + id: watchFace + height: parent.height * (modelModel.get(root.pebble.model - 1).shape === "rectangle" ? .5 : .515) + width: height * (modelModel.get(root.pebble.model - 1).shape === "rectangle" ? .85 : 1) + anchors.centerIn: parent + anchors.horizontalCenterOffset: units.dp(1) + anchors.verticalCenterOffset: units.dp(modelModel.get(root.pebble.model - 1).shape === "rectangle" ? 0 : 1) + + Image { + id: image + anchors.fill: parent + source: "file://" + root.pebble.screenshots.latestScreenshot + visible: false + } + + Component.onCompleted: { + if (!root.pebble.screenshots.latestScreenshot) { + root.pebble.requestScreenshot(); + } + } + + Rectangle { + id: textItem + anchors.fill: parent + layer.enabled: true + radius: modelModel.get(root.pebble.model - 1).shape === "rectangle" ? units.gu(.5) : height / 2 + // This item should be used as the 'mask' + layer.samplerName: "maskSource" + layer.effect: ShaderEffect { + property var colorSource: image; + fragmentShader: " + uniform lowp sampler2D colorSource; + uniform lowp sampler2D maskSource; + uniform lowp float qt_Opacity; + varying highp vec2 qt_TexCoord0; + void main() { + gl_FragColor = + texture2D(colorSource, qt_TexCoord0) + * texture2D(maskSource, qt_TexCoord0).a + * qt_Opacity; + } + " + } + } + } + } + } + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + spacing: units.gu(2) + Rectangle { + height: units.gu(10) + width: height + radius: height / 2 + color: root.pebble.connected ? UbuntuColors.green : UbuntuColors.red + + Icon { + anchors.fill: parent + anchors.margins: units.gu(2) + color: "white" + name: root.pebble.connected ? "tick" : "dialog-error-symbolic" + } + } + + Label { + text: root.pebble.connected ? i18n.tr("Connected") : i18n.tr("Disconnected") + Layout.fillWidth: true + } + } + } + } + + + Column { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + spacing: menuRepeater.count > 0 ? 0 : units.gu(2) + Label { + text: i18n.tr("Your Pebble smartwatch is disconnected. Please make sure it is powered on, within range and it is paired properly in the Bluetooth System Settings.") + width: parent.width - units.gu(4) + anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Text.WordWrap + visible: !root.pebble.connected + fontSize: "large" + horizontalAlignment: Text.AlignHCenter + } + + Button { + text: i18n.tr("Open System Settings") + visible: !root.pebble.connected + onClicked: Qt.openUrlExternally("settings://system/bluetooth") + color: UbuntuColors.orange + anchors.horizontalCenter: parent.horizontalCenter + } + + Label { + text: i18n.tr("Your Pebble smartwatch is in factory mode and needs to be initialized.") + width: parent.width - units.gu(4) + anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Text.WordWrap + visible: root.pebble.connected && root.pebble.recovery && !root.pebble.upgradingFirmware + fontSize: "large" + horizontalAlignment: Text.AlignHCenter + } + Button { + text: i18n.tr("Initialize Pebble") + onClicked: root.pebble.performFirmwareUpgrade(); + visible: root.pebble.connected && root.pebble.recovery && !root.pebble.upgradingFirmware + color: UbuntuColors.orange + anchors.horizontalCenter: parent.horizontalCenter + } + + Rectangle { + id: upgradeIcon + height: units.gu(10) + width: height + radius: width / 2 + color: UbuntuColors.orange + anchors.horizontalCenter: parent.horizontalCenter + Icon { + anchors.fill: parent + anchors.margins: units.gu(1) + name: "preferences-system-updates-symbolic" + color: "white" + } + + RotationAnimation on rotation { + duration: 2000 + loops: Animation.Infinite + from: 0 + to: 360 + running: upgradeIcon.visible + } + visible: root.pebble.connected && root.pebble.upgradingFirmware + } + + Label { + text: i18n.tr("Upgrading...") + fontSize: "large" + anchors.horizontalCenter: parent.horizontalCenter + visible: root.pebble.connected && root.pebble.upgradingFirmware + } + + Repeater { + id: menuRepeater + model: root.pebble.connected && !root.pebble.recovery && !root.pebble.upgradingFirmware ? mainMenuModel : null + delegate: ListItem { + + RowLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + + UbuntuShape { + Layout.fillHeight: true + Layout.preferredWidth: height + backgroundColor: model.color + Icon { + anchors.fill: parent + anchors.margins: units.gu(.5) + name: model.icon + color: "white" + } + } + + + Label { + text: model.text + Layout.fillWidth: true + } + } + + onClicked: { + var options = {}; + options["pebble"] = root.pebble + var modelItem = mainMenuModel.get(index) + options["showWatchApps"] = modelItem.showWatchApps + options["showWatchFaces"] = modelItem.showWatchFaces + pageStack.push(Qt.resolvedUrl(model.page), options) + } + } + } + } + } + + Connections { + target: pebble + onOpenURL: { + if (url) { + pageStack.push(Qt.resolvedUrl("AppSettingsPage.qml"), {uuid: uuid, url: url, pebble: pebble}) + } + } + } +} diff --git a/rockwork/qml/NotificationsPage.qml b/rockwork/qml/NotificationsPage.qml new file mode 100644 index 0000000..9802b05 --- /dev/null +++ b/rockwork/qml/NotificationsPage.qml @@ -0,0 +1,88 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import RockWork 1.0 + +Page { + id: root + title: i18n.tr("Notifications") + + property var pebble: null + + ColumnLayout { + anchors.fill: parent + anchors.topMargin: units.gu(1) + + Item { + Layout.fillWidth: true + implicitHeight: infoLabel.height + + Label { + id: infoLabel + anchors { + left: parent.left + right: parent.right + margins: units.gu(2) + } + + wrapMode: Text.WordWrap + text: i18n.tr("Entries here will be added as notifications appear on the phone. Selected notifications will be shown on your Pebble smartwatch.") + } + } + + + ListView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + model: root.pebble.notifications + + delegate: ListItem { + ListItemLayout { + title.text: model.name + + UbuntuShape { + SlotsLayout.position: SlotsLayout.Leading; + height: units.gu(5) + width: height + backgroundColor: { + // Add some hacks for known icons + switch (model.icon) { + case "calendar": + return UbuntuColors.orange; + case "settings": + return "grey"; + case "dialog-question-symbolic": + return UbuntuColors.red; + case "alarm-clock": + return UbuntuColors.purple; + case "gpm-battery-050": + return UbuntuColors.green; + } + return "black" + } + source: Image { + height: parent.height + width: parent.width + source: model.icon.indexOf("/") === 0 ? "file://" + model.icon : "" + } + Icon { + anchors.fill: parent + anchors.margins: units.gu(.5) + name: model.icon.indexOf("/") !== 0 ? model.icon : "" + color: "white" + } + } + + Switch { + checked: model.enabled + SlotsLayout.position: SlotsLayout.Trailing; + onClicked: { + root.pebble.setNotificationFilter(model.name, checked) + } + } + } + } + } + } +} diff --git a/rockwork/qml/PebbleModels.qml b/rockwork/qml/PebbleModels.qml new file mode 100644 index 0000000..103064a --- /dev/null +++ b/rockwork/qml/PebbleModels.qml @@ -0,0 +1,28 @@ +import QtQuick 2.4 + +ListModel { + id: modelModel + ListElement { image: 'artwork/tintin-black.png'; shape: "rectangle" } // Fallback for Unknown + ListElement { image: 'artwork/tintin-black.png'; shape: "rectangle" } + ListElement { image: 'artwork/tintin-white.png'; shape: "rectangle" } + ListElement { image: 'artwork/tintin-red.png'; shape: "rectangle" } + ListElement { image: 'artwork/tintin-orange.png'; shape: "rectangle" } + ListElement { image: 'artwork/tintin-grey.png'; shape: "rectangle" } + ListElement { image: 'artwork/bianca-silver.png'; shape: "rectangle" } + ListElement { image: 'artwork/bianca-black.png'; shape: "rectangle" } + ListElement { image: 'artwork/tintin-blue.png'; shape: "rectangle" } + ListElement { image: 'artwork/tintin-green.png'; shape: "rectangle" } + ListElement { image: 'artwork/tintin-pink.png'; shape: "rectangle" } + ListElement { image: 'artwork/snowy-white.png'; shape: "rectangle" } + ListElement { image: 'artwork/snowy-black.png'; shape: "rectangle" } + ListElement { image: 'artwork/snowy-red.png'; shape: "rectangle" } + ListElement { image: 'artwork/bobby-silver.png'; shape: "rectangle" } + ListElement { image: 'artwork/bobby-black.png'; shape: "rectangle" } + ListElement { image: 'artwork/bobby-gold.png'; shape: "rectangle" } + ListElement { image: 'artwork/spalding-14mm-silver.png'; shape: "round" } + ListElement { image: 'artwork/spalding-14mm-black.png'; shape: "round" } + ListElement { image: 'artwork/spalding-20mm-silver.png'; shape: "round" } + ListElement { image: 'artwork/spalding-20mm-black.png'; shape: "round" } + ListElement { image: 'artwork/spalding-14mm-rose-gold.png'; shape: "round" } +} + diff --git a/rockwork/qml/PebblesPage.qml b/rockwork/qml/PebblesPage.qml new file mode 100644 index 0000000..a973b0a --- /dev/null +++ b/rockwork/qml/PebblesPage.qml @@ -0,0 +1,69 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 + +Page { + title: i18n.tr("Manage Pebble Watches") + + head { + actions: [ + Action { + iconName: "settings" + onTriggered: { + onClicked: Qt.openUrlExternally("settings://system/bluetooth") + } + } + ] + } + + ListView { + anchors.fill: parent + model: pebbles + delegate: ListItem { + RowLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + + ColumnLayout { + Layout.fillHeight: true + Layout.fillWidth: true + + Label { + text: model.name + } + + Label { + text: model.connected ? i18n.tr("Connected") : i18n.tr("Disconnected") + fontSize: "small" + } + } + } + + onClicked: { + var p = pebbles.get(index); + print("opening pebble:", p.name, p.hardwarePlatform) + pageStack.push(Qt.resolvedUrl("MainMenuPage.qml"), {pebble: pebbles.get(index)}) + } + } + } + + Column { + anchors.centerIn: parent + width: parent.width - units.gu(4) + spacing: units.gu(4) + visible: pebbles.count === 0 + + Label { + text: i18n.tr("No Pebble smartwatches configured yet. Please connect your Pebble smartwatch using System Settings.") + fontSize: "large" + width: parent.width + wrapMode: Text.WordWrap + } + + Button { + text: i18n.tr("Open System Settings") + anchors.horizontalCenter: parent.horizontalCenter + onClicked: Qt.openUrlExternally("settings://system/bluetooth") + } + } +} diff --git a/rockwork/qml/ScreenshotsPage.qml b/rockwork/qml/ScreenshotsPage.qml new file mode 100644 index 0000000..fdbeb9a --- /dev/null +++ b/rockwork/qml/ScreenshotsPage.qml @@ -0,0 +1,107 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import Ubuntu.Components.Popups 1.3 +import Ubuntu.Content 1.3 +import RockWork 1.0 + +Page { + id: root + + title: i18n.tr("Screenshots") + + property var pebble: null + + head { + actions: [ + Action { + iconName: "camera-app-symbolic" + onTriggered: root.pebble.requestScreenshot() + } + ] + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + spacing: units.gu(1) + + GridView { + id: grid + Layout.fillHeight: true + Layout.fillWidth: true + clip: true + + property int columns: 2 + + cellWidth: width / columns + cellHeight: cellWidth + + model: root.pebble.screenshots + + displaced: Transition { + UbuntuNumberAnimation { properties: "x,y" } + } + + delegate: Item { + width: grid.cellWidth + height: grid.cellHeight + Image { + anchors.fill: parent + anchors.margins: units.gu(.5) + fillMode: Image.PreserveAspectFit + source: "file://" + model.filename + } + MouseArea { + anchors.fill: parent + onClicked: { + PopupUtils.open(dialogComponent, root, {filename: model.filename}) + } + } + } + } + } + + Component { + id: dialogComponent + Dialog { + id: dialog + title: i18n.tr("Screenshot options") + + property string filename + + Button { + text: i18n.tr("Share") + color: UbuntuColors.blue + onClicked: { + pageStack.push(Qt.resolvedUrl("ContentPeerPickerPage.qml"), {itemName: i18n.tr("Pebble screenshot"), handler: ContentHandler.Share, contentType: ContentType.Pictures, filename: filename }) + PopupUtils.close(dialog) + } + } + Button { + text: i18n.tr("Save") + color: UbuntuColors.green + onClicked: { + pageStack.push(Qt.resolvedUrl("ContentPeerPickerPage.qml"), {itemName: i18n.tr("Pebble screenshot"),handler: ContentHandler.Destination, contentType: ContentType.Pictures, filename: filename }) + PopupUtils.close(dialog) + } + } + + Button { + text: i18n.tr("Delete") + color: UbuntuColors.red + onClicked: { + root.pebble.removeScreenshot(filename) + PopupUtils.close(dialog) + } + } + Button { + text: i18n.tr("Cancel") + onClicked: { + PopupUtils.close(dialog) + } + } + } + } +} + diff --git a/rockwork/qml/SettingsPage.qml b/rockwork/qml/SettingsPage.qml new file mode 100644 index 0000000..153aaf4 --- /dev/null +++ b/rockwork/qml/SettingsPage.qml @@ -0,0 +1,80 @@ +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import Ubuntu.Components 1.3 +import Ubuntu.Components.ListItems 1.3 + +Page { + id: root + title: i18n.tr("Settings") + + property var pebble: null + + ColumnLayout { + anchors.fill: parent + anchors.margins: units.gu(1) + spacing: units.gu(1) + + Label { + Layout.fillWidth: true + text: i18n.tr("Distance Units") + font.bold: true + } + + RowLayout { + Layout.fillWidth: true + CheckBox { + id: metricUnitsCheckbox + checked: !root.pebble.imperialUnits + onClicked: { + checked = true + root.pebble.imperialUnits = false; + imperialUnitsCheckBox.checked = false; + } + } + Label { + text: i18n.tr("Metric") + Layout.fillWidth: true + } + CheckBox { + id: imperialUnitsCheckBox + checked: root.pebble.imperialUnits + onClicked: { + checked = true + root.pebble.imperialUnits = true; + metricUnitsCheckbox.checked = false; + } + } + Label { + text: i18n.tr("Imperial") + Layout.fillWidth: true + } + } + ThinDivider {} + + Label { + text: i18n.tr("Calendar") + Layout.fillWidth: true + font.bold: true + } + RowLayout { + Layout.fillWidth: true + Label { + text: i18n.tr("Sync calendar to timeline") + Layout.fillWidth: true + } + Switch { + checked: root.pebble.calendarSyncEnabled + onClicked: { + root.pebble.calendarSyncEnabled = checked; + } + } + } + ThinDivider {} + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } + } +} + diff --git a/rockwork/qml/SystemAppIcon.qml b/rockwork/qml/SystemAppIcon.qml new file mode 100644 index 0000000..88e37bc --- /dev/null +++ b/rockwork/qml/SystemAppIcon.qml @@ -0,0 +1,67 @@ +import QtQuick 2.4 +import Ubuntu.Components 1.3 + +Item { + id: root + + property bool isSystemApp: false + property string uuid: "" + property string iconSource: "" + + UbuntuShape { + anchors.fill: parent + visible: root.isSystemApp + backgroundColor: { + switch (root.uuid) { + case "{07e0d9cb-8957-4bf7-9d42-35bf47caadfe}": + return "gray"; + case "{18e443ce-38fd-47c8-84d5-6d0c775fbe55}": + return "blue"; + case "{36d8c6ed-4c83-4fa1-a9e2-8f12dc941f8c}": + return UbuntuColors.red; + case "{1f03293d-47af-4f28-b960-f2b02a6dd757}": + return "gold" + case "{b2cae818-10f8-46df-ad2b-98ad2254a3c1}": + return "darkviolet" + case "{67a32d95-ef69-46d4-a0b9-854cc62f97f9}": + return "green"; + case "{8f3c8686-31a1-4f5f-91f5-01600c9bdc59}": + return "black" + } + + return ""; + } + } + Icon { + anchors.fill: parent + implicitHeight: height + anchors.margins: units.gu(1) + visible: root.isSystemApp + color: "white" + name: { + switch (root.uuid) { + case "{07e0d9cb-8957-4bf7-9d42-35bf47caadfe}": + return "settings"; + case "{18e443ce-38fd-47c8-84d5-6d0c775fbe55}": + return "clock-app-symbolic"; + case "{36d8c6ed-4c83-4fa1-a9e2-8f12dc941f8c}": + return "like"; + case "{1f03293d-47af-4f28-b960-f2b02a6dd757}": + return "stock_music"; + case "{b2cae818-10f8-46df-ad2b-98ad2254a3c1}": + return "stock_notification"; + case "{67a32d95-ef69-46d4-a0b9-854cc62f97f9}": + return "stock_alarm-clock"; + case "{8f3c8686-31a1-4f5f-91f5-01600c9bdc59}": + return "clock-app-symbolic"; + } + return ""; + } + } + + Image { + source: root.isSystemApp ? "" : "file://" + root.iconSource; + anchors.fill: parent + visible: !root.isSystemApp + } +} -- cgit v1.2.3