~music-app-dev/music-app/remix

« back to all changes in this revision

Viewing changes to common/ColumnFlow.qml

* Refactor ColumnFlow so that it uses insert/removes instead of resetting the view
* Add search support to MusicAlbums.qml MusicArtists.qml MusicGenres.qml MusicPlaylists.qml MusicTracks.qml MusicaddtoPlaylist.qml
* Remove any references to sheets as they have been removed. Fixes: https://bugs.launchpad.net/bugs/1297253, https://bugs.launchpad.net/bugs/1301893, https://bugs.launchpad.net/bugs/1332877, https://bugs.launchpad.net/bugs/1342928.

Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2014
 
2
 * Copyright (C) 2014, 2015
3
3
 *      Andrew Hayzen <ahayzen@gmail.com>
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
32
32
    property int columnWidth: parent.width / columns
33
33
    property int contentHeight: 0
34
34
    property int count: model === undefined ? 0 : model.count
 
35
    property int delayRebuildIndex: -1
35
36
    property var incubating: ({})  // incubating objects
36
37
    property var items: ({})
37
38
    property var itemToColumn: ({})  // cache of the columns of indexes
38
39
    property int lastIndex: 0  // the furtherest index loaded
 
40
    property bool removing: false
39
41
    property bool restoring: false  // is the view restoring?
40
42
    property var restoreItems: ({})  // when rebuilding items are stored here temporarily
41
43
 
59
61
        }
60
62
    }
61
63
 
62
 
    onCountChanged: {
63
 
        if (!visible) {  // store changes for when visible
64
 
            if (count === 0 && lastIndex > -1) {
65
 
                lastIndex = -1;
66
 
            } else if (lastIndex > -1) {
67
 
                lastIndex = -(lastIndex + 2);  // save the index to restore later
68
 
            }
69
 
        } else if (count === 0) {  // likely the model is been reset so reset the view
70
 
            reset()
71
 
        } else {  // likely new items in the model check if any can be shown
72
 
            append()
73
 
        }
 
64
    onModelChanged: {  // reload the model when it is set
 
65
        reset()
 
66
        append(true, model.count - 1)
74
67
    }
75
68
 
76
69
    onVisibleChanged: {
77
 
        if (columns != columnHeights.length && visible) {  // number of columns has changed while invisible so reset
78
 
            if (!restoring) {
79
 
                rebuildColumns()
80
 
            }
81
 
        } else if (lastIndex < 0 && visible) {  // restore from count change
82
 
            if (lastIndex === -1) {
83
 
                reset()
84
 
            } else {
85
 
                lastIndex = (-lastIndex) - 2
86
 
            }
87
 
 
88
 
            append()
 
70
        if (visible && delayRebuildIndex !== -1) {  // restore from count change
 
71
            if (delayRebuildIndex === 0) {
 
72
                reset()
 
73
            } else {
 
74
                removeIndex(delayRebuildIndex)
 
75
            }
 
76
 
 
77
            delayRebuildIndex = -1
 
78
            append(true)
 
79
        }
 
80
 
 
81
        // number of columns has changed while invisible so reset if not already restoring
 
82
        if (visible && !restoring && columns != columnHeights.length) {
 
83
            rebuildColumns()
 
84
        }
 
85
    }
 
86
 
 
87
    ListModel {  // fakemodel for connections to link to when there is no model
 
88
        id: fakeModel
 
89
    }
 
90
 
 
91
    Connections {
 
92
        target: model === undefined ? fakeModel : model
 
93
        onModelReset: {
 
94
            if (!visible) {
 
95
                delayRebuildIndex = 0
 
96
            } else {
 
97
                reset()
 
98
                append()
 
99
            }
 
100
        }
 
101
        onRowsInserted: {
 
102
            if (!visible) {
 
103
                setDelayRebuildIndex(first)
 
104
            } else {
 
105
                if (first <= lastIndex) {
 
106
                    if (first === 0) {
 
107
                        reset()
 
108
                    } else {
 
109
                        removeIndex(first)  // remove earliest index and all items after
 
110
                    }
 
111
                }
 
112
 
 
113
                // Supply last index if larger as count is not updated until after insertion
 
114
                append(true, last > count ? last : count)
 
115
            }
 
116
        }
 
117
        onRowsRemoved: {
 
118
            if (!visible) {
 
119
                setDelayRebuildIndex(first)
 
120
            } else {
 
121
                if (first <= lastIndex) {
 
122
                    if (first === 0) {
 
123
                        reset()
 
124
                    } else {
 
125
                        removeIndex(first)  // remove earliest index and all items after
 
126
                    }
 
127
 
 
128
                    // count is not updated until after removal, so send insertMax
 
129
                    // insertMax is count - removal region inclusive - 1 (lastIndex is 1 infront)
 
130
 
 
131
                    append(true, count - (1 + last - first) - 1)  // rebuild any items on screen or before
 
132
                }
 
133
            }
 
134
        }
 
135
    }
 
136
 
 
137
 
 
138
    Connections {
 
139
        target: flickable
 
140
        onContentYChanged: {
 
141
            append()  // Append any new items (scrolling down)
 
142
 
 
143
            ensureItemsVisible()
89
144
        }
90
145
    }
91
146
 
92
147
    // Append a new row of items if possible
93
 
    function append()
 
148
    function append(loadBefore, insertMax)
94
149
    {
95
150
        // Do not allow append to run if incubating
96
 
        if (isIncubating() || restoring) {
 
151
        if (isIncubating() || restoring || removing) {
97
152
            return;
98
153
        }
99
154
 
106
161
            var y = columnHeightsMax[columnsByHeight[i]];
107
162
 
108
163
            // build new object in column if possible
109
 
            if (count > 0 && lastIndex < count && inViewport(y, 0)) {
 
164
            // if insertMax is undefined then allow if there is work todo (from the count in the model)
 
165
            // otherwise use the insertMax as the count to compare with the lastIndex added to the columnFlow
 
166
            // and
 
167
            // allow if the y position is within the viewport
 
168
            // or if loadBefore is true then allow if the y position is before the viewport
 
169
            if (((count > 0 && lastIndex < count && insertMax === undefined) || (insertMax !== undefined && lastIndex <= insertMax)) && (inViewport(y, 0) || (loadBefore === true && beforeViewport(y)))) {
110
170
                incubateObject(lastIndex++, columnsByHeight[i], getMaxInColumn(columnsByHeight[i]), append);
111
171
                workDone = true
112
172
            } else {
119
179
        }
120
180
    }
121
181
 
 
182
    // Detect if a loaded object is before the viewport with a buffer
 
183
    function beforeViewport(y)
 
184
    {
 
185
        return y <= flickable.contentY - buffer;
 
186
    }
 
187
 
122
188
    // Cache the size of the columns for use later
123
189
    function cacheColumnHeights()
124
190
    {
319
385
        }
320
386
    }
321
387
 
 
388
    // Remove an index from the model (invalidating anything after)
 
389
    function removeIndex(index)
 
390
    {
 
391
        removing = true
 
392
 
 
393
        forceIncubationCompletion()
 
394
 
 
395
        for (var i in items) {
 
396
            if (i >= index && items.hasOwnProperty(i)) {
 
397
                delete columnHeights[itemToColumn[i]][i]
 
398
                delete itemToColumn[i]
 
399
 
 
400
                items[i].destroy()
 
401
                delete items[i]
 
402
            }
 
403
        }
 
404
 
 
405
        lastIndex = index
 
406
        removing = false
 
407
 
 
408
        cacheColumnHeights()
 
409
    }
 
410
 
322
411
    // Restores existing items into potentially new positions
323
412
    function restoreExisting()
324
413
    {
385
474
 
386
475
        // Reset and rebuild the variables
387
476
        items = ({})
 
477
        itemToColumn = ({})
388
478
        lastIndex = 0
389
479
 
390
480
        columnHeights = []
398
488
        contentHeight = 0
399
489
    }
400
490
 
401
 
    Connections {
402
 
        target: flickable
403
 
        onContentYChanged: {
404
 
            append()  // Append any new items (scrolling down)
405
 
 
406
 
            ensureItemsVisible()
 
491
    function setDelayRebuildIndex(index)
 
492
    {
 
493
        if (delayRebuildIndex === -1 || index < lastIndex) {
 
494
            delayRebuildIndex = index
407
495
        }
408
496
    }
409
497
}