Commit ddf4bea6 authored by Aleksi Suomalainen's avatar Aleksi Suomalainen Committed by GitHub

Merge pull request #57 from eekkelund/applauncher_improvements

Applauncher improvements
parents d609775b 11fc86e5
*.pro.user
*.pyc
.directory
*.o
*.so
*.qmlc
moc_*
qrc_*
.qmake.stash
*.spec.*
documentation.list
examples/touch/glacier-components
Makefile
installroot/
RPMS/
debug*.list
...@@ -21,8 +21,9 @@ ...@@ -21,8 +21,9 @@
// //
// Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk> // Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk>
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org> // Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2017, Eetu Kahelin
import QtQuick 2.0 import QtQuick 2.6
import org.nemomobile.lipstick 0.1 import org.nemomobile.lipstick 0.1
import QtQuick.Controls.Nemo 1.0 import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0 import QtQuick.Controls.Styles.Nemo 1.0
...@@ -30,70 +31,270 @@ import QtQuick.Controls.Styles.Nemo 1.0 ...@@ -30,70 +31,270 @@ import QtQuick.Controls.Styles.Nemo 1.0
// App Launcher page // App Launcher page
// the place for browsing installed applications and launching them // the place for browsing installed applications and launching them
GridView { GridView {
id: gridview id: gridview
cellWidth: Math.min(parent.width,parent.height)/4 cellWidth: cellSize
cellHeight: cellWidth + 30 cellHeight: cellSize
width: parent.width width: parent.width
cacheBuffer: gridview.contentHeight cacheBuffer: gridview.contentHeight
property Item reorderItem property Item reorderItem
property bool onUninstall property bool onUninstall
property alias deleter: deleter property alias deleter: deleter
property var switcher: null property var switcher: null
property string searchString
property int cellSize: Math.min(parent.width,parent.height)/4
property int folderIndex: -1
property bool isRootFolder:true
property bool newFolderActive
property bool newFolder: newFolderActive && isRootFolder && folderIndex >= 0
clip: true
// just for margin purposes onContentYChanged: {
header: Item { if( contentY < -140 ) {
height: Math.min(parent.width,parent.height)/10 headerItem.visible = true;
timer.running = true;
}
}
onSearchStringChanged: timer.restart()
Timer{
id: timer; running: false; interval: 7000; repeat: true
onTriggered: {
if(searchString.length < 1 ) headerItem.visible = false
}
}
Connections {
target: headerItem
onHeightChanged:{
if(headerItem.oldHeight < headerItem.height)
if(!flicking) gridview.contentY = headerItem.y
headerItem.oldHeight = headerItem.height
}
onVisibleChanged:timer.restart()
}
Connections {
target: Lipstick.compositor
onDisplayOff: {
headerItem.searchField.text = ""
headerItem.visible = false
}
onWindowAdded: {
if(window.category=="" && window.title !== "Home"){
headerItem.searchField.text = ""
headerItem.visible = false
}
}
onWindowRaised: {
if(window.category=="" && window.title !== "Home"){
headerItem.searchField.text = ""
headerItem.visible = false
}
} }
}
Connections {
target: pager
onFlickEnded: {
headerItem.searchField.text = ""
headerItem.visible = false
}
}
Connections {
target: lockScreen
onVisibleChanged: {
if(lockscreenVisible()) {
headerItem.searchField.text = ""
headerItem.visible = false
}
}
}
header: SearchListView {
width: gridview.width
}
footer: Item { footer: Item {
height: Math.min(parent.width,parent.height)/10 height: Theme.itemHeightLarge*1.5
} }
Item { Item {//Doesn't yet uninstall applications
id: deleter id: deleter
anchors.top: parent.top anchors.top: parent.top
property alias remove: remove property alias remove: remove
property alias uninstall: uninstall property alias uninstall: uninstall
Rectangle { function uninstalling(action, caption) {
state = action
if (action==="remove") {
remove.text = qsTr("Removing") + " " + caption
} else if (action == "uninstall") {
uninstall.text = qsTr("Uninstalling") + " " + caption
}
}
states: [
State {
name: "remove"
PropertyChanges {
target: remove
color1: "#D9ff0000"
color2: "#D9ff0000"
color3: "#D9ff0000"
}
PropertyChanges {
target: uninstall
color1: "#D9ff0000"
color2: "#80ff0000"
color3: "#4Dff0000"
}
PropertyChanges {
target: uninstall
text: qsTr("Uninstall")
}
},
State {
name: "uninstall"
PropertyChanges {
target: uninstall
color1: "#D9ff0000"
color2: "#D9ff0000"
color3: "#D9ff0000"
}
PropertyChanges {
target: remove
color1: "#D9ff0000"
color2: "#80ff0000"
color3: "#4Dff0000"
}
PropertyChanges {
target: remove
text: qsTr("Remove")
}
},
State {
name:"basic"
PropertyChanges {
target: remove
color1: "#D9ff0000"
color2: "#80ff0000"
color3: "#4Dff0000"
}
PropertyChanges {
target: remove
text: qsTr("Remove")
}
PropertyChanges {
target: uninstall
color1: "#D9ff0000"
color2: "#80ff0000"
color3: "#4Dff0000"
}
PropertyChanges {
target: uninstall
text: qsTr("Uninstall")
}
}
]
Rectangle {//WHY?
id: remove id: remove
property color color1: "#D9ff0000"
property color color2: "#80ff0000"
property color color3: "#4Dff0000"
property alias text: removeLabel.text property alias text: removeLabel.text
visible: onUninstall visible: gridview.onUninstall
height: 110 height: Theme.itemHeightExtraLarge
color: "red"
width: gridview.width / 2 width: gridview.width / 2
gradient: Gradient {
GradientStop { position: 0.0; color: remove.color1 }
GradientStop { position: 0.5; color: remove.color2 }
GradientStop { position: 1.0; color: remove.color3 }
}
Label { Label {
id: removeLabel id: removeLabel
height: parent.height
width: parent.width
anchors.centerIn: parent anchors.centerIn: parent
text: qsTr("Remove") text: qsTr("Remove")
font.pointSize: 8 font.pixelSize: Theme.fontSizeLarge
elide:Text.ElideRight
horizontalAlignment:Text.AlignHCenter
verticalAlignment:Text.AlignVCenter
} }
} }
Rectangle { Rectangle {
id: uninstall id: uninstall
property color color1: "#D9ff0000"
property color color2: "#80ff0000"
property color color3: "#4Dff0000"
property alias text: uninstallLabel.text property alias text: uninstallLabel.text
anchors.left: remove.right anchors.left: remove.right
visible: onUninstall visible: gridview.onUninstall
color: "red"
width: gridview.width / 2 width: gridview.width / 2
height: 110 height: Theme.itemHeightExtraLarge
gradient: Gradient {
GradientStop { position: 0.0; color: uninstall.color1 }
GradientStop { position: 0.5; color: uninstall.color2 }
GradientStop { position: 1.0; color: uninstall.color3 }
}
Label { Label {
id: uninstallLabel id: uninstallLabel
height: parent.height
width: parent.width
anchors.centerIn: parent anchors.centerIn: parent
text: qsTr("Uninstall") text: qsTr("Uninstall")
font.pointSize: 8 font.pixelSize: Theme.fontSizeLarge
elide:Text.ElideRight
horizontalAlignment:Text.AlignHCenter
verticalAlignment:Text.AlignVCenter
} }
} }
} }
onFolderIndexChanged: if (folderIndex == -1) newFolderActive = false
model: LauncherFolderModel { id: launcherModel } model: LauncherFolderModel { id: launcherModel }
//Using loader that in the future we can also have widgets as delegate
delegate: Loader {
id:loader
width: cellSize
height: cellSize
onXChanged: item.x = x
onYChanged: item.y = y
property QtObject modelData : model
property int cellSize: gridview.cellHeight
property int cellIndex: index
sourceComponent: object.type == LauncherModel.Folder ? folder : app
}
delegate: LauncherItemDelegate { Component {
id:app
LauncherItemDelegate {
id: launcherItem id: launcherItem
width: gridview.cellWidth parent: gridview
height: gridview.cellHeight parentItem: gridview
iconCaption: model.object.title iconCaption.color:Theme.textColor
isFolder: model.object.type == LauncherModel.Folder iconCaption.text: modelData.object.title
folderAppsCount: isFolder && model.object ? model.object.itemCount : 0 isFolder: modelData.object.type == LauncherModel.Folder
source: model.object.iconId == "" || isFolder ? "/usr/share/lipstick-glacier-home-qt5/qml/theme/default-icon.png" : (model.object.iconId.indexOf("/") == 0 ? "file://" : "image://theme/") + model.object.iconId source: modelData.object.iconId == "" ? "/usr/share/lipstick-glacier-home-qt5/qml/theme/default-icon.png" : (modelData.object.iconId.indexOf("/") == 0 ? "file://" : "image://theme/") + modelData.object.iconId
notNemoIcon: isFolder || modelData.object.iconId == "" ? false : modelData.object.iconId.indexOf("harbour") > -1 || modelData.object.iconId.indexOf("apkd_launcher") > -1 ? true : false
folderModel:launcherModel
}
}
Component {
id:folder
LauncherItemFolder {
id: launcherfolder
parent: gridview
iconCaption.color:Theme.textColor
iconCaption.text: modelData.object.title
isFolder: modelData.object.type == LauncherModel.Folder
folderAppsCount: isFolder && modelData.object ? modelData.object.itemCount : 0
notNemoIcon: isFolder || modelData.object.iconId == "" ? false : modelData.object.iconId.indexOf("harbour") > -1 || modelData.object.iconId.indexOf("apkd_launcher") > -1 ? true : false
folderModel:launcherModel
}
} }
} }
...@@ -22,8 +22,9 @@ ...@@ -22,8 +22,9 @@
// Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk> // Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk>
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org> // Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
import QtQuick 2.2 import QtQuick 2.6
import org.nemomobile.lipstick 0.1 import org.nemomobile.lipstick 0.1
import QtQuick.Controls 1.0
import QtQuick.Controls.Nemo 1.0 import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0 import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.glacier 1.0 import org.nemomobile.glacier 1.0
...@@ -33,7 +34,6 @@ import org.nemomobile.glacier 1.0 ...@@ -33,7 +34,6 @@ import org.nemomobile.glacier 1.0
Item { Item {
id: switcherRoot id: switcherRoot
property bool closeMode: false property bool closeMode: false
property bool visibleInHome: false property bool visibleInHome: false
property alias runningAppsCount: switcherModel.itemCount property alias runningAppsCount: switcherModel.itemCount
...@@ -46,12 +46,34 @@ Item { ...@@ -46,12 +46,34 @@ Item {
closeMode = false; closeMode = false;
} }
} }
// Empty switcher indicator
Rectangle {
id: topText
visible: switcherModel.itemCount === 0
width: noAppsLabel.width
height: Theme.itemHeightMedium
anchors {
top: parent.top
topMargin:Theme.itemSpacingLarge
horizontalCenter: parent.horizontalCenter
}
color: "transparent"
Label {
id: noAppsLabel
text: qsTr("No apps open")
anchors {
top: parent.top
left: parent.left
}
font.weight: Font.Light
font.pixelSize: Theme.fontSizeExtraLarge
}
}
Flickable { Flickable {
id: flickable id: flickable
contentHeight: gridview.height contentHeight: gridview.height
width: closeMode ? parent.width - 20 : parent.width // see comment re right anchor below width: closeMode ? parent.width - 20 : parent.width // see comment re right anchor below
MouseArea { MouseArea {
height: flickable.contentHeight > flickable.height ? flickable.contentHeight : flickable.height height: flickable.contentHeight > flickable.height ? flickable.contentHeight : flickable.height
width: flickable.width width: flickable.width
...@@ -181,12 +203,4 @@ Item { ...@@ -181,12 +203,4 @@ Item {
} }
} }
} }
// Empty switcher indicator
Label {
visible: switcherModel.itemCount === 0
text: qsTr("No apps open")
width: parent.width
fontSizeMode: Text.HorizontalFit
}
} }
...@@ -7,6 +7,8 @@ import QtQuick.Layouts 1.0 ...@@ -7,6 +7,8 @@ import QtQuick.Layouts 1.0
import org.nemomobile.lipstick 0.1 import org.nemomobile.lipstick 0.1
import org.nemomobile.devicelock 1.0 import org.nemomobile.devicelock 1.0
import "scripts/desktop.js" as Desktop
Item { Item {
id: root id: root
...@@ -39,6 +41,8 @@ Item { ...@@ -39,6 +41,8 @@ Item {
id: authenticator id: authenticator
onAuthenticated: { onAuthenticated: {
DeviceLock.unlock(authenticationToken) DeviceLock.unlock(authenticationToken)
Desktop.instance.setLockScreen(false)
Desktop.instance.codepadVisible = false
} }
onFeedback: { onFeedback: {
console.log('### still locked', feedback, attemptsRemaining) console.log('### still locked', feedback, attemptsRemaining)
...@@ -47,34 +51,46 @@ Item { ...@@ -47,34 +51,46 @@ Item {
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: 40 spacing: Theme.itemSpacingLarge
TextField { TextField {
id: lockCodeField id: lockCodeField
anchors.horizontalCenter: parent.horizontalCenter
readOnly: true readOnly: true
echoMode: TextInput.PasswordEchoOnEdit echoMode: TextInput.PasswordEchoOnEdit
anchors.horizontalCenter: parent.horizontalCenter font.pixelSize: Theme.fontSizeExtraLarge
} }
GridLayout { GridLayout {
height: parent.height height: parent.height
width: parent.width width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
columns: 3 columns: 3
Repeater { Repeater {
model: ["1","2","3","4","5","6","7","8","9","Ca","0","OK"] model: ["1","2","3","4","5","6","7","8","9","Ca","0","OK"]
delegate: delegate:
Button { Button {
style: ButtonStyle {} height: Theme.itemHeightHuge
Layout.fillWidth: true width: Theme.itemHeightHuge
Layout.maximumWidth: Theme.itemHeightHuge * 1.5
Layout.maximumHeight: Theme.itemHeightHuge * 1.5
Label {
id: btnLabel
text: modelData text: modelData
font.pixelSize: Theme.fontSizeExtraLarge * 1.5
anchors {
centerIn: parent
}
}
onClicked: { onClicked: {
if (text !== "Ca" && text !== "OK") { if (btnLabel.text !== "Ca" && btnLabel.text !== "OK") {
lockCodeField.insert(lockCodeField.cursorPosition, text) lockCodeField.insert(lockCodeField.cursorPosition, btnLabel.text)
} else { } else {
if (text === "OK") { if (btnLabel.text === "OK") {
authenticator.enterLockCode(lockCodeField.text) authenticator.enterLockCode(lockCodeField.text)
lockCodeField.text = "" lockCodeField.text = ""
} else if (text === "Ca"){ } else if (btnLabel.text === "Ca"){
lockCodeField.text = "" lockCodeField.text = ""
} }
} }
......
...@@ -33,7 +33,7 @@ import "notifications" ...@@ -33,7 +33,7 @@ import "notifications"
Flickable { Flickable {
id: mainFlickable id: mainFlickable
clip: true
contentHeight: rootitem.height contentHeight: rootitem.height
contentWidth: parent.width contentWidth: parent.width
Item { Item {
...@@ -43,26 +43,27 @@ Flickable { ...@@ -43,26 +43,27 @@ Flickable {
// Day of week // Day of week
Rectangle { Rectangle {
id: daterow id: daterow
height: displayCurrentDate.height + 15 height: Theme.itemHeightMedium
width: childrenRect.width width: parent.width
anchors{ anchors{
top: parent.top top: parent.top
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
topMargin: Theme.itemSpacingLarge
bottomMargin: Theme.itemSpacingLarge
} }
color: "transparent" color: "transparent"
Label { Label {
id: displayDayOfWeek id: displayDayOfWeek
text: Qt.formatDateTime(wallClock.time, "dddd") + ", " text: Qt.formatDateTime(wallClock.time, "dddd")
color: "white" color: Theme.textColor
font.pointSize: 12 font.pixelSize: Theme.fontSizeExtraLarge
font.bold: true font.weight: Font.Bold
anchors { anchors {
top: parent.top top: parent.top
left: parent.left horizontalCenter: parent.horizontalCenter
topMargin: 30
} }
} }
...@@ -70,12 +71,13 @@ Flickable { ...@@ -70,12 +71,13 @@ Flickable {
Label { Label {
id: displayCurrentDate id: displayCurrentDate
text: Qt.formatDate(wallClock.time, "d MMMM yyyy") text: Qt.formatDate(wallClock.time, "d MMMM yyyy")
font.pointSize: 12 font.pixelSize: Theme.fontSizeExtraLarge
color: Theme.textColor
font.weight: Font.Light
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
anchors { anchors {
left: displayDayOfWeek.right horizontalCenter: parent.horizontalCenter
top: parent.top top: displayDayOfWeek.bottom
topMargin: 30
} }
} }
} }
...@@ -85,9 +87,9 @@ Flickable { ...@@ -85,9 +87,9 @@ Flickable {
width: parent.width width: parent.width
anchors{ anchors{
top: daterow.bottom top: daterow.bottom
topMargin: 50 topMargin: Theme.itemSpacingHuge
} }
spacing: 10 spacing: Theme.itemSpacingHuge
Repeater { Repeater {
model: NotificationListModel { model: NotificationListModel {
id: notifmodel id: notifmodel
......
...@@ -19,11 +19,12 @@ ...@@ -19,11 +19,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
// //
// Copyright (c) 2017, Eetu Kahelin
// Copyright (c) 2013, Jolla Ltd <robin.burchell@jollamobile.com> // Copyright (c) 2013, Jolla Ltd <robin.burchell@jollamobile.com>
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org> // Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk> // Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk>
import QtQuick 2.0 import QtQuick 2.6
import QtQuick.Controls.Nemo 1.0 import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0 import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.lipstick 0.1 import org.nemomobile.lipstick 0.1
...@@ -31,15 +32,17 @@ import org.nemomobile.lipstick 0.1 ...@@ -31,15 +32,17 @@ import org.nemomobile.lipstick 0.1
Item { Item {
id: wrapper id: wrapper
property alias source: iconImage.source property alias source: iconImage.source
property alias iconCaption: iconText.text property alias iconCaption: iconText
property bool reordering property bool reordering: launcherItem.reordering
property int newIndex: -1
property real oldY
property bool isFolder property bool isFolder
property int folderAppsCount: 0 //Sailfish and other app icons are larger than nemo icons. Thats why this property could be used to scale them
property bool notNemoIcon
property alias parentItem: launcherItem.parentItem
property alias folderModel:launcherItem.folderModel
onXChanged: moveTimer.start() onXChanged: moveTimer.start()
onYChanged: moveTimer.start() onYChanged: moveTimer.start()
clip: true
Timer { Timer {
id: moveTimer id: moveTimer
...@@ -49,230 +52,80 @@ Item { ...@@ -49,230 +52,80 @@ Item {
function moveIcon() { function moveIcon() {
if (!reordering) { if (!reordering) {
if (!slideMoveAnim.running) { if (!launcherItem.slideMoveAnim.running) {
slideMoveAnim.start() launcherItem.slideMoveAnim.start()
} }
} }
} }
GridView {
id: folderLoader
parent: gridview.contentItem
y: wrapper.y + wrapper.height
x: 0
z: wrapper.z + 100
width: gridview.width
height: childrenRect.height
cellWidth: gridview.cellWidth
cellHeight: cellWidth + 30
visible: false
Rectangle {
anchors.fill: parent
opacity: 0.75
color: "white"
z: -1
}
delegate: MouseArea {
width: gridview.cellWidth
height: gridview.cellHeight
Image {
id: iconimage
source: model.object.iconId
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 8
}
width: gridview.cellWidth - gridview.cellWidth/10
height: width
asynchronous: true
Spinner {
id: spinner
anchors.centerIn: parent
enabled: (model.object.type === LauncherModel.Application) ? model.object.isLaunching : false
}
}
Text {
id: icontext
// elide only works if an explicit width is set
width: parent.width
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
font.pixelSize: gridview.cellWidth/10
color: 'black'
anchors {
left: parent.left
right: parent.right
top: iconimage.bottom
topMargin: 5
}
text: model.object.title
}
onClicked: {
model.object.launchApplication()
}
}
}
// Application icon for the launcher // Application icon for the launcher
MouseArea { LauncherItemWrapper {
id: launcherItem id: launcherItem
width: wrapper.width width: wrapper.width
height: wrapper.height height: wrapper.height
parent: gridview.contentItem isFolder: wrapper.isFolder
scale: reordering ? 1.3 : 1 notNemoIcon: wrapper.notNemoIcon
transformOrigin: Item.Center
onXChanged: moved()
onYChanged: moved()
onClicked: {
// TODO: disallow if close mode enabled
if (model.object.type !== LauncherModel.Folder) {
var winId = switcher.switchModel.getWindowIdForTitle(model.object.title)
console.log("Window id found: " + winId)
if (winId == 0)
model.object.launchApplication()
else
Lipstick.compositor.windowToFront(winId)
} else {
if (!folderLoader.visible) {
folderLoader.visible = true
folderLoader.model = model.object
} else {
folderLoader.visible = false
}
}
}
onPressAndHold: {
reparent(gridview)
reorderItem = launcherItem
drag.target = launcherItem
z = 1000
reordering = true
gridview.onUninstall = true
// don't allow dragging an icon out of pages with a horizontal flick
pager.interactive = false
}
onReleased: {
if (reordering) {
reordering = false
reorderTimer.stop()
drag.target = null
reorderItem = null
pager.interactive = true
gridview.onUninstall = false
deleter.remove.text = qsTr("Remove")
deleter.uninstall.text = qsTr("Uninstall")
reparent(gridview.contentItem)
slideMoveAnim.start()
}
}
function reparent(newParent) {
var newPos = mapToItem(newParent, 0, 0)
parent = newParent
x = newPos.x - width/2 * (1-scale)
y = newPos.y - height/2 * (1-scale)
}
function moved() {
if (reordering) {
var gridViewPos = gridview.contentItem.mapFromItem(launcherItem, width/2, height/2)
var idx = gridview.indexAt(gridViewPos.x, gridViewPos.y)
var delPos = deleter.remove.mapFromItem(launcherItem, width/2, height/2)
var isdel = deleter.childAt(delPos.x, delPos.y)
if (isdel === deleter.remove) {
deleter.remove.text = qsTr("Removing") + " " + iconCaption
} else if (isdel === deleter.uninstall) {
deleter.uninstall.text = qsTr("Uninstalling") + " " + iconCaption
}
if (newIndex !== idx) {
reorderTimer.restart()
newIndex = idx
}
}
}
Timer {
id: reorderTimer
interval: 100
onTriggered: {
if (newIndex != -1 && newIndex !== index) {
launcherModel.move(index, newIndex)
}
newIndex = -1
}
}
Behavior on scale {
NumberAnimation { easing.type: Easing.InOutQuad; duration: 150 }
}
ParallelAnimation {
id: slideMoveAnim
NumberAnimation { target: launcherItem; property: "x"; to: wrapper.x; duration: 130; easing.type: Easing.OutQuint }
NumberAnimation { target: launcherItem; property: "y"; to: wrapper.y; duration: 130; easing.type: Easing.OutQuint }
}
Item {
id: iconWrapper
width: parent.width -parent.width/10
height: width - iconText.height
anchors.centerIn: parent
Image { Image {
id: iconImage id: iconImage
anchors { anchors {
horizontalCenter: parent.horizontalCenter // centerIn: launcherItem.n.otNemoIcon ? parent : undefined
horizontalCenter: /* launcherItemnotNemoIcon ? undefined : */parent.horizontalCenter
top: parent.top top: parent.top
topMargin: 8 //topMargin: Theme.itemSpacingExtraSmall
} }
width: gridview.cellWidth - gridview.cellWidth/10 width:/*launcherItem.notNemoIcon ? parent.width-parent.width/3 : */parent.width - parent.width/4
height: width height: width
asynchronous: true asynchronous: true
onStatusChanged: {
if (iconImage.status == Image.Error) {
iconImage.source = "/usr/share/lipstick-glacier-home-qt5/qml/theme/default-icon.png"
}
}
}
Spinner { Spinner {
id: spinner id: spinnerr
anchors { anchors {
horizontalCenter: parent.horizontalCenter centerIn: iconImage
top: parent.top top: iconImage.top
topMargin: 8 topMargin: Theme.itemSpacingExtraSmall
} }
width: gridview.cellWidth - gridview.cellWidth/10 width: iconWrapper.width
height: width height: width
enabled: (model.object.type === LauncherModel.Application) ? model.object.isLaunching : false enabled: (modelData.object.type === LauncherModel.Application) ? modelData.object.isLaunching ? switcher.switchModel.getWindowIdForTitle(modelData.object.title) == 0 : false : false
Connections {
target: Lipstick.compositor
onWindowAdded: {
if(window.category=="" && window.title !== "Home"){
spinnerr.stop()
}
} }
} }
Text{
id: itemsCount
visible: isFolder
text: folderAppsCount
anchors.centerIn: iconImage
horizontalAlignment: Text.AlignHCenter
font.pixelSize: gridview.cellWidth/4
color: "white"
} }
}
// Caption for the icon // Caption for the icon
Text { Text {
id: iconText id: iconText
// elide only works if an explicit width is set // elide only works if an explicit width is set
width: parent.width width: iconWrapper.width
elide: Text.ElideRight elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
font.pixelSize: gridview.cellWidth/8 font.pixelSize: Theme.fontSizeSmall
color: 'white' color: Theme.textColor
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
top: iconImage.bottom bottom: parent.bottom
topMargin: 5 topMargin: Theme.itemSpacingExtraSmall
} }
} }
} }
} }
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Copyright (c) 2017, Eetu Kahelin
// Copyright (c) 2013, Jolla Ltd <robin.burchell@jollamobile.com>
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk>
import QtQuick 2.6
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.lipstick 0.1
Item {
id: wrapper
property alias iconCaption: iconText
property bool reordering: launcherItem.reordering
property bool isFolder
property int folderAppsCount
property bool notNemoIcon
property alias folderLoader: folderLoader
property alias folderModel:launcherItem.folderModel
onXChanged: moveTimer.start()
onYChanged: moveTimer.start()
Timer {
id: moveTimer
interval: 1
onTriggered: moveIcon()
}
function moveIcon() {
if (!reordering) {
if (!launcherItem.slideMoveAnim.running) {
launcherItem.slideMoveAnim.start()
}
}
}
// Application icon for the launcher
LauncherItemWrapper {
id: launcherItem
width: wrapper.width
height: wrapper.height
isFolder: wrapper.isFolder
notNemoIcon:wrapper.notNemoIcon
parentItem: wrapper.parent
clip: true
onClicked: {
// TODO: disallow if close mode enabled
if (modelData.object.type === LauncherModel.Folder) {
if(folderLoader.count>0 || reopenTimer.running) {
folderLoader.model = 0
} else {
folderLoader.model = modelData.object
}
}
}
Item {
id:folderIconStack
width: size
height: size
property int size: parent.width -parent.width/10
property int iconSize: (/*launcherItem.notNemoIcon ? size-size/3 : */ (size - size/4)) * 0.9
property real transparency: 0.6
property int iconCount: 4
property var icons: addIcons()
function addIcons() {
var iconsList = []
for (var i = 0; i < modelData.object.itemCount && i < iconCount; i++) {
var icon = (modelData.object.get(i).iconId.indexOf("/") == 0 ? "file://" : "image://theme/") + modelData.object.get(i).iconId
iconsList.push(icon)
}
return iconsList
}
Image {
width: folderIconStack.iconSize
height: folderIconStack.iconSize
opacity: folderIconStack.transparency
x:toppestIcon.x+Theme.itemSpacingSmall
y:toppestIcon.y+Theme.itemSpacingSmall
visible: folderIconStack.icons.length > folderIconStack.iconCount-1
source: visible ? folderIconStack.icons[folderIconStack.iconCount-1] : ""
}
Image {
width: folderIconStack.iconSize
height: folderIconStack.iconSize
opacity: folderIconStack.transparency
x:toppestIcon.x-Theme.itemSpacingSmall
y:toppestIcon.y+Theme.itemSpacingSmall
visible: folderIconStack.icons.length > folderIconStack.iconCount-2
source: visible ? folderIconStack.icons[folderIconStack.iconCount-2] : ""
}
Image {
width: folderIconStack.iconSize
height: folderIconStack.iconSize
opacity: folderIconStack.transparency
x:toppestIcon.x+Theme.itemSpacingSmall
y:toppestIcon.y-Theme.itemSpacingSmall
visible: folderIconStack.icons.length > folderIconStack.iconCount-3
source: visible ? folderIconStack.icons[folderIconStack.iconCount-3] : ""
}
Image {
id:toppestIcon
width: folderIconStack.iconSize
height: folderIconStack.iconSize
opacity: folderIconStack.transparency
anchors.centerIn: parent
visible: folderIconStack.icons.length > 0
source: visible ? folderIconStack.icons[0]: ""
}
Text{
id: itemsCount
visible: false// launcherItem.isFolder
text: wrapper.folderAppsCount
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
font.pixelSize: folderIconStack.iconSize.width/4
color: "white"
}
}
// Caption for the icon
Text {
id: iconText
// elide only works if an explicit width is set
width: launcherItem.width
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Theme.fontSizeSmall
color: Theme.textColor
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
topMargin: Theme.itemSpacingExtraSmall
}
}
Rectangle {
id:triangle
width: wrapper.height/4
height: width
rotation: 45
color: "white"
opacity: 0.85
visible: folderLoader.visible && folderLoader.count > 0
anchors.top:launcherItem.bottom
anchors.horizontalCenter: launcherItem.horizontalCenter
}
}
GridView {
id: folderLoader
property Item reorderItem
property bool isRootFolder:false
cacheBuffer: folderLoader.contentHeight
parent: gridview.contentItem
y: wrapper.y + wrapper.width
x: 0
z: wrapper.z + 100
width: gridview.width
height: count == 0 ? 0 : (Math.floor((count*wrapper.height-1)/width) + 1) * wrapper.height
cellWidth: wrapper.width
cellHeight: wrapper.width
onReorderItemChanged: if(reorderItem == null) folderIconStack.icons=folderIconStack.addIcons()
Rectangle {
width: parent.width
height: parent.height
opacity: 0.85
color: triangle.color
radius: Theme.itemSpacingMedium
z: -1
}
delegate: LauncherItemDelegate {
id:folderLauncherItem
property QtObject modelData : model
property int cellIndex: index
parent: folderLoader
parentItem: folderLoader
width: wrapper.width
height: wrapper.height
notNemoIcon: isFolder || model.object.iconId == "" ? false : model.object.iconId.indexOf("harbour") > -1 || model.object.iconId.indexOf("apkd_launcher") > -1 ? true : false //Dirty but works most of the times
isFolder: model.object.type == LauncherModel.Folder
source: model.object.iconId == "" || isFolder ? "/usr/share/lipstick-glacier-home-qt5/qml/theme/default-icon.png" : (model.object.iconId.indexOf("/") == 0 ? "file://" : "image://theme/") + model.object.iconId
iconCaption.text: model.object.title
iconCaption.color: Theme.backgroundColor
folderModel:folderLoader.model
}
Behavior on height {
NumberAnimation {
easing.type: Easing.InQuad
duration: 100
}
}
}
//When display goes off, close the folderloader
Connections {
target: Lipstick.compositor
onDisplayOff: {
folderLoader.model = 0
}
}
InverseMouseArea {
anchors.fill: folderLoader
enabled: folderLoader.visible && folderLoader.count > 0
parent: folderLoader.contentItem
onPressed: {
folderLoader.model = 0
reopenTimer.start()
}
}
Timer {
id: reopenTimer
interval: 300
running: false
}
}
// This file is part of colorful-home, a nice user experience for touchscreens.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Copyright (c) 2017, Eetu Kahelin
// Copyright (c) 2013, Jolla Ltd <robin.burchell@jollamobile.com>
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
// Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk>
import QtQuick 2.6
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.lipstick 0.1
MouseArea {
property bool reordering
property int newIndex: -1
property int newFolderIndex: -1
property real oldY
property bool isFolder
property bool notNemoIcon
property Item parentItem
property alias slideMoveAnim: slideMoveAnim
property QtObject folderModel
property Item folderItem
property string deleteState: "basic"
id: launcherItem
parent: parentItem.contentItem
scale: gridview.newFolder && parentItem.folderIndex == cellIndex && !isFolder ? 0.5 : (reordering || parentItem.folderIndex == cellIndex ? 1.3 : 1)
transformOrigin: Item.Center
onXChanged: moved()
onYChanged: moved()
drag.minimumX: parentItem.contentItem.x - width/2
drag.maximumX: parentItem.contentItem.width + width/2
drag.minimumY: parentItem.contentItem.y -height/2 -height/4
drag.maximumY: parentItem.contentItem.height +height/2
onClicked: {
// TODO: disallow if close mode enabled
if (modelData.object.type !== LauncherModel.Folder) {
var winId = switcher.switchModel.getWindowIdForTitle(modelData.object.title)
if (winId == 0 || !modelData.object.isLaunching)
modelData.object.launchApplication()
else
Lipstick.compositor.windowToFront(winId)
}
}
onPressed: {
newIndex = -1
newFolderIndex = -1
}
onPressAndHold: {
reparent(parentItem)
parentItem.reorderItem = launcherItem
drag.target = launcherItem
z = 1000
reordering = true
if(!isFolder){
parentItem.onUninstall = true
}
// don't allow dragging an icon out of pages with a horizontal flick
pager.interactive = false
}
onReleased: {
if (reordering) {
reordering = false
reorderEnded()
reorderTimer.stop()
drag.target = null
parentItem.reorderItem = null
pager.interactive = true
parentItem.onUninstall = false
deleteState="basic"
deleter.uninstalling(deleteState)
parentItem.folderIndex = -1
reparent(parentItem.contentItem)
z = parent.z
slideMoveAnim.start()
}
}
function reparent(newParent) {
var newPos = mapToItem(newParent, 0, 0)
parent = newParent
x = newPos.x - width/2 * (1-scale)
y = newPos.y - height/2 * (1-scale)
}
function moved() {
if (reordering) {
var gridViewPos = parentItem.contentItem.mapFromItem(launcherItem, width/2, height/2)
var item = parentItem.itemAt(gridViewPos.x, gridViewPos.y)
var idx = -1
var folderIdx = -1
var delPos = deleter.remove.mapFromItem(launcherItem, width/2, height/2)
var isdel = deleter.childAt(delPos.x, delPos.y-height/4)
var isdel2 = deleter.childAt(delPos.x, delPos.y+height/4)//hjelp?
if(!isFolder) {
if (isdel === deleter.remove || isdel2 === deleter.remove) {
deleteState="remove"
deleter.uninstalling(deleteState, iconCaption.text)
} else if (isdel === deleter.uninstall || isdel2 === deleter.uninstall) {
deleteState="uninstall"
deleter.uninstalling(deleteState, iconCaption.text)
} else{
deleteState="basic"
deleter.uninstalling(deleteState)
}
}
//When adding new icon to folder or creating new folder
var offset = gridViewPos.x - item.x
var folderThreshold = !isFolder ? item.width / 4 : item.width / 2
if (offset < folderThreshold) {
if (Math.abs(cellIndex - item.cellIndex) > 1 || cellIndex > item.cellIndex || item.y !== wrapper.offsetY) {
idx = cellIndex < item.cellIndex ? item.cellIndex - 1 : item.cellIndex
folderItem = null
}
} else if (offset >= item.width - folderThreshold) {
if (Math.abs(cellIndex - item.cellIndex) > 1 || cellIndex < item.cellIndex || item.y !== wrapper.offsetY) {
idx = cellIndex > item.cellIndex ? item.cellIndex + 1 : item.cellIndex
folderItem = null
}
} else if (item.cellIndex !== cellIndex && parent.isRootFolder && !isFolder) {
folderItem = item
folderIdx = item.cellIndex
}
if (newIndex !== idx) {
newIndex = idx
reorderTimer.restart()
}
if (newFolderIndex != folderIdx) {
newFolderIndex = folderIdx
reorderTimer.restart()
}
if (newFolderIndex != parentItem.folderIndex) {
parentItem.folderIndex = -1
}
}
}
function reorderEnded() {
//called when icon is released and reordering is true
if (parentItem.folderIndex >= 0) {
if (folderModel.get(parentItem.folderIndex).type == LauncherModel.Application) {
var folder = folderModel.createFolder(parentItem.folderIndex, qsTr("folder"))
if (folder) {
folderModel.moveToFolder(modelData.object, folder)
}
} else {
folderModel.moveToFolder(modelData.object, folderModel.get(parentItem.folderIndex))
}
parentItem.folderIndex = -1
parentItem.newFolderActive = false
}
//To drop appicon out of the folder
var realY = parseInt(parentItem.mapFromItem(launcherItem, 0, 0).y) + parseInt(((launcherItem.height*launcherItem.scale-launcherItem.height)/2).toFixed(2))
if (!parent.isRootFolder && (realY < -Math.abs(launcherItem.height/2) || realY > parentItem.height)) {
var parentFolderIndex = folderModel.parentFolder.indexOf(folderModel)
folderModel.parentFolder.moveToFolder(modelData.object, folderModel.parentFolder, parentFolderIndex+1)
}
if(deleteState != "basic"){
//Just placeholder to get visual feedback
enabled=false
deleteAnimation.start()
deleteTimer.start()
}
}
Timer {//Just placeholder to get visual feedback
id:deleteTimer
interval: 5000
onTriggered: {
iconWrapper.opacity=1.0
enabled = true
}
}
NumberAnimation { id:deleteAnimation; target: typeof iconWrapper !== 'undefined' ? iconWrapper : parent; property: "opacity"; to: 0.2; duration: 3000;}//Just placeholder to get visual feedback
Timer {
id: reorderTimer
interval: folderItem && folderItem.isFolder ? 10 : 100
onTriggered: {
if (newFolderIndex >= 0 && newFolderIndex !== cellIndex) {
if (!folderItem.isFolder) {
parentItem.newFolderActive = true
} else {
parentItem.newFolderActive = false
}
parentItem.folderIndex = newFolderIndex
} else if (newIndex != -1 && newIndex !== cellIndex) {
folderModel.move(cellIndex, newIndex)
}
newIndex = -1
}
}
Behavior on scale {
NumberAnimation { easing.type: Easing.InOutQuad; duration: 150 }
}
ParallelAnimation {
id: slideMoveAnim
NumberAnimation { target: launcherItem; property: "x"; to: wrapper.x; duration: 130; easing.type: Easing.OutQuint }
NumberAnimation { target: launcherItem; property: "y"; to: wrapper.y; duration: 130; easing.type: Easing.OutQuint }
}
Connections {
target: modelData.object
ignoreUnknownSignals: true
onItemRemoved: {
var modelDataObject = modelData.object
//If there is only one item in folder, remove the folder
if (modelDataObject.itemCount === 1) {
var parentFolderIndex = modelDataObject.parentFolder.indexOf(modelDataObject)
modelDataObject.parentFolder.moveToFolder(modelDataObject.get(0), modelDataObject.parentFolder, parentFolderIndex)
modelDataObject.destroyFolder()
}
}
}
}
...@@ -14,7 +14,6 @@ Image { ...@@ -14,7 +14,6 @@ Image {
key: "/home/glacier/lockScreen/wallpaperImage" key: "/home/glacier/lockScreen/wallpaperImage"
defaultValue: "/usr/share/lipstick-glacier-home-qt5/qml/images/graphics-wallpaper-home.jpg" defaultValue: "/usr/share/lipstick-glacier-home-qt5/qml/images/graphics-wallpaper-home.jpg"
} }
LockscreenClock { LockscreenClock {
id: clock id: clock
anchors { anchors {
...@@ -25,6 +24,7 @@ Image { ...@@ -25,6 +24,7 @@ Image {
} }
DeviceLockUI { DeviceLockUI {
id: deviceLockUI id: deviceLockUI
visible: false//DeviceLock.state === DeviceLock.Locked
anchors { anchors {
top: clock.bottom top: clock.bottom
left: parent.left left: parent.left
......
import QtQuick 2.0 import QtQuick 2.1
import org.nemomobile.devicelock 1.0
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
Rectangle { Rectangle {
id: lockscreenClock id: lockscreenClock
...@@ -22,10 +25,10 @@ Rectangle { ...@@ -22,10 +25,10 @@ Rectangle {
Text { Text {
id: timeDisplay id: timeDisplay
font.pointSize: 16 font.pixelSize: Theme.fontSizeExtraLarge * 2
font.weight: Font.Light font.weight: Font.Light
lineHeight: 0.85 lineHeight: 0.85
color: "white" color: Theme.textColor
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
anchors { anchors {
...@@ -35,22 +38,46 @@ Rectangle { ...@@ -35,22 +38,46 @@ Rectangle {
text: Qt.formatDateTime(wallClock.time, "hh:mm") text: Qt.formatDateTime(wallClock.time, "hh:mm")
} }
Rectangle {
id: dateRow
height: childrenRect.height
width: weekdayDisplay.width + dateDisplay.width
anchors {
horizontalCenter: parent.horizontalCenter
}
Text { color: "transparent"
id: dateDisplay
Label {
id: weekdayDisplay
font.pointSize: 14 font.pixelSize: Theme.fontSizeLarge
color: "white" color: Theme.textColor
opacity: 0.8
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
font.weight: Font.Bold
anchors {
horizontalCenter: parent.horizontalCenter
}
text: Qt.formatDateTime(wallClock.time, "dddd")
}
Label {
id: dateDisplay
font.pixelSize: Theme.fontSizeLarge
color: Theme.textColor
horizontalAlignment: Text.AlignHCenter
font.weight: Font.Light
anchors { anchors {
left: parent.left horizontalCenter: parent.horizontalCenter
right: parent.right top: weekdayDisplay.bottom
} }
text: Qt.formatDateTime(wallClock.time, "<b>dddd</b>, d MMMM yyyy") text: Qt.formatDate(wallClock.time, "d MMMM yyyy")
} }
} }
}
} }
...@@ -58,7 +58,10 @@ Page { ...@@ -58,7 +58,10 @@ Page {
id: desktop id: desktop
property alias lockscreen: lockScreen property alias lockscreen: lockScreen
property alias switcher: switcher property alias switcher: switcher
property alias codepad: codePad
property int statusBarHeight: statusbar.height property int statusBarHeight: statusbar.height
property bool codepadVisible: false
// Implements back key navigation // Implements back key navigation
Keys.onReleased: { Keys.onReleased: {
...@@ -72,6 +75,7 @@ Page { ...@@ -72,6 +75,7 @@ Page {
Statusbar { Statusbar {
id: statusbar id: statusbar
enabled: DeviceLock.state !== DeviceLock.Locked
} }
GlacierRotation { GlacierRotation {
...@@ -80,7 +84,7 @@ Page { ...@@ -80,7 +84,7 @@ Page {
unrotatedItems: [lockScreen] unrotatedItems: [lockScreen]
} }
orientation: Lipstick.compositor.screenOrientation orientation: DeviceLock.state == DeviceLock.Locked ? nativeOrientation : Lipstick.compositor.screenOrientation
onOrientationChanged: { onOrientationChanged: {
if (!lockscreenVisible()) if (!lockscreenVisible())
...@@ -142,7 +146,7 @@ Page { ...@@ -142,7 +146,7 @@ Page {
} }
// Initial view should be the AppLauncher // Initial view should be the AppLauncher
currentIndex: 0 //currentIndex: 0
} }
Image { Image {
id:wallpaper id:wallpaper
...@@ -153,10 +157,21 @@ Page { ...@@ -153,10 +157,21 @@ Page {
} }
Lockscreen { Lockscreen {
id: lockScreen id: lockScreen
visible: DeviceLock.state >= DeviceLock.Locked visible: lockscreenVisible()//DeviceLock.state == DeviceLock.Locked
width: parent.width width: parent.width
height: parent.height height: parent.height
z: 200 z: 200
} }
DeviceLockUI {
id: codePad
visible: DeviceLock.state == DeviceLock.Locked && codepadVisible
width: lockScreen.width
height:lockScreen.height / 2
anchors {
verticalCenter: lockScreen.verticalCenter
}
z: 200
}
} }
/****************************************************************************************
**
** Copyright (c) 2017, Eetu Kahelin
** All rights reserved.
**
** You may use this file under the terms of BSD license as follows:
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the author nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
****************************************************************************************/
import QtQuick 2.6
import org.nemomobile.lipstick 0.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.contacts 1.0
Item {
height: (searchField.text.length > 0 ? listView.height+searchField.height : searchField.height) + (visible ? Theme.itemSpacingHuge + margin.height : 0)
visible: false
anchors.bottomMargin:Theme.itemSpacingHuge
property alias searchField: searchField
property int oldHeight
Behavior on height {
enabled:!visible
NumberAnimation{ duration: 300 }
}
onVisibleChanged: {
if( visible) searchField.focus = true
else searchField.focus = false
oldHeight=height
}
Item {
id:margin
height: Theme.itemSpacingSmall
}
TextField {
id:searchField
anchors {
top:margin.bottom
left: parent.left
right: parent.right
topMargin: Theme.itemSpacingHuge
leftMargin: Theme.itemSpacingMedium
rightMargin: Theme.itemSpacingMedium
bottomMargin:Theme.itemSpacingHuge
}
Binding {
target: gridview
property: "searchString"
value: searchField.text.toLowerCase().trim()
}
}
ListView {
id:listView
clip: true
width: parent.width
height:contentHeight
anchors.top: searchField.bottom
anchors.topMargin: Theme.itemSpacingSmall
visible: searchString.length>0
section.property: 'category'
section.delegate: Component{
id: sectionHeading
Rectangle {
width: listView.width
height: Theme.itemHeightMedium
color: "transparent"
Text {
id: sectionText
text: {
switch (section) {
case 'Application':
return qsTr("Application")
case 'Contact':
return qsTr("Contact")
default:
return qsTr("Content")
}
}
font.capitalization: Font.AllUppercase
font.pixelSize: Theme.fontSizeMedium
color: Theme.textColor
anchors{
left: parent.left
leftMargin: Theme.itemSpacingSmall
verticalCenter: parent.verticalCenter
}
}
Rectangle{
id: line
height: 1
color: Theme.textColor
width: listView.width-sectionText.width-Theme.itemHeightExtraSmall
anchors{
left: sectionText.right
leftMargin: Theme.itemSpacingSmall
verticalCenter: sectionText.verticalCenter
}
}
}
}
Behavior on height {
NumberAnimation{ duration: 300 }
}
Connections {
target: gridview
onSearchStringChanged: listView.update()
}
model: ListModel {
id: listModel
}
LauncherFolderModel { id: searchLauncherModel }
PeopleModel {
id: peopleModel
filterType: PeopleModel.FilterAll
filterPattern: searchString
requiredProperty: PeopleModel.PhoneNumberRequired
//searchableProperty: root.searchableProperty
}
//Orginal function ** Copyright (C) 2013 Jolla Ltd. ** Contact: Joona Petrell <joona.petrell@jollamobile.com>
//Function has been modified
function update() {
if(searchString.length<1) {
listModel.clear()
} else {
var iconTitle
var category
var extraCaption
var iconId
var found
var i
var titles = []
var contacts = []
for (i = 0; i < searchLauncherModel.itemCount; ++i) {
titles.push({'iconTitle':searchLauncherModel.get(i).title, 'iconSource':searchLauncherModel.get(i).iconId, 'id':i, 'category':qsTr("Application")})
}
for (i = 0; i < peopleModel.count; ++i) {
if(peopleModel.get(i).firstName && peopleModel.get(i).lastName) {
contacts.push({'title':(peopleModel.get(i).firstName + " " + peopleModel.get(i).lastName), 'iconSource':peopleModel.get(i).avatarUrl.toString(), 'extraCaption':peopleModel.get(i).phoneNumbers, 'category':qsTr("Contact")})
}
}
var filteredTitles = titles.filter(function (icon) {
return icon.iconTitle.toLowerCase().indexOf(searchString) !== -1
})
// helper objects that can be quickly accessed
var filteredTitleObject = new Object
for (i = 0; i < filteredTitles.length; ++i) {
filteredTitleObject[filteredTitles[i].iconTitle] = true
}
var existingTitleObject = new Object
for (i = 0; i < count; ++i) {
iconTitle = listModel.get(i).title
existingTitleObject[iconTitle] = true
}
// remove items no longer in filtered set
i = 0
while (i < count) {
iconTitle = listModel.get(i).title
found = filteredTitleObject.hasOwnProperty(iconTitle)
if (!found) {
listModel.remove(i)
} else {
i++
}
}
// add new items
for (i = 0; i < filteredTitles.length; ++i) {
iconTitle = filteredTitles[i].iconTitle
iconId = filteredTitles[i].iconSource
var id = filteredTitles[i].id
category = filteredTitles[i].category
found = existingTitleObject.hasOwnProperty(iconTitle)
if (!found) {
// for simplicity, just adding to end instead of corresponding position in original list
listModel.append({'title':iconTitle, 'iconSource':iconId, 'id':id, 'category':category})
}
}
for (i = 0; i < contacts.length; ++i) {
iconTitle = contacts[i].title
iconId = contacts[i].iconSource
extraCaption = contacts[i].extraCaption[0]
category = contacts[i].category
listModel.append({'title':iconTitle, 'iconSource':iconId, 'extraCaption':extraCaption, 'category':category})
}
}
}
delegate: Item {
width: parent.width
height:Theme.itemHeightExtraLarge*1.2
property string iconCaption: model.title
property string iconSource: {
if(model.iconSource) {
if(model.iconSource.indexOf("file:///") == 0) {
return model.iconSource
}else {
if( model.iconSource.indexOf("/") == 0) {
return "file://" + model.iconSource
} else return "image://theme/" + model.iconSource
}
} else return "/usr/share/lipstick-glacier-home-qt5/qml/theme/default-icon.png"
}
Rectangle {
anchors.fill: parent
color: "#11ffffff"
visible: mouse.pressed
}
Image {
id: iconImage
width: parent.height-Theme.itemSpacingMedium
height: width
source:iconSource
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Theme.itemSpacingLarge
onStatusChanged: {
if (iconImage.status == Image.Error) {
iconImage.source = "/usr/share/lipstick-glacier-home-qt5/qml/theme/default-icon.png"
}
}
}
Spinner {
id: spinner
anchors {
centerIn: iconImage
top: iconImage.top
topMargin: Theme.itemSpacingExtraSmall
}
width: iconImage.width
height: width
enabled: (searchLauncherModel.get(model.id).type === LauncherModel.Application) ? searchLauncherModel.get(model.id).isLaunching ? switcher.switchModel.getWindowIdForTitle(model.title) == 0 : false : false
Connections {
target: Lipstick.compositor
onWindowAdded: {
if(window.category=="" && window.title !== "Home"){
spinner.stop()
}
}
}
}
Item {
id: labelWrapper
anchors {
left: iconImage.right
leftMargin: Theme.itemSpacingLarge
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: Theme.itemSpacingLarge
}
height: labelWrapper.childrenRect.height
Label {
id:mainLabel
text:iconCaption
anchors {
left: parent.left
right: parent.right
}
font.pixelSize:Theme.fontSizeLarge
color:Theme.textColor
elide:Text.ElideRight
verticalAlignment:Text.AlignVCenter
}
Label {
id:extraLabel
text: extraCaption ? extraCaption : category === "Application" ? qsTr("Open" + " " + iconCaption) : ""
anchors {
top:mainLabel.bottom
left:mainLabel.left
}
font.pixelSize:Theme.fontSizeSmall
color:Theme.textColor
elide:Text.ElideRight
verticalAlignment:Text.AlignVCenter
}
}
MouseArea {
id:mouse
anchors.fill: parent
onClicked: {
switch (category ) {
case "Application":
if (searchLauncherModel.get(model.id).type !== LauncherModel.Folder) {
var winId = switcher.switchModel.getWindowIdForTitle(model.title)
if (winId == 0 || !searchLauncherModel.get(model.id).isLaunching)
searchLauncherModel.get(model.id).launchApplication()
else
Lipstick.compositor.windowToFront(winId)
}
context.state=""
break
case "Contact":
console.log("Call to person. Or open contextmenu where sms and call")
break
}
}
}
}
}
}
...@@ -42,28 +42,60 @@ import "statusbar" ...@@ -42,28 +42,60 @@ import "statusbar"
Item { Item {
id: root id: root
z: 201 z: 201
height: Math.min(parent.width,parent.height)/10 height: Theme.itemHeightLarge
width: parent.width width: parent.width
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
enabled: !lockscreenVisible()
Rectangle { Rectangle {
id: statusbar id: statusbar
color: "black" color: Theme.fillDarkColor
anchors.fill: parent anchors.fill: parent
opacity: 0.5 opacity: 0.5
z: 200 z: 200
} }
MouseArea {
property int oldX
property int oldY
anchors.fill: row
z: row.z + 10
enabled: !lockscreenVisible()
onClicked: {
if(oldX != mouseX && oldY !== mouseY && row.childAt(mouseX, mouseY) && row.currentChild !== row.childAt(mouseX, mouseY)) {
row.currentChild = row.childAt(mouseX, mouseY)
row.currentChild.clicked()
}else {
row.currentChild = null
}
}
onPositionChanged: {
oldX = mouseX
oldY = mouseY
if(pressed && row.childAt(mouseX, mouseY)) {
if(row.currentChild !== row.childAt(mouseX, mouseY)) {
row.currentChild = row.childAt(mouseX, mouseY)
if(panel_loader.visible) panel_loader.visible = false
row.currentChild.clicked()
}
} else {
row.currentChild = null
}
}
}
Connections { Connections {
target: lipstickSettings; target: lipstickSettings;
onLockscreenVisibleChanged: { onLockscreenVisibleChanged: {
if(lipstickSettings.lockscreenVisible) { if(lipstickSettings.lockscreenVisible) {
batteryChargePercentage.subscribe() batteryIndicator.batteryChargePercentage.subscribe()
cellularSignalBars.subscribe() cellularSignalBars.subscribe()
cellularRegistrationStatus.subscribe() cellularRegistrationStatus.subscribe()
cellularNetworkName.subscribe() cellularNetworkName.subscribe()
cellularDataTechnology.subscribe() cellularDataTechnology.subscribe()
} else { } else {
batteryChargePercentage.unsubscribe() batteryIndicator.batteryChargePercentage.unsubscribe()
cellularSignalBars.unsubscribe() cellularSignalBars.unsubscribe()
cellularRegistrationStatus.unsubscribe() cellularRegistrationStatus.unsubscribe()
cellularNetworkName.unsubscribe() cellularNetworkName.unsubscribe()
...@@ -131,14 +163,39 @@ Item { ...@@ -131,14 +163,39 @@ Item {
Loader { Loader {
id: panel_loader id: panel_loader
anchors.bottom: root.top anchors.bottom: root.top
height: 240 height: 0
width: parent.width width: parent.width
visible: false visible: false
onVisibleChanged: {
if(visible) riseUp.start()
else closeDown.start()
}
NumberAnimation {
id:riseUp
target: panel_loader
property: "height"
duration: 200
from:0
to:Theme.itemWidthMedium
easing.type: Easing.InOutQuad
}
NumberAnimation {
id:closeDown
target: panel_loader
property: "height"
duration: 200
from: panel_loader.height
to: 0
easing.type: Easing.InOutQuad
}
} }
RowLayout { RowLayout {
id:row
anchors.fill: statusbar anchors.fill: statusbar
spacing: root.height/4 spacing: root.height/4
property var currentChild
StatusbarItem { StatusbarItem {
iconSize: root.height/2 iconSize: root.height/2
source: (cellularSignalBars.value > 0) ? "image://theme/icon_cell" + cellularSignalBars.value : "image://theme/icon_cell1" source: (cellularSignalBars.value > 0) ? "image://theme/icon_cell" + cellularSignalBars.value : "image://theme/icon_cell1"
...@@ -196,8 +253,10 @@ Item { ...@@ -196,8 +253,10 @@ Item {
} else if (networkManager.defaultRoute.strength >= 40) { } else if (networkManager.defaultRoute.strength >= 40) {
return "image://theme/icon_wifi_focused1" return "image://theme/icon_wifi_focused1"
} else { } else {
return "image://theme/icon_wifi_normal4" return "image://theme/icon_wifi_0"
} }
} else if (wifimodel.powered && !wlan.connected) {
return "image://theme/icon_wifi_touch"
} else { } else {
return "image://theme/icon_wifi_0" return "image://theme/icon_wifi_0"
} }
...@@ -224,6 +283,7 @@ Item { ...@@ -224,6 +283,7 @@ Item {
} }
StatusbarItem { StatusbarItem {
iconSize: root.height/2 iconSize: root.height/2
anchors.verticalCenter: parent.verticalCenter
Label { Label {
id: hours id: hours
width: root.height/4 width: root.height/4
...@@ -242,6 +302,8 @@ Item { ...@@ -242,6 +302,8 @@ Item {
} }
} }
BatteryIndicator{} BatteryIndicator{
id:batteryIndicator
}
} }
} }
...@@ -112,7 +112,7 @@ Compositor { ...@@ -112,7 +112,7 @@ Compositor {
id: overlayLayer id: overlayLayer
z: 5 z: 5
visible: root.appActive //visible: root.appActive
} }
Item { Item {
...@@ -135,7 +135,7 @@ Compositor { ...@@ -135,7 +135,7 @@ Compositor {
property real lockThreshold: 0.25 property real lockThreshold: 0.25
property int lockscreenX property int lockscreenX
property int lockscreenY property int lockscreenY
enabled: DeviceLock.state != DeviceLock.Locked enabled: true//!Desktop.instance.codepadVisible//DeviceLock.state != DeviceLock.Locked
onGestureStarted: { onGestureStarted: {
swipeAnimation.stop() swipeAnimation.stop()
...@@ -144,6 +144,15 @@ Compositor { ...@@ -144,6 +144,15 @@ Compositor {
if (root.appActive) { if (root.appActive) {
state = "swipe" state = "swipe"
} }
else if (!root.appActive && DeviceLock.state !== DeviceLock.Locked) {
state = "lock"
}
else if (Desktop.instance.lockscreenVisible() && DeviceLock.state === DeviceLock.Locked && !Desktop.instance.codepadVisible) {
state = "pullCodepad"
}
else if (Desktop.instance.lockscreenVisible() && DeviceLock.state === DeviceLock.Locked && Desktop.instance.codepadVisible) {
state = "pushCodepad"
}
} }
onGestureFinished: { onGestureFinished: {
...@@ -163,10 +172,21 @@ Compositor { ...@@ -163,10 +172,21 @@ Compositor {
Desktop.instance.lockscreen.width : Desktop.instance.lockscreen.width :
-Desktop.instance.lockscreen.width) -Desktop.instance.lockscreen.width)
lockAnimation.start() lockAnimation.start()
// Locks or unlocks depending if the screen is locked. // Locks, unlocks or brings up codepad to enter security code
// Locks
if (!Desktop.instance.lockscreenVisible()) { if (!Desktop.instance.lockscreenVisible()) {
Desktop.instance.setLockScreen(true) Desktop.instance.setLockScreen(true)
} else { }
// Brings up codepad, only left and right swipes allowed for it for now
else if (Desktop.instance.lockscreenVisible() && !Desktop.instance.codepad.visible && DeviceLock.state == DeviceLock.Locked && (gesture !== "down" && gesture !== "up")) {
Desktop.instance.codepadVisible = true
}
// Hides codepad but does not unlock the code, only left and right swipes allowed for now
else if (Desktop.instance.lockscreenVisible() && Desktop.instance.codepad.visible && DeviceLock.state == DeviceLock.Locked && gesture !== "down" && gesture !== "up") {
Desktop.instance.codepadVisible = false
}
// Unlocks if no security code required
else if (DeviceLock.state !== DeviceLock.Locked && Desktop.instance.lockscreenVisible()) {
Desktop.instance.setLockScreen(false) Desktop.instance.setLockScreen(false)
} }
} else { } else {
...@@ -174,11 +194,12 @@ Compositor { ...@@ -174,11 +194,12 @@ Compositor {
} }
} }
} }
// States are for the animations that follow your finger during swipes
states: [ states: [
// Swipe state is when app is on and you are swiping it to background or closing it
State { State {
name: "swipe" name: "swipe"
when: DeviceLock.state != DeviceLock.Locked when: !Desktop.instance.codepadVisible
PropertyChanges { PropertyChanges {
target: gestureArea target: gestureArea
delayReset: true delayReset: true
...@@ -190,9 +211,10 @@ Compositor { ...@@ -190,9 +211,10 @@ Compositor {
y: gestureArea.horizontal ? 0 : gestureArea.value y: gestureArea.horizontal ? 0 : gestureArea.value
} }
}, },
// Lock state is for when screen is locked but no security code required, can be swiped from any edge
State { State {
name: "lock" name: "lock"
when: DeviceLock.state == DeviceLock.Locked when: Desktop.instance.lockscreenVisible()
PropertyChanges { PropertyChanges {
target: Desktop.instance.lockscreen target: Desktop.instance.lockscreen
visible: true visible: true
...@@ -220,6 +242,63 @@ Compositor { ...@@ -220,6 +242,63 @@ Compositor {
Desktop.instance.lockscreen.height : Desktop.instance.lockscreen.height :
Desktop.instance.lockscreen.width)+gestureArea.value) ) ) Desktop.instance.lockscreen.width)+gestureArea.value) ) )
} }
},
// pullCodepad is when you are pulling codepad into view to enter security code
State {
name: "pullCodepad"
when: Desktop.instance.codepadVisible
PropertyChanges {
target: Desktop.instance
codepadVisible: true
}
PropertyChanges {
target: gestureArea
delayReset: true
}
PropertyChanges {
target: Desktop.instance.codepad
// Confusing logic and math to get the codepad follow your finger
x: gestureArea.lockscreenX + (gestureArea.value < 0 ? Desktop.instance.lockscreen.width : -Desktop.instance.lockscreen.width) +
((gestureArea.horizontal) ? (Desktop.instance.lockscreenVisible()?(gestureArea.value) :
(gestureArea.gesture == "right" ?
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
-Desktop.instance.lockscreen.width :
-Desktop.instance.lockscreen.height)+Math.abs(gestureArea.value) :
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
Desktop.instance.lockscreen.width :
Desktop.instance.lockscreen.height)+gestureArea.value) ) : 0 )
// Bringing up the codepad opacity from 0 to 1
opacity: gestureArea.horizontal ? (gestureArea.value < 0 ? (gestureArea.value / -Desktop.instance.lockscreen.width) :
gestureArea.value / Desktop.instance.lockscreen.width) : 0
}
},
// pushCodepad is when you are pushing the codepad away without entering a security code
State {
name: "pushCodepad"
when: Desktop.instance.lockscreenVisible() && DeviceLock.state === DeviceLock.Locked && Desktop.instance.codepadVisible
PropertyChanges {
target: gestureArea
delayReset: true
}
PropertyChanges {
target: Desktop.instance.codepad
// Confusing logic for the codepad to follow your swipe
x: gestureArea.lockscreenX +
((gestureArea.horizontal) ? (Desktop.instance.lockscreenVisible()?(gestureArea.value) :
(gestureArea.gesture == "right" ?
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
-Desktop.instance.lockscreen.width :
-Desktop.instance.lockscreen.height)+Math.abs(gestureArea.value) :
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
Desktop.instance.lockscreen.width :
Desktop.instance.lockscreen.height)+gestureArea.value) ) : 0 )
// Hiding the codepad with opacity fading from 1 to 0
opacity: 1 - (gestureArea.horizontal ? (gestureArea.value < 0 ? (gestureArea.value / -Desktop.instance.lockscreen.width) :
gestureArea.value / Desktop.instance.lockscreen.width) : 0)
}
} }
] ]
...@@ -250,6 +329,7 @@ Compositor { ...@@ -250,6 +329,7 @@ Compositor {
id: valueAnimationLock id: valueAnimationLock
target: Desktop.instance.lockscreen target: Desktop.instance.lockscreen
property: "x" property: "x"
velocity: 1
easing.type: Easing.OutQuint easing.type: Easing.OutQuint
} }
...@@ -305,8 +385,10 @@ Compositor { ...@@ -305,8 +385,10 @@ Compositor {
} }
onDisplayOff: onDisplayOff:
if (root.topmostAlarmWindow == null) if (root.topmostAlarmWindow == null) {
Desktop.instance.codepadVisible = false
setCurrentWindow(root.homeWindow) setCurrentWindow(root.homeWindow)
}
onWindowAdded: { onWindowAdded: {
console.log("Compositor: Window added \"" + window.title + "\"" + " category: " + window.category) console.log("Compositor: Window added \"" + window.title + "\"" + " category: " + window.category)
...@@ -316,6 +398,7 @@ Compositor { ...@@ -316,6 +398,7 @@ Compositor {
var isNotificationWindow = window.category == "notification" var isNotificationWindow = window.category == "notification"
var isOverlayWindow = window.category == "overlay" var isOverlayWindow = window.category == "overlay"
var isAlarmWindow = window.category == "alarm" var isAlarmWindow = window.category == "alarm"
var isApplicationWindow = window.category == ""
var parent = null var parent = null
if (window.category == "cover") { if (window.category == "cover") {
window.visible = false window.visible = false
...@@ -329,10 +412,14 @@ Compositor { ...@@ -329,10 +412,14 @@ Compositor {
parent = overlayLayer parent = overlayLayer
} else if (isAlarmWindow) { } else if (isAlarmWindow) {
parent = alarmsLayer parent = alarmsLayer
} else if (isApplicationWindow) {
parent = appLayer
} else { } else {
parent = appLayer parent = appLayer
} }
window.focusOnTouch = !window.isInProcess && !isOverlayWindow && !isNotificationWindow
var w; var w;
if (isOverlayWindow) w = alphaWrapper.createObject(parent, { window: window }) if (isOverlayWindow) w = alphaWrapper.createObject(parent, { window: window })
else w = windowWrapper.createObject(parent, { window: window }) else w = windowWrapper.createObject(parent, { window: window })
......
import QtQuick 2.0 import QtQuick 2.6
import QtQuick.Controls.Nemo 1.0 import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0 import QtQuick.Controls.Styles.Nemo 1.0
...@@ -8,55 +8,115 @@ MouseArea { ...@@ -8,55 +8,115 @@ MouseArea {
height: childrenRect.height height: childrenRect.height
width: rootitem.width width: rootitem.width
drag.target: notifyArea
drag.axis: Drag.XAxis
drag.minimumX: 0-Theme.itemHeightMedium
drag.maximumX: notifyArea.width
drag.onActiveChanged: {
if(!drag.active ) {
if((notifyArea.x > notifyArea.width/3)) {
slideAnimation.start()
}else slideBackAnimation.start()
}
}
onClicked: { onClicked: {
if (modelData.userRemovable) { if (modelData.userRemovable) {
modelData.actionInvoked("default") slideAnimation.start()
}
}
NumberAnimation {
id:slideAnimation
target: notifyArea
property: "x"
duration: 200
from: notifyArea.x
to: notifyArea.width
easing.type: Easing.InOutQuad
onStopped: modelData.actionInvoked("default")
} }
NumberAnimation {
id:slideBackAnimation
target: notifyArea
property: "x"
duration: 200
from: notifyArea.x
to: 0
easing.type: Easing.InOutQuad
}
Rectangle {
anchors.fill: parent
color: "#11ffffff"
visible: notifyArea.pressed
radius: Theme.itemSpacingMedium
} }
Image { Image {
id: appIcon id: appIcon
height: 100 height: Theme.itemHeightExtraLarge
width: height width: height
property string defaultIcon: "/usr/share/lipstick-glacier-home-qt5/qml/images/glacier.svg"
anchors{ anchors{
left: parent.left left: parent.left
leftMargin: 20 leftMargin: Theme.itemSpacingLarge
} }
source: { source: {
if (modelData.icon) if (modelData.icon)
return "image://theme/" + modelData.icon return "image://theme/" + modelData.icon
else else
return "/usr/share/lipstick-glacier-home-qt5/qml/images/glacier.svg" return defaultIcon
}
onStatusChanged: {
if (appIcon.status == Image.Error) {
appIcon.source = defaultIcon
}
}
}
Label {
id: appName
text: modelData.appName
width: (rootitem.width-appIcon.width)-Theme.itemSpacingHuge
color: Theme.textColor
font.pixelSize: Theme.fontSizeMedium
font.capitalization: Font.AllUppercase
font.bold: true
anchors {
left: appIcon.right
top: parent.top
leftMargin: Theme.itemSpacingLarge
} }
} }
Label { Label {
id: appSummary id: appSummary
text: modelData.summary text: modelData.summary
width: (rootitem.width-appIcon.width)-40 width: (rootitem.width-appIcon.width)-Theme.itemSpacingHuge
font.pointSize: 12 color: Theme.textColor
font.bold :true font.pixelSize: Theme.fontSizeLarge
font.capitalization: Font.AllUppercase //font.bold :true
//font.capitalization: Font.AllUppercase
anchors{ anchors{
left: appIcon.right left: appName.left
leftMargin: 20 top: appName.bottom
top: parent.top topMargin: Theme.itemSpacingSmall
} }
wrapMode: Text.Wrap elide: Text.ElideRight
} }
Label { Label {
id: appBody id: appBody
width: (rootitem.width-appIcon.width)-40 width: (rootitem.width-appIcon.width)-Theme.itemSpacingHuge
text: modelData.body text: modelData.body
font.pointSize: 14 color: Theme.textColor
font.pixelSize: Theme.fontSizeMedium
anchors{ anchors{
left: appSummary.left left: appName.left
top: appSummary.bottom top: appSummary.bottom
} }
wrapMode: Text.Wrap elide: Text.ElideRight
} }
} }
...@@ -26,6 +26,7 @@ import QtQuick 2.0 ...@@ -26,6 +26,7 @@ import QtQuick 2.0
import org.nemomobile.lipstick 0.1 import org.nemomobile.lipstick 0.1
import QtQuick.Controls.Nemo 1.0 import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0 import QtQuick.Controls.Styles.Nemo 1.0
import QtGraphicalEffects 1.0
import "../scripts/desktop.js" as Desktop import "../scripts/desktop.js" as Desktop
...@@ -39,27 +40,12 @@ Item { ...@@ -39,27 +40,12 @@ Item {
rotation: Desktop.instance.parent.rotation rotation: Desktop.instance.parent.rotation
x: Desktop.instance.parent.x x: Desktop.instance.parent.x
y: Desktop.instance.parent.y y: Desktop.instance.parent.y
Rectangle {
id: dimmer
height: Math.min(parent.width,parent.height)/14
anchors.top: parent.top
anchors.topMargin: notificationArea.notificationHeight
anchors.left: parent.left
anchors.right: parent.right
gradient: Gradient {
GradientStop { position: 1.0; color: "black" }
GradientStop { position: 0; color: "transparent" }
}
}
MouseArea { MouseArea {
id: notificationArea id: notificationArea
property int notificationHeight: Math.min(parent.width,parent.height)/12 property int notificationHeight: Theme.itemHeightExtraLarge
property int notificationMargin: 14 property int notificationMargin: Theme.itemSpacingExtraSmall
property int notificationIconSize: Math.min(parent.width,parent.height)/12 property int notificationIconSize: Theme.itemHeightMedium
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
width: notificationWindow.width width: notificationWindow.width
...@@ -67,14 +53,18 @@ Item { ...@@ -67,14 +53,18 @@ Item {
onClicked: if (notificationPreviewPresenter.notification != null) notificationPreviewPresenter.notification.actionInvoked("default") onClicked: if (notificationPreviewPresenter.notification != null) notificationPreviewPresenter.notification.actionInvoked("default")
Rectangle { Rectangle {
id: notificationPreview id: notificationPreview
anchors { anchors {
fill: parent fill: parent
} }
color: "transparent"
radius: 10
gradient: Gradient {
GradientStop { position: 1.0; color: Theme.fillDarkColor }
GradientStop { position: 0; color: "transparent"}
}
opacity: 0 opacity: 0
states: [ states: [
...@@ -149,13 +139,14 @@ Item { ...@@ -149,13 +139,14 @@ Item {
top: parent.top top: parent.top
left: icon.right left: icon.right
right: parent.right right: parent.right
leftMargin: notificationArea.notificationMargin + 26 topMargin: notificationArea.notificationMargin
leftMargin: notificationArea.notificationMargin*2
rightMargin: notificationArea.notificationMargin rightMargin: notificationArea.notificationMargin
bottomMargin: notificationArea.notificationMargin //bottomMargin: notificationArea.notificationMargin
} }
font.pointSize: 12 font.pixelSize: Theme.fontSizeLarge
text: notificationPreviewPresenter.notification != null ? notificationPreviewPresenter.notification.previewSummary : "" text: notificationPreviewPresenter.notification != null ? notificationPreviewPresenter.notification.previewSummary : ""
color: "white" color: Theme.textColor
clip: true clip: true
elide: Text.ElideRight elide: Text.ElideRight
} }
...@@ -168,14 +159,33 @@ Item { ...@@ -168,14 +159,33 @@ Item {
right: summary.right right: summary.right
} }
font { font {
pointSize: 10 pixelSize: Theme.fontSizeMedium
bold: true bold: true
} }
text: notificationPreviewPresenter.notification != null ? notificationPreviewPresenter.notification.previewBody : "" text: notificationPreviewPresenter.notification != null ? notificationPreviewPresenter.notification.previewBody : ""
color: "white" color: Theme.textColor
clip: true clip: true
elide: Text.ElideRight elide: Text.ElideRight
} }
//The close button goes here that is in one of the designs
MouseArea {
id: notificationCloser
anchors {
right: parent.right
top: parent.top
}
height: notificationArea.notificationHeight
width: height
//The X icon goes here
/*Image {
id: closeIcon
anchors.centerIn: parent
width: Theme.itemHeightMedium
height: width
source: "/usr/share/lipstick-glacier-home-qt5/qml/images/closeapp.svg"
}*/
}
Connections { Connections {
target: notificationPreviewPresenter; target: notificationPreviewPresenter;
......
...@@ -4,11 +4,17 @@ import org.freedesktop.contextkit 1.0 ...@@ -4,11 +4,17 @@ import org.freedesktop.contextkit 1.0
StatusbarItem { StatusbarItem {
id: batteryIndicator id: batteryIndicator
property int chargeValue: 0 property int chargeValue: 0
property alias batteryChargePercentage: batteryChargePercentage
ContextProperty { ContextProperty {
id: batteryChargePercentage id: batteryChargePercentage
key: "Battery.ChargePercentage" key: "Battery.ChargePercentage"
value: "100" value: "100"
onValueChanged: {
if(batteryStateContextProperty.value != "charging") {
chargeIcon();
}
}
} }
ContextProperty { ContextProperty {
...@@ -17,8 +23,13 @@ StatusbarItem { ...@@ -17,8 +23,13 @@ StatusbarItem {
onValueChanged: { onValueChanged: {
if(batteryStateContextProperty.value == "charging") if(batteryStateContextProperty.value == "charging")
{ {
if (batteryChargePercentage.value === 100) {
chargingTimer.stop()
chargeIcon()
}else {
chargingTimer.start() chargingTimer.start()
} }
}
else else
{ {
chargingTimer.stop() chargingTimer.stop()
......
...@@ -40,7 +40,7 @@ Component { ...@@ -40,7 +40,7 @@ Component {
Label { Label {
text: qsTr("Level")+ ": " + batteryChargePercentage.value + "%" text: qsTr("Level")+ ": " + batteryChargePercentage.value + "%"
font.pointSize: 8 font.pixelSize: Theme.fontSizeMedium
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
......
...@@ -34,6 +34,7 @@ import QtQuick 2.0 ...@@ -34,6 +34,7 @@ import QtQuick 2.0
import QtQuick.Controls 1.0 import QtQuick.Controls 1.0
import QtQuick.Controls.Nemo 1.0 import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0 import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.lipstick 0.1
Rectangle { Rectangle {
id: commonPanel id: commonPanel
...@@ -41,8 +42,14 @@ Rectangle { ...@@ -41,8 +42,14 @@ Rectangle {
property alias switcherEnabled: columnCheckBox.enabled property alias switcherEnabled: columnCheckBox.enabled
property alias switcherChecked: columnCheckBox.checked property alias switcherChecked: columnCheckBox.checked
property string name: "" property string name: ""
signal click
onClick: {
panel_loader.sourceComponent = parent.panel
panel_loader.visible = !panel_loader.visible
row.currentChild=null
}
height: 240 height: Theme.itemWidthMedium
width: root.width width: root.width
color: "transparent" color: "transparent"
...@@ -50,6 +57,20 @@ Rectangle { ...@@ -50,6 +57,20 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#313131" color: "#313131"
opacity: 0.3 opacity: 0.3
}
InverseMouseArea {
anchors.fill: parent
enabled: parent.visible
onPressed: {
parent.click()
}
}
MouseArea {
id:mouseArea
anchors.fill:parent
onClicked: parent.click()
} }
clip: true clip: true
...@@ -60,7 +81,7 @@ Rectangle { ...@@ -60,7 +81,7 @@ Rectangle {
id: actionColumn id: actionColumn
anchors{ anchors{
top: commonPanel.top top: commonPanel.top
topMargin: 20 topMargin: Theme.itemSpacingLarge
} }
width: parent.width width: parent.width
Label{ Label{
...@@ -68,7 +89,7 @@ Rectangle { ...@@ -68,7 +89,7 @@ Rectangle {
text: name text: name
anchors{ anchors{
left: actionColumn.left left: actionColumn.left
leftMargin: 20 leftMargin: Theme.itemSpacingLarge
} }
wrapMode: Text.Wrap wrapMode: Text.Wrap
font.pointSize: 8 font.pointSize: 8
...@@ -81,7 +102,7 @@ Rectangle { ...@@ -81,7 +102,7 @@ Rectangle {
visible: enabled visible: enabled
anchors{ anchors{
right: actionColumn.right right: actionColumn.right
rightMargin: 20 rightMargin: Theme.itemSpacingLarge
verticalCenter: nameLabel.verticalCenter verticalCenter: nameLabel.verticalCenter
} }
} }
...@@ -89,12 +110,54 @@ Rectangle { ...@@ -89,12 +110,54 @@ Rectangle {
Column{ Column{
id: dataColumn id: dataColumn
width: parent.width-40 width: parent.width-settingsIcon.width
anchors{ anchors{
left: parent.left left: parent.left
leftMargin: 20 leftMargin: Theme.itemSpacingLarge
top: actionColumn.bottom top: actionColumn.bottom
topMargin: 60 topMargin: Theme.itemSpacingHuge*1.5
}
}
//Just placeholder until IconButton will get merged
Image {
id:settingsIcon
fillMode: Image.PreserveAspectFit
height: Theme.itemHeightMedium
visible: parent.height > Theme.itemSpacingMedium
source: "image://theme/icon-app-settings" //maybe better icon? settings.png from statusbar spec
anchors{
right: parent.right
rightMargin: Theme.itemSpacingLarge
bottom:parent.bottom
bottomMargin: Theme.itemSpacingLarge
}
MouseArea {
anchors.fill:parent
onClicked: console.log("open right settings page...")
}
}
Connections {
target: lockScreen
onVisibleChanged: {
if(lockscreenVisible()) {
panel_loader.visible = false
}
}
}
Connections {
target: Lipstick.compositor
onDisplayOff: {
panel_loader.visible = false
}
onWindowAdded: {
if(window.category=="" && window.title !== "Home"){
panel_loader.visible = false
}
}
onWindowRaised: {
if(window.category=="" && window.title !== "Home"){
panel_loader.visible = false
}
} }
} }
} }
...@@ -68,7 +68,7 @@ Component { ...@@ -68,7 +68,7 @@ Component {
anchors.fill: simpanel anchors.fill: simpanel
spacing: 0 spacing: 0
RowLayout { RowLayout {
spacing: 16 spacing: Theme.itemSpacingMedium
TextField { TextField {
id: pinquery id: pinquery
width: 140 width: 140
...@@ -138,7 +138,7 @@ Component { ...@@ -138,7 +138,7 @@ Component {
Label { Label {
visible: !needsPin visible: !needsPin
text: qsTr("No pin required!") text: qsTr("No pin required!")
font.pointSize: 16 font.pixelSize:Theme.fontSizeMedium
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
......
...@@ -3,20 +3,13 @@ import QtQuick.Layouts 1.0 ...@@ -3,20 +3,13 @@ import QtQuick.Layouts 1.0
Item { Item {
property alias source: icon.source property alias source: icon.source
property alias pressed: mouse.pressed
property string panel_source property string panel_source
property Component panel property Component panel
property double iconSize property double iconSize
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Image { function clicked() {
width: iconSize
height: iconSize
id: icon
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
if (panel_source !== "" && !panel) { if (panel_source !== "" && !panel) {
panel_loader.source = panel_source panel_loader.source = panel_source
panel_loader.visible = !panel_loader.visible panel_loader.visible = !panel_loader.visible
...@@ -26,5 +19,25 @@ Item { ...@@ -26,5 +19,25 @@ Item {
panel_loader.visible = !panel_loader.visible panel_loader.visible = !panel_loader.visible
} }
} }
Rectangle{
anchors.fill:parent
opacity: 0.8
color: Theme.fillDarkColor
visible: panel_loader.visible && (panel_loader.sourceComponent == panel)
}
Image {
fillMode: Image.PreserveAspectFit
height: iconSize
id: icon
anchors.centerIn: parent
}
MouseArea {
id:mouse
anchors.fill: parent
enabled: !lockscreenVisible()
onClicked: parent.clicked()
} }
} }
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
** **
****************************************************************************************/ ****************************************************************************************/
import QtQuick 2.1 import QtQuick 2.6
import QtQuick.Controls.Nemo 1.0 import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0 import QtQuick.Controls.Styles.Nemo 1.0
import MeeGo.Connman 0.2 import MeeGo.Connman 0.2
...@@ -40,7 +40,7 @@ Component { ...@@ -40,7 +40,7 @@ Component {
id: wifiPanel id: wifiPanel
name: "Wifi" name: "Wifi"
switcherEnabled: true switcherEnabled: true
switcherChecked: true switcherChecked: wifimodel.powered
onSwitcherCheckedChanged: { onSwitcherCheckedChanged: {
wifimodel.setPowered(switcherChecked) wifimodel.setPowered(switcherChecked)
...@@ -57,10 +57,9 @@ Component { ...@@ -57,10 +57,9 @@ Component {
model: wifimodel model: wifimodel
delegate: Item { delegate: Item {
width: wifiPanel.width width: wifiPanel.width
height: 40 height: Theme.itemHeightSmall
function getStrengthIndex(strength) { function getStrengthIndex(strength) {
var strengthIndex = "0" var strengthIndex = "0"
if (strength >= 59) { if (strength >= 59) {
strengthIndex = "4" strengthIndex = "4"
} else if (strength >= 55) { } else if (strength >= 55) {
...@@ -73,21 +72,22 @@ Component { ...@@ -73,21 +72,22 @@ Component {
return strengthIndex return strengthIndex
} }
Row { Row {
spacing: 12 spacing: Theme.itemSpacingSmall
Image { Image {
id: statusImage id: statusImage
source: (getStrengthIndex(modelData.strength) === "0")? "image://theme/icon_wifi_0" : "image://theme/icon_wifi_focused" + getStrengthIndex(modelData.strength) source: (getStrengthIndex(modelData.strength) === "0")? "image://theme/icon_wifi_0" : (modelData.state === "online" ? "image://theme/icon_wifi_focused" : "image://theme/icon_wifi_normal")+ getStrengthIndex(modelData.strength)
} }
Label { Label {
anchors{ anchors{
leftMargin: 20 leftMargin: Theme.itemSpacingLarge
verticalCenter: statusImage.verticalCenter verticalCenter: statusImage.verticalCenter
} }
width: root.width width: root.width
font.pointSize: 8 font.pixelSize: Theme.fontSizeMedium
text: modelData.name text: modelData.name
wrapMode: Text.Wrap wrapMode: Text.Wrap
color: modelData.state === "online" ? Theme.accentColor : Theme.textColor
} }
} }
} }
......
...@@ -44,7 +44,10 @@ qml.files = qml/MainScreen.qml \ ...@@ -44,7 +44,10 @@ qml.files = qml/MainScreen.qml \
qml/CommonPanel.qml \ qml/CommonPanel.qml \
qml/ShutdownScreen.qml \ qml/ShutdownScreen.qml \
qml/GlacierRotation.qml \ qml/GlacierRotation.qml \
qml/DeviceLockUI.qml qml/DeviceLockUI.qml \
qml/LauncherItemWrapper.qml \
qml/LauncherItemFolder.qml \
qml/SearchListView.qml
qmlcompositor.path = /usr/share/lipstick-glacier-home-qt5/qml/compositor qmlcompositor.path = /usr/share/lipstick-glacier-home-qt5/qml/compositor
qmlcompositor.files = qml/compositor/WindowWrapperMystic.qml \ qmlcompositor.files = qml/compositor/WindowWrapperMystic.qml \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment