Unity 8
ScopesListCategory.qml
1 /*
2  * Copyright (C) 2014,2015 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.4
18 import Ubuntu.Components 1.3
19 import Ubuntu.Components.ListItems 1.3 as ListItems
20 import Dash 0.1
21 import "../Components"
22 
23 Item {
24  id: root
25 
26  property alias model: list.model
27  property alias title: header.text
28  property var scopeStyle
29  property bool editMode: false
30  property bool isFavoritesFeed: false
31  property bool isAlsoInstalled: false
32 
33  visible: !editMode || isFavoritesFeed
34 
35  signal itemDragging(bool dragging, var dragItem)
36  signal requestFavorite(string scopeId, bool favorite)
37  signal requestEditMode()
38  signal requestScopeMoveTo(string scopeId, int index)
39  signal requestActivate(var result)
40  signal requestRestore(string scopeId)
41 
42  implicitHeight: visible ? childrenRect.height : 0
43 
44  DashSectionHeader {
45  id: header
46  width: root.width
47  height: units.gu(5)
48  color: scopeStyle ? scopeStyle.foreground : theme.palette.normal.baseText
49  }
50 
51  readonly property double listItemHeight: units.gu(6)
52 
53  ListView {
54  id: list
55  objectName: "scopesListCategoryInnerList"
56 
57  readonly property double targetHeight: model.count * listItemHeight
58  clip: height != targetHeight
59  height: targetHeight
60  Behavior on height { enabled: visible; UbuntuNumberAnimation { } }
61  width: parent.width
62  interactive: false
63 
64  anchors.top: header.bottom
65  delegate: Loader {
66  id: loader
67  readonly property bool addDropHint: {
68  if (dragMarker.visible) {
69  if (dragItem.originalIndex > index) {
70  return dragMarker.index == index;
71  } else {
72  return dragMarker.index == index - 1;
73  }
74  } else {
75  return false;
76  }
77  }
78  asynchronous: true
79  width: root.width
80  height: listItemHeight + (addDropHint ? units.gu(2) : 0)
81  clip: height < listItemHeight
82  Behavior on height { enabled: visible; UbuntuNumberAnimation { } }
83  sourceComponent: ScopesListCategoryItem {
84  objectName: "delegate" + model.scopeId
85 
86  width: root.width
87  topMargin: height > listItemHeight ? height - listItemHeight : 0
88 
89  icon: model.art || model.mascot || ""
90  text: model.title || ""
91  subtext: model.subtitle || ""
92  showStar: root.isFavoritesFeed || root.isAlsoInstalled
93  isFavorite: root.isFavoritesFeed
94 
95  hideChildren: dragItem.loaderToShrink == loader
96 
97  onClicked: {
98  if (!editMode) {
99  if (root.isFavoritesFeed)
100  root.requestRestore(model.scopeId);
101  else
102  root.requestActivate(result);
103  }
104  }
105  onPressAndHold: {
106  if (!editMode) {
107  root.requestEditMode();
108  }
109  }
110  onRequestFavorite: root.requestFavorite(model.scopeId, favorite);
111  onHandlePressed: {
112  if (editMode) {
113  root.itemDragging(true, dragItem);
114  handle.drag.target = dragItem;
115  handle.drag.maximumX = units.gu(1);
116  handle.drag.minimumX = units.gu(1);
117  handle.drag.minimumY = list.y - dragItem.height / 2;
118  handle.drag.maximumY = list.y + list.height - dragItem.height / 2
119  dragItem.icon = icon;
120  dragItem.text = text;
121  dragItem.subtext = subtext;
122  dragItem.originalY = mapToItem(root, 0, 0).y;
123  dragItem.originalIndex = index;
124  dragItem.y = dragItem.originalY;
125  dragItem.x = units.gu(1);
126  dragItem.visible = true;
127  dragItem.loaderToShrink = loader;
128  }
129  }
130  onHandleReleased: {
131  root.itemDragging(false, dragItem);
132  if (dragItem.visible) {
133  handle.drag.target = undefined;
134  dragItem.visible = false;
135  if (dragMarker.visible && dragMarker.index != index) {
136  root.requestScopeMoveTo(model.scopeId, dragMarker.index);
137  }
138  dragMarker.visible = false;
139  dragItem.loaderToShrink.height = listItemHeight;
140  dragItem.loaderToShrink = null;
141  }
142  }
143  }
144  }
145  }
146 
147  ListItems.ThinDivider {
148  id: dragMarker
149  visible: false
150  anchors {
151  leftMargin: units.gu(1)
152  rightMargin: units.gu(1)
153  }
154  property int index: {
155  var i = Math.round((dragItem.y - list.y + dragItem.height/2) / listItemHeight);
156  if (i < 0) i = 0;
157  if (i >= model.count - 1) i = model.count - 1;
158  return i;
159  }
160  y: list.y + index * listItemHeight + units.gu(1)
161  }
162 
163  ScopesListCategoryItem {
164  id: dragItem
165 
166  property real originalY
167  property int originalIndex
168  property var loaderToShrink: null
169 
170  objectName: "dragItem"
171  visible: false
172  showStar: false
173  width: root.width
174  height: listItemHeight
175  opacity: 0.9
176 
177  onYChanged: {
178  if (!dragMarker.visible && Math.abs(y - originalY) > height / 2) {
179  dragMarker.visible = true;
180  loaderToShrink.height = 0;
181  }
182  }
183  }
184 }