Skip to content

Commit ac168cf

Browse files
ChristophWurstPytal
authored andcommitted
feat(contactsmenu): Show user status
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
1 parent b4e7070 commit ac168cf

21 files changed

Lines changed: 237 additions & 59 deletions

File tree

apps/user_status/appinfo/info.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@
2525
<background-jobs>
2626
<job>OCA\UserStatus\BackgroundJob\ClearOldStatusesBackgroundJob</job>
2727
</background-jobs>
28+
<contactsmenu>
29+
<provider>OCA\UserStatus\ContactsMenu\StatusProvider</provider>
30+
</contactsmenu>
2831
</info>

apps/user_status/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'OCA\\UserStatus\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
1313
'OCA\\UserStatus\\Connector\\UserStatus' => $baseDir . '/../lib/Connector/UserStatus.php',
1414
'OCA\\UserStatus\\Connector\\UserStatusProvider' => $baseDir . '/../lib/Connector/UserStatusProvider.php',
15+
'OCA\\UserStatus\\ContactsMenu\\StatusProvider' => $baseDir . '/../lib/ContactsMenu/StatusProvider.php',
1516
'OCA\\UserStatus\\Controller\\HeartbeatController' => $baseDir . '/../lib/Controller/HeartbeatController.php',
1617
'OCA\\UserStatus\\Controller\\PredefinedStatusController' => $baseDir . '/../lib/Controller/PredefinedStatusController.php',
1718
'OCA\\UserStatus\\Controller\\StatusesController' => $baseDir . '/../lib/Controller/StatusesController.php',

apps/user_status/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ComposerStaticInitUserStatus
2727
'OCA\\UserStatus\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
2828
'OCA\\UserStatus\\Connector\\UserStatus' => __DIR__ . '/..' . '/../lib/Connector/UserStatus.php',
2929
'OCA\\UserStatus\\Connector\\UserStatusProvider' => __DIR__ . '/..' . '/../lib/Connector/UserStatusProvider.php',
30+
'OCA\\UserStatus\\ContactsMenu\\StatusProvider' => __DIR__ . '/..' . '/../lib/ContactsMenu/StatusProvider.php',
3031
'OCA\\UserStatus\\Controller\\HeartbeatController' => __DIR__ . '/..' . '/../lib/Controller/HeartbeatController.php',
3132
'OCA\\UserStatus\\Controller\\PredefinedStatusController' => __DIR__ . '/..' . '/../lib/Controller/PredefinedStatusController.php',
3233
'OCA\\UserStatus\\Controller\\StatusesController' => __DIR__ . '/..' . '/../lib/Controller/StatusesController.php',
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* @copyright 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
7+
*
8+
* @author 2023 Christoph Wurst <christoph@winzerhof-wurst.at>
9+
*
10+
* @license GNU AGPL version 3 or any later version
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU Affero General Public License as
14+
* published by the Free Software Foundation, either version 3 of the
15+
* License, or (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU Affero General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU Affero General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*/
25+
26+
namespace OCA\UserStatus\ContactsMenu;
27+
28+
use OCA\UserStatus\Db\UserStatus;
29+
use OCA\UserStatus\Service\StatusService;
30+
use OCP\Contacts\ContactsMenu\IBulkProvider;
31+
use OCP\Contacts\ContactsMenu\IEntry;
32+
use function array_combine;
33+
use function array_filter;
34+
use function array_map;
35+
36+
class StatusProvider implements IBulkProvider {
37+
38+
public function __construct(private StatusService $statusService) {
39+
}
40+
41+
public function process(array $entries): void {
42+
$uids = array_filter(
43+
array_map(fn (IEntry $entry): ?string => $entry->getProperty('UID'), $entries)
44+
);
45+
46+
$statuses = $this->statusService->findByUserIds($uids);
47+
$indexed = array_combine(
48+
array_map(fn(UserStatus $status) => $status->getUserId(), $statuses),
49+
$statuses
50+
);
51+
52+
foreach ($entries as $entry) {
53+
$uid = $entry->getProperty('UID');
54+
if ($uid !== null && isset($indexed[$uid])) {
55+
$status = $indexed[$uid];
56+
$entry->setStatus(
57+
$status->getStatus(),
58+
$status->getCustomMessage(),
59+
$status->getCustomIcon(),
60+
);
61+
}
62+
}
63+
}
64+
65+
}

core/src/components/ContactsMenu/Contact.vue

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,37 @@
2525
:href="contact.profileUrl"
2626
class="contact__avatar-wrapper">
2727
<NcAvatar class="contact__avatar"
28-
:is-no-user="true"
28+
:size="44"
29+
:user="contact.isUser ? contact.uid : undefined"
30+
:is-no-user="!contact.isUser"
2931
:display-name="contact.avatarLabel"
30-
:url="contact.avatar" />
32+
:url="contact.avatar"
33+
:preloaded-user-status="preloadedUserStatus" />
3134
</a>
3235
<a v-else-if="contact.profileUrl"
3336
:href="contact.profileUrl">
3437
<NcAvatar class="contact__avatar"
35-
:is-no-user="true"
36-
:display-name="contact.avatarLabel" />
38+
:size="44"
39+
:user="contact.isUser ? contact.uid : undefined"
40+
:is-no-user="!contact.isUser"
41+
:display-name="contact.avatarLabel"
42+
:preloaded-user-status="preloadedUserStatus" />
3743
</a>
3844
<NcAvatar v-else
45+
:size="44"
3946
class="contact__avatar"
40-
:is-no-user="true"
47+
:user="contact.isUser ? contact.uid : undefined"
48+
:is-no-user="!contact.isUser"
4149
:display-name="contact.avatarLabel"
42-
:url="contact.avatar" />
50+
:url="contact.avatar"
51+
:preloaded-user-status="preloadedUserStatus" />
4352

4453
<a class="contact__body"
4554
:href="contact.profileUrl || contact.topAction?.hyperlink">
4655
<div class="contact__body__full-name">{{ contact.fullName }}</div>
4756
<div v-if="contact.lastMessage" class="contact__body__last-message">{{ contact.lastMessage }}</div>
48-
<div class="contact__body__email-address">{{ contact.emailAddresses[0] }}</div>
57+
<div v-if="contact.statusMessage" class="contact__body__status-message">{{ contact.statusMessage }}</div>
58+
<div v-else class="contact__body__email-address">{{ contact.emailAddresses[0] }}</div>
4959
</a>
5060
<NcActions v-if="actions.length"
5161
:inline="contact.topAction ? 1 : 0">
@@ -97,6 +107,16 @@ export default {
97107
}
98108
return this.contact.actions
99109
},
110+
preloadedUserStatus() {
111+
if (this.contact.status) {
112+
return {
113+
status: this.contact.status,
114+
message: this.contact.statusMessage,
115+
icon: this.contact.statusIcon,
116+
}
117+
}
118+
return undefined
119+
}
100120
},
101121
}
102122
</script>
@@ -118,28 +138,32 @@ export default {
118138
}
119139
120140
&__avatar-wrapper {
121-
height: 32px;
122141
}
123142
124143
&__avatar {
125-
height: 32px;
126-
width: 32px;
127144
display: inherit;
128145
}
129146
130147
&__body {
131148
flex-grow: 1;
132-
padding-left: 8px;
149+
padding-left: 10px;
133150
min-width: 0;
134151
135152
div {
136153
position: relative;
137154
width: 100%;
138155
overflow-x: hidden;
139156
text-overflow: ellipsis;
157+
margin: -1px 0;
158+
}
159+
div:first-of-type {
160+
margin-top: 0;
161+
}
162+
div:last-of-type {
163+
margin-bottom: 0;
140164
}
141165
142-
.last-message, .email-address {
166+
&__last-message, &__status-message, &__email-address {
143167
color: var(--color-text-maxcontrast);
144168
}
145169
}

core/src/tests/views/ContactsMenu.spec.js

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ describe('ContactsMenu', function() {
139139
emailAddresses: [],
140140
}
141141
],
142-
contactsAppEnabled: false,
142+
contactsAppEnabled: true,
143143
},
144144
})
145145

@@ -149,26 +149,6 @@ describe('ContactsMenu', function() {
149149
expect(view.vm.contacts.length).toBe(2)
150150
expect(view.text()).toContain('Acosta Lancaster')
151151
expect(view.text()).toContain('Adeline Snider')
152-
})
153-
154-
it('shows link ot Contacts', async () => {
155-
const view = shallowMount(ContactsMenu)
156-
axios.post.mockResolvedValue({
157-
data: {
158-
contacts: [
159-
{
160-
id: 1,
161-
},
162-
{
163-
id: 2,
164-
},
165-
],
166-
contactsAppEnabled: true,
167-
},
168-
})
169-
170-
await view.vm.handleOpen()
171-
172-
expect(view.text()).toContain('Show all contacts …')
152+
expect(view.text()).toContain('Show all contacts')
173153
})
174154
})

core/src/views/ContactsMenu.vue

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@
5858
</ul>
5959
</div>
6060
<div v-if="contactsAppEnabled" class="contactsmenu__menu__content__footer">
61-
<a :href="contactsAppURL">{{ t('core', 'Show all contacts') }}</a>
61+
<NcButton type="tertiary" :href="contactsAppURL">{{ t('core', 'Show all contacts') }}</NcButton>
6262
</div>
6363
<div v-else-if="canInstallApp" class="contactsmenu__menu__content__footer">
64-
<a :href="contactsAppMgmtURL">{{ t('core', 'Install the Contacts app') }}</a>
64+
<NcButton type="tertiary" :href="contactsAppMgmtURL">{{ t('core', 'Install the Contacts app') }}</NcButton>
6565
</div>
6666
</div>
6767
</div>
@@ -75,6 +75,7 @@ import debounce from 'debounce'
7575
import { getCurrentUser } from '@nextcloud/auth'
7676
import { generateUrl } from '@nextcloud/router'
7777
import Magnify from 'vue-material-design-icons/Magnify.vue'
78+
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
7879
import NcEmptyContent from '@nextcloud/vue/dist/Components/NcEmptyContent.js'
7980
import NcHeaderMenu from '@nextcloud/vue/dist/Components/NcHeaderMenu.js'
8081
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
@@ -91,6 +92,7 @@ export default {
9192
Contact,
9293
Contacts,
9394
Magnify,
95+
NcButton,
9496
NcEmptyContent,
9597
NcHeaderMenu,
9698
NcLoadingIcon,
@@ -178,14 +180,9 @@ export default {
178180
overflow-y: auto;
179181
180182
&__footer {
181-
text-align: center;
182-
183-
a {
184-
display: block;
185-
width: 100%;
186-
padding: 12px 0;
187-
opacity: .5;
188-
}
183+
display: flex;
184+
flex-direction: column;
185+
align-items: center;
189186
}
190187
}
191188

dist/core-main.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/core-main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-personal-settings.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)