Merge lp:~aacid/unity8/optimize_LVWPH_layout into lp:unity8

Proposed by Albert Astals Cid
Status: Superseded
Proposed branch: lp:~aacid/unity8/optimize_LVWPH_layout
Merge into: lp:unity8
Diff against target: 350 lines (+69/-49)
9 files modified
plugins/Dash/listviewwithpageheader.cpp (+35/-26)
plugins/Dash/listviewwithpageheader.h (+1/-1)
qml/Dash/DashCategoryBase.qml (+3/-11)
qml/Dash/GenericScopeView.qml (+2/-2)
tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp (+2/-2)
tests/plugins/Dash/listviewwithpageheadersectiontest.cpp (+17/-2)
tests/plugins/Dash/listviewwithpageheadertestsection.qml (+3/-2)
tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml (+2/-1)
tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml (+4/-2)
To merge this branch: bzr merge lp:~aacid/unity8/optimize_LVWPH_layout
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
Josh Arenson Approve
Andrea Cimitan Pending
Review via email: mp+289373@code.launchpad.net

This proposal has been superseded by a proposal from 2016-03-24.

Commit message

Don't use context properties but properties of the delegates

This increases a bit the requirements for delegates of the LVWPH but since we control them it's not really a problem.

In ::layout the setContextProperty calls accounted for around 45% according to callgrind, now it's around 10% only.

Description of the change

 * Are there any related MPs required for this MP to build/function as expected?
No

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * Did you make sure that your branch does not contain spurious tags?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

 * If you changed the UI, has there been a design review?
N/A

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2279
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/764/
Executed test runs:
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/423
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial,testname=qmluitests.sh/423
    FAILURE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=phone-armhf,release=vivid+overlay,testname=autopilot.sh/423/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/1005
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1021
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1021
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1019
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1019/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/1019
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/1019/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1019
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1019/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/1019
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/1019/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1019
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1019/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/1019
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/1019/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/764/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Josh Arenson (josharenson) wrote :

* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass?
No, the usual

 * Did you make sure that the branch does not contain spurious tags?
Yes

review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2279
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/822/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/1069
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1087
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1087
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1085
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/1085/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial/1085/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1085
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/1085/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial/1085/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1085
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/1085/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial/1085/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/822/rebuild

review: Needs Fixing (continuous-integration)
2280. By Albert Astals Cid

forgot to adapt this test

2281. By Albert Astals Cid

Merge sectionDelegateResizes

2282. By Albert Astals Cid

Merge

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Dash/listviewwithpageheader.cpp'
2--- plugins/Dash/listviewwithpageheader.cpp 2016-02-05 14:56:32 +0000
3+++ plugins/Dash/listviewwithpageheader.cpp 2016-03-24 10:57:49 +0000
4@@ -97,6 +97,7 @@
5 #include <qqmlengine.h>
6 #pragma GCC diagnostic push
7 #pragma GCC diagnostic ignored "-pedantic"
8+#include <private/qqmlcontext_p.h>
9 #include <private/qqmldelegatemodel_p.h>
10 #include <private/qqmlglobal_p.h>
11 #include <private/qquickitem_p.h>
12@@ -285,7 +286,7 @@
13
14 m_sectionDelegate = delegate;
15
16- m_topSectionItem = getSectionItem(QString());
17+ m_topSectionItem = getSectionItem(QString(), false /*watchGeometry*/);
18 m_topSectionItem->setZ(3);
19 QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
20 connect(m_topSectionItem, &QQuickItem::heightChanged, this, &ListViewWithPageHeader::stickyHeaderHeightChanged);
21@@ -700,8 +701,10 @@
22
23 void ListViewWithPageHeader::releaseItem(ListItem *listItem)
24 {
25- QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(listItem->m_item);
26- itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
27+ QQuickItemPrivate::get(listItem->m_item)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
28+ if (listItem->sectionItem()) {
29+ QQuickItemPrivate::get(listItem->sectionItem())->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
30+ }
31 m_itemsToRelease << listItem;
32 }
33
34@@ -744,14 +747,12 @@
35 return getSectionItem(section);
36 }
37
38-QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText)
39+QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText, bool watchGeometry)
40 {
41 QQuickItem *sectionItem = nullptr;
42
43 QQmlContext *creationContext = m_sectionDelegate->creationContext();
44 QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));
45- context->setContextProperty(QStringLiteral("section"), sectionText);
46- context->setContextProperty(QStringLiteral("delegateIndex"), -1);
47 QObject *nobj = m_sectionDelegate->beginCreate(context);
48 if (nobj) {
49 QQml_setParent_noEvent(context, nobj);
50@@ -759,6 +760,8 @@
51 if (!sectionItem) {
52 delete nobj;
53 } else {
54+ sectionItem->setProperty("text", sectionText);
55+ sectionItem->setProperty("delegateIndex", -1);
56 sectionItem->setZ(2);
57 QQml_setParent_noEvent(sectionItem, m_clipItem);
58 sectionItem->setParentItem(m_clipItem);
59@@ -768,7 +771,9 @@
60 }
61 m_sectionDelegate->completeCreate();
62
63- // TODO attach to sectionItem so we can accomodate to it changing its height
64+ if (watchGeometry) {
65+ QQuickItemPrivate::get(sectionItem)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
66+ }
67
68 return sectionItem;
69 }
70@@ -792,8 +797,7 @@
71 if (!item->sectionItem()) {
72 item->setSectionItem(getSectionItem(sectionText));
73 } else {
74- QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext();
75- context->setContextProperty(QStringLiteral("section"), sectionText);
76+ item->sectionItem()->setProperty("text", sectionText);
77 }
78 } else {
79 if (item->sectionItem()) {
80@@ -914,8 +918,7 @@
81 polish();
82 }
83 if (listItem->sectionItem()) {
84- QQmlContext *context = QQmlEngine::contextForObject(listItem->sectionItem())->parentContext();
85- context->setContextProperty(QStringLiteral("delegateIndex"), modelIndex);
86+ listItem->sectionItem()->setProperty("delegateIndex", modelIndex);
87 }
88 adjustMinYExtent();
89 m_contentHeightDirty = true;
90@@ -939,9 +942,10 @@
91 return;
92
93 item->setParentItem(m_clipItem);
94+ // FIXME Why do we need the refreshExpressions call?
95 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
96- context->setContextProperty(QStringLiteral("ListViewWithPageHeader"), this);
97- context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0));
98+ QQmlContextPrivate::get(context)->data->refreshExpressions();
99+ item->setProperty("heightToClip", QVariant::fromValue<int>(0));
100 if (modelIndex == m_asyncRequestedIndex) {
101 createItem(modelIndex, false);
102 refill();
103@@ -1107,8 +1111,7 @@
104 for (int i = 0; i < m_visibleItems.count(); ++i) {
105 ListItem *item = m_visibleItems[i];
106 if (item->sectionItem()) {
107- QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext();
108- context->setContextProperty(QStringLiteral("delegateIndex"), m_firstVisibleIndex + i);
109+ item->sectionItem()->setProperty("delegateIndex", m_firstVisibleIndex + i);
110 }
111 }
112
113@@ -1126,15 +1129,23 @@
114 }
115 }
116
117-void ListViewWithPageHeader::itemGeometryChanged(QQuickItem * /*item*/, const QRectF &newGeometry, const QRectF &oldGeometry)
118+void ListViewWithPageHeader::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
119 {
120 const qreal heightDiff = newGeometry.height() - oldGeometry.height();
121 if (heightDiff != 0) {
122- if (!m_inContentHeightKeepHeaderShown && oldGeometry.y() + oldGeometry.height() + m_clipItem->y() <= contentY() && !m_visibleItems.isEmpty()) {
123+ if (!m_visibleItems.isEmpty()) {
124 ListItem *firstItem = m_visibleItems.first();
125- firstItem->setY(firstItem->y() - heightDiff);
126- adjustMinYExtent();
127- layout();
128+ const auto prevFirstItemY = firstItem->y();
129+ if (!m_inContentHeightKeepHeaderShown && oldGeometry.y() + oldGeometry.height() + m_clipItem->y() <= contentY()) {
130+ firstItem->setY(firstItem->y() - heightDiff);
131+ } else if (item == firstItem->sectionItem()) {
132+ firstItem->setY(firstItem->y() + heightDiff);
133+ }
134+
135+ if (firstItem->y() != prevFirstItemY) {
136+ adjustMinYExtent();
137+ layout();
138+ }
139 }
140 refill();
141 adjustMinYExtent();
142@@ -1270,8 +1281,7 @@
143 } else {
144 // Update the top sticky section header
145 const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
146- QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();
147- context->setContextProperty(QStringLiteral("section"), section);
148+ m_topSectionItem->setProperty("text", section);
149
150 QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);
151 m_topSectionItem->setY(topSectionStickPos);
152@@ -1283,19 +1293,18 @@
153 break;
154 delegateIndex--;
155 }
156- context->setContextProperty(QStringLiteral("delegateIndex"), delegateIndex);
157+ m_topSectionItem->setProperty("delegateIndex", delegateIndex);
158 if (item->sectionItem()) {
159 QQuickItemPrivate::get(item->sectionItem())->setCulled(true);
160 }
161 }
162 }
163 }
164- QQmlContext *context = QQmlEngine::contextForObject(item->m_item)->parentContext();
165 const qreal clipFrom = visibleFrom + (!item->sectionItem() && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0);
166 if (!cull && pos < clipFrom) {
167- context->setContextProperty(QStringLiteral("heightToClip"), clipFrom - pos);
168+ item->m_item->setProperty("heightToClip", clipFrom - pos);
169 } else {
170- context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0));
171+ item->m_item->setProperty("heightToClip", QVariant::fromValue<int>(0));
172 }
173 // qDebug() << "ListViewWithPageHeader::layout" << item->m_item;
174 pos += item->height();
175
176=== modified file 'plugins/Dash/listviewwithpageheader.h'
177--- plugins/Dash/listviewwithpageheader.h 2016-02-05 14:56:32 +0000
178+++ plugins/Dash/listviewwithpageheader.h 2016-03-24 10:57:49 +0000
179@@ -166,7 +166,7 @@
180 void reallyReleaseItem(ListItem *item);
181 void updateWatchedRoles();
182 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
183- QQuickItem *getSectionItem(const QString &sectionText);
184+ QQuickItem *getSectionItem(const QString &sectionText, bool watchGeometry = true);
185 void updateSectionItem(int modelIndex);
186 void initializeValuesForEmptyList();
187
188
189=== modified file 'qml/Dash/DashCategoryBase.qml'
190--- qml/Dash/DashCategoryBase.qml 2015-07-15 15:07:19 +0000
191+++ qml/Dash/DashCategoryBase.qml 2016-03-24 10:57:49 +0000
192@@ -24,17 +24,9 @@
193 /* Relevant really only for ListViewWithPageHeader case: specify how many pixels we can overlap with the section header */
194 readonly property int allowedOverlap: units.dp(1)
195
196- property real __heightToClip: {
197- // Check this is in position where clipping is needed
198- if (typeof ListViewWithPageHeader !== 'undefined') {
199- if (typeof heightToClip !== 'undefined') {
200- if (heightToClip >= allowedOverlap) {
201- return heightToClip - allowedOverlap;
202- }
203- }
204- }
205- return 0;
206- }
207+ property real heightToClip: 0
208+ readonly property real __heightToClip: heightToClip >= allowedOverlap ? heightToClip - allowedOverlap : 0
209+
210
211 /*!
212 \internal
213
214=== modified file 'qml/Dash/GenericScopeView.qml'
215--- qml/Dash/GenericScopeView.qml 2016-03-14 08:53:26 +0000
216+++ qml/Dash/GenericScopeView.qml 2016-03-24 10:57:49 +0000
217@@ -607,10 +607,10 @@
218 sectionProperty: "name"
219 sectionDelegate: ListItems.Header {
220 objectName: "dashSectionHeader" + (delegate ? delegate.category : "")
221+ property int delegateIndex: -1
222 readonly property var delegate: categoryView.item(delegateIndex)
223 width: categoryView.width
224- height: section != "" ? units.gu(5) : 0
225- text: section
226+ height: text != "" ? units.gu(5) : 0
227 color: scopeStyle ? scopeStyle.foreground : theme.palette.normal.baseText
228 iconName: delegate && delegate.headerLink ? "go-next" : ""
229 onClicked: {
230
231=== modified file 'tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp'
232--- tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp 2015-05-21 15:52:48 +0000
233+++ tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp 2016-03-24 10:57:49 +0000
234@@ -151,12 +151,12 @@
235
236 QString section(QQuickItem *item)
237 {
238- return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
239+ return item ? item->property("text").toString() : QString();
240 }
241
242 int sectionDelegateIndex(QQuickItem *item)
243 {
244- return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
245+ return item ? item->property("delegateIndex").toInt() : -1;
246 }
247
248 private Q_SLOTS:
249
250=== modified file 'tests/plugins/Dash/listviewwithpageheadersectiontest.cpp'
251--- tests/plugins/Dash/listviewwithpageheadersectiontest.cpp 2015-11-26 13:50:56 +0000
252+++ tests/plugins/Dash/listviewwithpageheadersectiontest.cpp 2016-03-24 10:57:49 +0000
253@@ -116,12 +116,12 @@
254
255 QString section(QQuickItem *item) const
256 {
257- return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
258+ return item ? item->property("text").toString() : QString();
259 }
260
261 int sectionDelegateIndex(QQuickItem *item) const
262 {
263- return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
264+ return item ? item->property("delegateIndex").toInt() : -1;
265 }
266
267 private Q_SLOTS:
268@@ -2180,6 +2180,21 @@
269 verifyItem(2, 480., 390., false, "Agressive", false);
270 }
271
272+ void firstItemSectionHeightChange()
273+ {
274+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 1), Q_ARG(QVariant, 5));
275+ model->setProperty(0, "type", "halfheight");
276+ verifyItem(0, 50., 170., false, "halfheight", false);
277+ }
278+
279+ void secondItemSectionHeightChange()
280+ {
281+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 2), Q_ARG(QVariant, 4));
282+ model->setProperty(1, "type", "halfheight");
283+ verifyItem(0, 50., 190., false, "Agressive", false);
284+ verifyItem(1, 240., 220., false, "halfheight", false);
285+ }
286+
287 private:
288 QQuickView *view;
289 ListViewWithPageHeader *lvwph;
290
291=== modified file 'tests/plugins/Dash/listviewwithpageheadertestsection.qml'
292--- tests/plugins/Dash/listviewwithpageheadertestsection.qml 2015-07-15 15:07:19 +0000
293+++ tests/plugins/Dash/listviewwithpageheadertestsection.qml 2016-03-24 10:57:49 +0000
294@@ -97,9 +97,10 @@
295 sectionProperty: "type"
296 sectionDelegate: Component {
297 Rectangle {
298+ property alias text: theText.text
299 color: "green"
300- height: 40
301- Text { text: section; font.pixelSize: 34 }
302+ height: section === "" ? 0 : section != "halfheight" ? 40 : 20;
303+ Text { id: theText; font.pixelSize: 34 }
304 anchors { left: parent.left; right: parent.right }
305 }
306 }
307
308=== modified file 'tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml'
309--- tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml 2015-07-15 15:07:19 +0000
310+++ tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml 2016-03-24 10:57:49 +0000
311@@ -65,9 +65,10 @@
312 sectionProperty: "type"
313 sectionDelegate: Component {
314 Rectangle {
315+ property alias text: theText.text
316 color: "green"
317 height: 40
318- Text { text: section; font.pixelSize: 34 }
319+ Text { id: theText; font.pixelSize: 34 }
320 anchors { left: parent.left; right: parent.right }
321 }
322 }
323
324=== modified file 'tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml'
325--- tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml 2015-07-15 15:07:19 +0000
326+++ tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml 2016-03-24 10:57:49 +0000
327@@ -81,9 +81,10 @@
328 sectionDelegate: Component {
329 id: sectionHeaderComponent
330 Rectangle {
331+ property alias text: theText.text
332 color: "green"
333 height: listView.sectionHeaderHeight
334- Text { text: section; font.pixelSize: 34 }
335+ Text { id: theText; font.pixelSize: 34 }
336 anchors { left: parent.left; right: parent.right }
337 }
338 }
339@@ -92,9 +93,10 @@
340 Component {
341 id: otherSectionHeaderComponent
342 Rectangle {
343+ property alias text: theText.text
344 color: "green"
345 height: 50
346- Text { text: section; font.pixelSize: 34 }
347+ Text { id: theText; font.pixelSize: 34 }
348 anchors { left: parent.left; right: parent.right }
349 }
350 }

Subscribers

People subscribed via source and target branches