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 @@
//
// Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk>
// 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 QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
......@@ -30,70 +31,270 @@ import QtQuick.Controls.Styles.Nemo 1.0
// App Launcher page
// the place for browsing installed applications and launching them
GridView {
id: gridview
cellWidth: Math.min(parent.width,parent.height)/4
cellHeight: cellWidth + 30
cellWidth: cellSize
cellHeight: cellSize
width: parent.width
cacheBuffer: gridview.contentHeight
property Item reorderItem
property bool onUninstall
property alias deleter: deleter
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
onContentYChanged: {
if( contentY < -140 ) {
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
}
}
}
// just for margin purposes
header: Item {
height: Math.min(parent.width,parent.height)/10
header: SearchListView {
width: gridview.width
}
footer: Item {
height: Math.min(parent.width,parent.height)/10
height: Theme.itemHeightLarge*1.5
}
Item {
Item {//Doesn't yet uninstall applications
id: deleter
anchors.top: parent.top
property alias remove: remove
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
property color color1: "#D9ff0000"
property color color2: "#80ff0000"
property color color3: "#4Dff0000"
property alias text: removeLabel.text
visible: onUninstall
height: 110
color: "red"
visible: gridview.onUninstall
height: Theme.itemHeightExtraLarge
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 {
id: removeLabel
height: parent.height
width: parent.width
anchors.centerIn: parent
text: qsTr("Remove")
font.pointSize: 8
font.pixelSize: Theme.fontSizeLarge
elide:Text.ElideRight
horizontalAlignment:Text.AlignHCenter
verticalAlignment:Text.AlignVCenter
}
}
Rectangle {
id: uninstall
property color color1: "#D9ff0000"
property color color2: "#80ff0000"
property color color3: "#4Dff0000"
property alias text: uninstallLabel.text
anchors.left: remove.right
visible: onUninstall
color: "red"
visible: gridview.onUninstall
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 {
id: uninstallLabel
height: parent.height
width: parent.width
anchors.centerIn: parent
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 }
//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 {
id: launcherItem
width: gridview.cellWidth
height: gridview.cellHeight
iconCaption: model.object.title
isFolder: model.object.type == LauncherModel.Folder
folderAppsCount: isFolder && model.object ? model.object.itemCount : 0
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
Component {
id:app
LauncherItemDelegate {
id: launcherItem
parent: gridview
parentItem: gridview
iconCaption.color:Theme.textColor
iconCaption.text: modelData.object.title
isFolder: modelData.object.type == LauncherModel.Folder
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 @@
// Copyright (c) 2011, Tom Swindell <t.swindell@rubyx.co.uk>
// Copyright (c) 2012, Timur Kristóf <venemo@fedoraproject.org>
import QtQuick 2.2
import QtQuick 2.6
import org.nemomobile.lipstick 0.1
import QtQuick.Controls 1.0
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.glacier 1.0
......@@ -33,7 +34,6 @@ import org.nemomobile.glacier 1.0
Item {
id: switcherRoot
property bool closeMode: false
property bool visibleInHome: false
property alias runningAppsCount: switcherModel.itemCount
......@@ -46,12 +46,34 @@ Item {
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 {
id: flickable
contentHeight: gridview.height
width: closeMode ? parent.width - 20 : parent.width // see comment re right anchor below
MouseArea {
height: flickable.contentHeight > flickable.height ? flickable.contentHeight : flickable.height
width: flickable.width
......@@ -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
import org.nemomobile.lipstick 0.1
import org.nemomobile.devicelock 1.0
import "scripts/desktop.js" as Desktop
Item {
id: root
......@@ -39,6 +41,8 @@ Item {
id: authenticator
onAuthenticated: {
DeviceLock.unlock(authenticationToken)
Desktop.instance.setLockScreen(false)
Desktop.instance.codepadVisible = false
}
onFeedback: {
console.log('### still locked', feedback, attemptsRemaining)
......@@ -47,34 +51,46 @@ Item {
ColumnLayout {
anchors.fill: parent
spacing: 40
spacing: Theme.itemSpacingLarge
TextField {
id: lockCodeField
anchors.horizontalCenter: parent.horizontalCenter
readOnly: true
echoMode: TextInput.PasswordEchoOnEdit
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Theme.fontSizeExtraLarge
}
GridLayout {
height: parent.height
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
columns: 3
Repeater {
model: ["1","2","3","4","5","6","7","8","9","Ca","0","OK"]
delegate:
Button {
style: ButtonStyle {}
Layout.fillWidth: true
text: modelData
height: Theme.itemHeightHuge
width: Theme.itemHeightHuge
Layout.maximumWidth: Theme.itemHeightHuge * 1.5
Layout.maximumHeight: Theme.itemHeightHuge * 1.5
Label {
id: btnLabel
text: modelData
font.pixelSize: Theme.fontSizeExtraLarge * 1.5
anchors {
centerIn: parent
}
}
onClicked: {
if (text !== "Ca" && text !== "OK") {
lockCodeField.insert(lockCodeField.cursorPosition, text)
if (btnLabel.text !== "Ca" && btnLabel.text !== "OK") {
lockCodeField.insert(lockCodeField.cursorPosition, btnLabel.text)
} else {
if (text === "OK") {
if (btnLabel.text === "OK") {
authenticator.enterLockCode(lockCodeField.text)
lockCodeField.text = ""
} else if (text === "Ca"){
} else if (btnLabel.text === "Ca"){
lockCodeField.text = ""
}
}
......
......@@ -33,7 +33,7 @@ import "notifications"
Flickable {
id: mainFlickable
clip: true
contentHeight: rootitem.height
contentWidth: parent.width
Item {
......@@ -43,26 +43,27 @@ Flickable {
// Day of week
Rectangle {
id: daterow
height: displayCurrentDate.height + 15
width: childrenRect.width
height: Theme.itemHeightMedium
width: parent.width
anchors{
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: Theme.itemSpacingLarge
bottomMargin: Theme.itemSpacingLarge
}
color: "transparent"
Label {
id: displayDayOfWeek
text: Qt.formatDateTime(wallClock.time, "dddd") + ", "
color: "white"
font.pointSize: 12
font.bold: true
text: Qt.formatDateTime(wallClock.time, "dddd")
color: Theme.textColor
font.pixelSize: Theme.fontSizeExtraLarge
font.weight: Font.Bold
anchors {
top: parent.top
left: parent.left
topMargin: 30
horizontalCenter: parent.horizontalCenter
}
}
......@@ -70,12 +71,13 @@ Flickable {
Label {
id: displayCurrentDate
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
anchors {
left: displayDayOfWeek.right
top: parent.top
topMargin: 30
horizontalCenter: parent.horizontalCenter
top: displayDayOfWeek.bottom
}
}
}
......@@ -85,9 +87,9 @@ Flickable {
width: parent.width
anchors{
top: daterow.bottom
topMargin: 50
topMargin: Theme.itemSpacingHuge
}
spacing: 10
spacing: Theme.itemSpacingHuge
Repeater {
model: NotificationListModel {
id: notifmodel
......
......@@ -19,11 +19,12 @@
// 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.0
import QtQuick 2.6
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.lipstick 0.1
......@@ -31,15 +32,17 @@ import org.nemomobile.lipstick 0.1
Item {
id: wrapper
property alias source: iconImage.source
property alias iconCaption: iconText.text
property bool reordering
property int newIndex: -1
property real oldY
property alias iconCaption: iconText
property bool reordering: launcherItem.reordering
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()
onYChanged: moveTimer.start()
clip: true
Timer {
id: moveTimer
......@@ -49,230 +52,80 @@ Item {
function moveIcon() {
if (!reordering) {
if (!slideMoveAnim.running) {
slideMoveAnim.start()
if (!launcherItem.slideMoveAnim.running) {
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
// Application icon for the launcher
LauncherItemWrapper {
id: launcherItem
width: wrapper.width
height: wrapper.height
isFolder: wrapper.isFolder
notNemoIcon: wrapper.notNemoIcon
Item {
id: iconWrapper
width: parent.width -parent.width/10
height: width - iconText.height
anchors.centerIn: parent
Image {
id: iconimage
source: model.object.iconId
id: iconImage
anchors {
horizontalCenter: parent.horizontalCenter
// centerIn: launcherItem.n.otNemoIcon ? parent : undefined
horizontalCenter: /* launcherItemnotNemoIcon ? undefined : */parent.horizontalCenter
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
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
MouseArea {
id: launcherItem
width: wrapper.width
height: wrapper.height
parent: gridview.contentItem
scale: reordering ? 1.3 : 1
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
onStatusChanged: {
if (iconImage.status == Image.Error) {
iconImage.source = "/usr/share/lipstick-glacier-home-qt5/qml/theme/default-icon.png"
}
}
}
}
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 }
}
Image {
id: iconImage
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 8
}
width: gridview.cellWidth - gridview.cellWidth/10
height: width
asynchronous: true
Spinner {
id: spinner
id: spinnerr
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 8
centerIn: iconImage
top: iconImage.top
topMargin: Theme.itemSpacingExtraSmall
}
width: gridview.cellWidth - gridview.cellWidth/10
width: iconWrapper.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
Text {
id: iconText
// elide only works if an explicit width is set
width: parent.width
width: iconWrapper.width
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
font.pixelSize: gridview.cellWidth/8
color: 'white'
font.pixelSize: Theme.fontSizeSmall
color: Theme.textColor
anchors {
left: parent.left
right: parent.right
top: iconImage.bottom
topMargin: 5
bottom: parent.bottom
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 {
key: "/home/glacier/lockScreen/wallpaperImage"
defaultValue: "/usr/share/lipstick-glacier-home-qt5/qml/images/graphics-wallpaper-home.jpg"
}
LockscreenClock {
id: clock
anchors {
......@@ -25,6 +24,7 @@ Image {
}
DeviceLockUI {
id: deviceLockUI
visible: false//DeviceLock.state === DeviceLock.Locked
anchors {
top: clock.bottom
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 {
id: lockscreenClock
......@@ -22,10 +25,10 @@ Rectangle {
Text {
id: timeDisplay
font.pointSize: 16
font.pixelSize: Theme.fontSizeExtraLarge * 2
font.weight: Font.Light
lineHeight: 0.85
color: "white"
color: Theme.textColor
horizontalAlignment: Text.AlignHCenter
anchors {
......@@ -35,22 +38,46 @@ Rectangle {
text: Qt.formatDateTime(wallClock.time, "hh:mm")
}
Rectangle {
id: dateRow
height: childrenRect.height
width: weekdayDisplay.width + dateDisplay.width
anchors {
horizontalCenter: parent.horizontalCenter
}
Text {
id: dateDisplay
color: "transparent"
font.pointSize: 14
color: "white"
opacity: 0.8
horizontalAlignment: Text.AlignHCenter
Label {
id: weekdayDisplay
anchors {
left: parent.left
right: parent.right
font.pixelSize: Theme.fontSizeLarge
color: Theme.textColor
horizontalAlignment: Text.AlignHCenter
font.weight: Font.Bold
anchors {
horizontalCenter: parent.horizontalCenter
}
text: Qt.formatDateTime(wallClock.time, "dddd")
}
text: Qt.formatDateTime(wallClock.time, "<b>dddd</b>, d MMMM yyyy")
Label {
id: dateDisplay
font.pixelSize: Theme.fontSizeLarge
color: Theme.textColor
horizontalAlignment: Text.AlignHCenter
font.weight: Font.Light
anchors {
horizontalCenter: parent.horizontalCenter
top: weekdayDisplay.bottom
}
text: Qt.formatDate(wallClock.time, "d MMMM yyyy")
}
}
}
}
......@@ -58,7 +58,10 @@ Page {
id: desktop
property alias lockscreen: lockScreen
property alias switcher: switcher
property alias codepad: codePad
property int statusBarHeight: statusbar.height
property bool codepadVisible: false
// Implements back key navigation
Keys.onReleased: {
......@@ -72,6 +75,7 @@ Page {
Statusbar {
id: statusbar
enabled: DeviceLock.state !== DeviceLock.Locked
}
GlacierRotation {
......@@ -80,7 +84,7 @@ Page {
unrotatedItems: [lockScreen]
}
orientation: Lipstick.compositor.screenOrientation
orientation: DeviceLock.state == DeviceLock.Locked ? nativeOrientation : Lipstick.compositor.screenOrientation
onOrientationChanged: {
if (!lockscreenVisible())
......@@ -142,7 +146,7 @@ Page {
}
// Initial view should be the AppLauncher
currentIndex: 0
//currentIndex: 0
}
Image {
id:wallpaper
......@@ -153,10 +157,21 @@ Page {
}
Lockscreen {
id: lockScreen
visible: DeviceLock.state >= DeviceLock.Locked
visible: lockscreenVisible()//DeviceLock.state == DeviceLock.Locked
width: parent.width
height: parent.height
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,35 +42,67 @@ import "statusbar"
Item {
id: root
z: 201
height: Math.min(parent.width,parent.height)/10
height: Theme.itemHeightLarge
width: parent.width
anchors.bottom: parent.bottom
enabled: !lockscreenVisible()
Rectangle {
id: statusbar
color: "black"
color: Theme.fillDarkColor
anchors.fill: parent
opacity: 0.5
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 {
target: lipstickSettings;
onLockscreenVisibleChanged: {
if(lipstickSettings.lockscreenVisible) {
batteryChargePercentage.subscribe()
batteryIndicator.batteryChargePercentage.subscribe()
cellularSignalBars.subscribe()
cellularRegistrationStatus.subscribe()
cellularNetworkName.subscribe()
cellularDataTechnology.subscribe()
} else {
batteryChargePercentage.unsubscribe()
batteryIndicator.batteryChargePercentage.unsubscribe()
cellularSignalBars.unsubscribe()
cellularRegistrationStatus.unsubscribe()
cellularNetworkName.unsubscribe()
cellularDataTechnology.unsubscribe()
}
}
}
}
ContextProperty {
id: cellularSignalBars
......@@ -131,14 +163,39 @@ Item {
Loader {
id: panel_loader
anchors.bottom: root.top
height: 240
height: 0
width: parent.width
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 {
id:row
anchors.fill: statusbar
spacing: root.height/4
property var currentChild
StatusbarItem {
iconSize: root.height/2
source: (cellularSignalBars.value > 0) ? "image://theme/icon_cell" + cellularSignalBars.value : "image://theme/icon_cell1"
......@@ -196,8 +253,10 @@ Item {
} else if (networkManager.defaultRoute.strength >= 40) {
return "image://theme/icon_wifi_focused1"
} 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 {
return "image://theme/icon_wifi_0"
}
......@@ -224,6 +283,7 @@ Item {
}
StatusbarItem {
iconSize: root.height/2
anchors.verticalCenter: parent.verticalCenter
Label {
id: hours
width: root.height/4
......@@ -242,6 +302,8 @@ Item {
}
}
BatteryIndicator{}
BatteryIndicator{
id:batteryIndicator
}
}
}
......@@ -112,7 +112,7 @@ Compositor {
id: overlayLayer
z: 5
visible: root.appActive
//visible: root.appActive
}
Item {
......@@ -135,7 +135,7 @@ Compositor {
property real lockThreshold: 0.25
property int lockscreenX
property int lockscreenY
enabled: DeviceLock.state != DeviceLock.Locked
enabled: true//!Desktop.instance.codepadVisible//DeviceLock.state != DeviceLock.Locked
onGestureStarted: {
swipeAnimation.stop()
......@@ -144,6 +144,15 @@ Compositor {
if (root.appActive) {
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: {
......@@ -158,27 +167,39 @@ Compositor {
cancelAnimation.start()
}
} else if (root.homeActive){
if (gestureArea.progress >= lockThreshold) {
lockAnimation.valueTo = (gesture == "left" ?
Desktop.instance.lockscreen.width :
-Desktop.instance.lockscreen.width)
lockAnimation.start()
// Locks or unlocks depending if the screen is locked.
if (!Desktop.instance.lockscreenVisible()) {
Desktop.instance.setLockScreen(true)
if (gestureArea.progress >= lockThreshold) {
lockAnimation.valueTo = (gesture == "left" ?
Desktop.instance.lockscreen.width :
-Desktop.instance.lockscreen.width)
lockAnimation.start()
// Locks, unlocks or brings up codepad to enter security code
// Locks
if (!Desktop.instance.lockscreenVisible()) {
Desktop.instance.setLockScreen(true)
}
// 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)
}
} else {
Desktop.instance.setLockScreen(false)
cancelAnimation.start()
}
} else {
cancelAnimation.start()
}
}
}
// States are for the animations that follow your finger during swipes
states: [
// Swipe state is when app is on and you are swiping it to background or closing it
State {
name: "swipe"
when: DeviceLock.state != DeviceLock.Locked
when: !Desktop.instance.codepadVisible
PropertyChanges {
target: gestureArea
delayReset: true
......@@ -190,9 +211,10 @@ Compositor {
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 {
name: "lock"
when: DeviceLock.state == DeviceLock.Locked
when: Desktop.instance.lockscreenVisible()
PropertyChanges {
target: Desktop.instance.lockscreen
visible: true
......@@ -220,6 +242,63 @@ Compositor {
Desktop.instance.lockscreen.height :
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 {
id: valueAnimationLock
target: Desktop.instance.lockscreen
property: "x"
velocity: 1
easing.type: Easing.OutQuint
}
......@@ -305,8 +385,10 @@ Compositor {
}
onDisplayOff:
if (root.topmostAlarmWindow == null)
if (root.topmostAlarmWindow == null) {
Desktop.instance.codepadVisible = false
setCurrentWindow(root.homeWindow)
}
onWindowAdded: {
console.log("Compositor: Window added \"" + window.title + "\"" + " category: " + window.category)
......@@ -316,6 +398,7 @@ Compositor {
var isNotificationWindow = window.category == "notification"
var isOverlayWindow = window.category == "overlay"
var isAlarmWindow = window.category == "alarm"
var isApplicationWindow = window.category == ""
var parent = null
if (window.category == "cover") {
window.visible = false
......@@ -329,10 +412,14 @@ Compositor {
parent = overlayLayer
} else if (isAlarmWindow) {
parent = alarmsLayer
} else if (isApplicationWindow) {
parent = appLayer
} else {
parent = appLayer
}
window.focusOnTouch = !window.isInProcess && !isOverlayWindow && !isNotificationWindow
var w;
if (isOverlayWindow) w = alphaWrapper.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.Styles.Nemo 1.0
......@@ -8,55 +8,115 @@ MouseArea {
height: childrenRect.height
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: {
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 {
id: appIcon
height: 100
height: Theme.itemHeightExtraLarge
width: height
property string defaultIcon: "/usr/share/lipstick-glacier-home-qt5/qml/images/glacier.svg"
anchors{
left: parent.left
leftMargin: 20
leftMargin: Theme.itemSpacingLarge
}
source: {
if (modelData.icon)
return "image://theme/" + modelData.icon
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 {
id: appSummary
text: modelData.summary
width: (rootitem.width-appIcon.width)-40
font.pointSize: 12
font.bold :true
font.capitalization: Font.AllUppercase
width: (rootitem.width-appIcon.width)-Theme.itemSpacingHuge
color: Theme.textColor
font.pixelSize: Theme.fontSizeLarge
//font.bold :true
//font.capitalization: Font.AllUppercase
anchors{
left: appIcon.right
leftMargin: 20
top: parent.top
left: appName.left
top: appName.bottom
topMargin: Theme.itemSpacingSmall
}
wrapMode: Text.Wrap
elide: Text.ElideRight
}
Label {
id: appBody
width: (rootitem.width-appIcon.width)-40
width: (rootitem.width-appIcon.width)-Theme.itemSpacingHuge
text: modelData.body
font.pointSize: 14
color: Theme.textColor
font.pixelSize: Theme.fontSizeMedium
anchors{
left: appSummary.left
left: appName.left
top: appSummary.bottom
}
wrapMode: Text.Wrap
elide: Text.ElideRight
}
}
......@@ -26,6 +26,7 @@ import QtQuick 2.0
import org.nemomobile.lipstick 0.1
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import QtGraphicalEffects 1.0
import "../scripts/desktop.js" as Desktop
......@@ -39,27 +40,12 @@ Item {
rotation: Desktop.instance.parent.rotation
x: Desktop.instance.parent.x
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 {
id: notificationArea
property int notificationHeight: Math.min(parent.width,parent.height)/12
property int notificationMargin: 14
property int notificationIconSize: Math.min(parent.width,parent.height)/12
property int notificationHeight: Theme.itemHeightExtraLarge
property int notificationMargin: Theme.itemSpacingExtraSmall
property int notificationIconSize: Theme.itemHeightMedium
anchors.top: parent.top
anchors.left: parent.left
width: notificationWindow.width
......@@ -67,14 +53,18 @@ Item {
onClicked: if (notificationPreviewPresenter.notification != null) notificationPreviewPresenter.notification.actionInvoked("default")
Rectangle {
id: notificationPreview
anchors {
fill: parent
}
color: "transparent"
radius: 10
gradient: Gradient {
GradientStop { position: 1.0; color: Theme.fillDarkColor }
GradientStop { position: 0; color: "transparent"}
}
opacity: 0
states: [
......@@ -149,13 +139,14 @@ Item {
top: parent.top
left: icon.right
right: parent.right
leftMargin: notificationArea.notificationMargin + 26
topMargin: notificationArea.notificationMargin
leftMargin: notificationArea.notificationMargin*2
rightMargin: notificationArea.notificationMargin
bottomMargin: notificationArea.notificationMargin
//bottomMargin: notificationArea.notificationMargin
}
font.pointSize: 12
font.pixelSize: Theme.fontSizeLarge
text: notificationPreviewPresenter.notification != null ? notificationPreviewPresenter.notification.previewSummary : ""
color: "white"
color: Theme.textColor
clip: true
elide: Text.ElideRight
}
......@@ -168,14 +159,33 @@ Item {
right: summary.right
}
font {
pointSize: 10
pixelSize: Theme.fontSizeMedium
bold: true
}
text: notificationPreviewPresenter.notification != null ? notificationPreviewPresenter.notification.previewBody : ""
color: "white"
color: Theme.textColor
clip: true
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 {
target: notificationPreviewPresenter;
......
......@@ -4,11 +4,17 @@ import org.freedesktop.contextkit 1.0
StatusbarItem {
id: batteryIndicator
property int chargeValue: 0
property alias batteryChargePercentage: batteryChargePercentage
ContextProperty {
id: batteryChargePercentage
key: "Battery.ChargePercentage"
value: "100"
onValueChanged: {
if(batteryStateContextProperty.value != "charging") {
chargeIcon();
}
}
}
ContextProperty {
......@@ -17,7 +23,12 @@ StatusbarItem {
onValueChanged: {
if(batteryStateContextProperty.value == "charging")
{
chargingTimer.start()
if (batteryChargePercentage.value === 100) {
chargingTimer.stop()
chargeIcon()
}else {
chargingTimer.start()
}
}
else
{
......
......@@ -40,7 +40,7 @@ Component {
Label {
text: qsTr("Level")+ ": " + batteryChargePercentage.value + "%"
font.pointSize: 8
font.pixelSize: Theme.fontSizeMedium
anchors.centerIn: parent
}
}
......
......@@ -34,6 +34,7 @@ import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import org.nemomobile.lipstick 0.1
Rectangle {
id: commonPanel
......@@ -41,8 +42,14 @@ Rectangle {
property alias switcherEnabled: columnCheckBox.enabled
property alias switcherChecked: columnCheckBox.checked
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
color: "transparent"
......@@ -50,6 +57,20 @@ Rectangle {
anchors.fill: parent
color: "#313131"
opacity: 0.3
}
InverseMouseArea {
anchors.fill: parent
enabled: parent.visible
onPressed: {
parent.click()
}
}
MouseArea {
id:mouseArea
anchors.fill:parent
onClicked: parent.click()
}
clip: true
......@@ -60,7 +81,7 @@ Rectangle {
id: actionColumn
anchors{
top: commonPanel.top
topMargin: 20
topMargin: Theme.itemSpacingLarge
}
width: parent.width
Label{
......@@ -68,7 +89,7 @@ Rectangle {
text: name
anchors{
left: actionColumn.left
leftMargin: 20
leftMargin: Theme.itemSpacingLarge
}
wrapMode: Text.Wrap
font.pointSize: 8
......@@ -81,7 +102,7 @@ Rectangle {
visible: enabled
anchors{
right: actionColumn.right
rightMargin: 20
rightMargin: Theme.itemSpacingLarge
verticalCenter: nameLabel.verticalCenter
}
}
......@@ -89,12 +110,54 @@ Rectangle {
Column{
id: dataColumn
width: parent.width-40
width: parent.width-settingsIcon.width
anchors{
left: parent.left
leftMargin: 20
leftMargin: Theme.itemSpacingLarge
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 {
anchors.fill: simpanel
spacing: 0
RowLayout {
spacing: 16
spacing: Theme.itemSpacingMedium
TextField {
id: pinquery
width: 140
......@@ -138,7 +138,7 @@ Component {
Label {
visible: !needsPin
text: qsTr("No pin required!")
font.pointSize: 16
font.pixelSize:Theme.fontSizeMedium
anchors.centerIn: parent
}
}
......
......@@ -3,28 +3,41 @@ import QtQuick.Layouts 1.0
Item {
property alias source: icon.source
property alias pressed: mouse.pressed
property string panel_source
property Component panel
property double iconSize
Layout.fillWidth: true
Layout.fillHeight: true
function clicked() {
if (panel_source !== "" && !panel) {
panel_loader.source = panel_source
panel_loader.visible = !panel_loader.visible
}
if (panel && panel_source === "") {
panel_loader.sourceComponent = panel
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 {
width: iconSize
fillMode: Image.PreserveAspectFit
height: iconSize
id: icon
anchors.centerIn: parent
}
MouseArea {
id:mouse
anchors.fill: parent
onClicked: {
if (panel_source !== "" && !panel) {
panel_loader.source = panel_source
panel_loader.visible = !panel_loader.visible
}
if (panel && panel_source === "") {
panel_loader.sourceComponent = panel
panel_loader.visible = !panel_loader.visible
}
}
enabled: !lockscreenVisible()
onClicked: parent.clicked()
}
}
......@@ -30,7 +30,7 @@
**
****************************************************************************************/
import QtQuick 2.1
import QtQuick 2.6
import QtQuick.Controls.Nemo 1.0
import QtQuick.Controls.Styles.Nemo 1.0
import MeeGo.Connman 0.2
......@@ -40,7 +40,7 @@ Component {
id: wifiPanel
name: "Wifi"
switcherEnabled: true
switcherChecked: true
switcherChecked: wifimodel.powered
onSwitcherCheckedChanged: {
wifimodel.setPowered(switcherChecked)
......@@ -57,10 +57,9 @@ Component {
model: wifimodel
delegate: Item {
width: wifiPanel.width
height: 40
height: Theme.itemHeightSmall
function getStrengthIndex(strength) {
var strengthIndex = "0"
if (strength >= 59) {
strengthIndex = "4"
} else if (strength >= 55) {
......@@ -73,21 +72,22 @@ Component {
return strengthIndex
}
Row {
spacing: 12
spacing: Theme.itemSpacingSmall
Image {
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 {
anchors{
leftMargin: 20
leftMargin: Theme.itemSpacingLarge
verticalCenter: statusImage.verticalCenter
}
width: root.width
font.pointSize: 8
font.pixelSize: Theme.fontSizeMedium
text: modelData.name
wrapMode: Text.Wrap
color: modelData.state === "online" ? Theme.accentColor : Theme.textColor
}
}
}
......
......@@ -44,7 +44,10 @@ qml.files = qml/MainScreen.qml \
qml/CommonPanel.qml \
qml/ShutdownScreen.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.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