Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let apps toggle an unread counter on app icons #26939

Merged
merged 1 commit into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion apps/files/tests/Controller/ViewControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public function testIndexWithRegularBrowser() {
'icon' => '',
'type' => 'link',
'classes' => '',
'unread' => 0,
],
'recent' => [
'id' => 'recent',
Expand All @@ -189,6 +190,7 @@ public function testIndexWithRegularBrowser() {
'icon' => '',
'type' => 'link',
'classes' => '',
'unread' => 0,
],
'favorites' => [
'id' => 'favorites',
Expand Down Expand Up @@ -247,7 +249,8 @@ public function testIndexWithRegularBrowser() {
],
],
'defaultExpandedState' => false,
'expandedState' => 'show_Quick_Access'
'expandedState' => 'show_Quick_Access',
'unread' => 0,
],
'systemtagsfilter' => [
'id' => 'systemtagsfilter',
Expand All @@ -259,6 +262,7 @@ public function testIndexWithRegularBrowser() {
'icon' => '',
'type' => 'link',
'classes' => '',
'unread' => 0,
],
'trashbin' => [
'id' => 'trashbin',
Expand All @@ -270,6 +274,7 @@ public function testIndexWithRegularBrowser() {
'icon' => '',
'type' => 'link',
'classes' => 'pinned',
'unread' => 0,
],
'shareoverview' => [
'id' => 'shareoverview',
Expand Down Expand Up @@ -320,6 +325,7 @@ public function testIndexWithRegularBrowser() {
'type' => 'link',
'expandedState' => 'show_sharing_menu',
'defaultExpandedState' => false,
'unread' => 0,
]
]);

Expand Down
19 changes: 19 additions & 0 deletions core/css/header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,25 @@ nav[role='navigation'] {
}
}

.unread-counter {
display: none;
}
#apps .app-icon-notification,
#appmenu .app-icon-notification {
fill: var(--color-error);
}

#apps svg:not(.has-unread),
#appmenu svg:not(.has-unread) {
.app-icon-notification-mask {
display: none;
}
.app-icon-notification {
display: none;
}
}


/* Skip navigation links – show only on keyboard focus */
.skip-navigation {
padding: 11px;
Expand Down
2 changes: 1 addition & 1 deletion core/js/dist/main.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion core/js/dist/main.js.map

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions core/src/components/MainMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@ import OC from '../OC'
* If the screen is bigger, the main menu is not a toggle any more.
*/
export const setUp = () => {

Object.assign(OC, {
setNavigationCounter(id, counter) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit undecided on the approach to take here, maybe we should rather listen to an event that might be emitted then by the apps through the event bus?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd advocate against the global variable approach, at least form an app API perspective. We can hide this in yet another @nextcloud/xyz package or add it to an existing one. Then we can also later on change the way this action propagates from an app to the server component.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, then lets keep the OC.setNavigationCounter for use in the additional package then which we then can use for offering a stable API. Unfortunately I don't think we have any fitting package for that already so it would need an additional one.

const appmenuElement = document.getElementById('appmenu').querySelector('[data-id="' + id + '"] svg')
const appsElement = document.getElementById('apps').querySelector('[data-id="' + id + '"] svg')
if (counter === 0) {
appmenuElement.classList.remove('has-unread')
appsElement.classList.remove('has-unread')
appmenuElement.getElementsByTagName('image')[0].style.mask = ''
appsElement.getElementsByTagName('image')[0].style.mask = ''
} else {
appmenuElement.classList.add('has-unread')
appsElement.classList.add('has-unread')
appmenuElement.getElementsByTagName('image')[0].style.mask = 'url(#hole)'
appsElement.getElementsByTagName('image')[0].style.mask = 'url(#hole)'
}
document.getElementById('appmenu').querySelector('[data-id="' + id + '"] .unread-counter').textContent = counter
document.getElementById('apps').querySelector('[data-id="' + id + '"] .unread-counter').textContent = counter
},
})
// init the more-apps menu
OC.registerMenu($('#more-apps > a'), $('#navigation'))

Expand Down
32 changes: 23 additions & 9 deletions core/templates/layout.user.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,18 @@
<a href="<?php print_unescaped($entry['href']); ?>"
<?php if ($entry['active']): ?> class="active"<?php endif; ?>
aria-label="<?php p($entry['name']); ?>">
<svg width="20" height="20" viewBox="0 0 20 20" alt="">
<?php if ($_['themingInvertMenu']) { ?>
<defs><filter id="invertMenuMain-<?php p($entry['id']); ?>"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /></filter></defs>
<?php } ?>
<image x="0" y="0" width="20" height="20" preserveAspectRatio="xMinYMin meet"<?php if ($_['themingInvertMenu']) { ?> filter="url(#invertMenuMain-<?php p($entry['id']); ?>)"<?php } ?> xlink:href="<?php print_unescaped($entry['icon'] . '?v=' . $_['versionHash']); ?>" class="app-icon"></image>
<svg width="24" height="20" viewBox="0 0 24 20" alt=""<?php if ($entry['unread'] !== 0) { ?> class="has-unread"<?php } ?>>
<defs>
<?php if ($_['themingInvertMenu']) { ?><filter id="invertMenuMain-<?php p($entry['id']); ?>"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" /></filter><?php } ?>
<mask id="hole">
<rect width="100%" height="100%" fill="white"/>
<circle r="4.5" cx="21" cy="3" fill="black"/>
</mask>
</defs>
<image x="2" y="0" width="20" height="20" preserveAspectRatio="xMinYMin meet"<?php if ($_['themingInvertMenu']) { ?> filter="url(#invertMenuMain-<?php p($entry['id']); ?>)"<?php } ?> xlink:href="<?php print_unescaped($entry['icon'] . '?v=' . $_['versionHash']); ?>" style="<?php if ($entry['unread'] !== 0) { ?>mask: url("#hole");<?php } ?>" class="app-icon"></image>
<circle class="app-icon-notification" r="3" cx="21" cy="3" fill="red"/>
</svg>
<div class="unread-counter" aria-hidden="true"><?php p($entry['unread']); ?></div>
<span>
<?php p($entry['name']); ?>
</span>
Expand All @@ -87,11 +93,19 @@
<a href="<?php print_unescaped($entry['href']); ?>"
<?php if ($entry['active']): ?> class="active"<?php endif; ?>
aria-label="<?php p($entry['name']); ?>">
<svg width="16" height="16" viewBox="0 0 16 16" alt="">
<defs><filter id="invertMenuMore-<?php p($entry['id']); ?>"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix></filter></defs>
<image x="0" y="0" width="16" height="16" preserveAspectRatio="xMinYMin meet" filter="url(#invertMenuMore-<?php p($entry['id']); ?>)" xlink:href="<?php print_unescaped($entry['icon'] . '?v=' . $_['versionHash']); ?>" class="app-icon"></image>
<svg width="20" height="20" viewBox="0 0 20 20" alt=""<?php if ($entry['unread'] !== 0) { ?> class="has-unread"<?php } ?>>
<defs>
<filter id="invertMenuMore-<?php p($entry['id']); ?>"><feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"></feColorMatrix></filter>
<mask id="hole">
<rect width="100%" height="100%" fill="white"/>
<circle r="4.5" cx="17" cy="3" fill="black"/>
</mask>
</defs>
<image x="0" y="0" width="16" height="16" preserveAspectRatio="xMinYMin meet" filter="url(#invertMenuMore-<?php p($entry['id']); ?>)" xlink:href="<?php print_unescaped($entry['icon'] . '?v=' . $_['versionHash']); ?>" style="<?php if ($entry['unread'] !== 0) { ?>mask: url("#hole");<?php } ?>" class="app-icon"></image>
<circle class="app-icon-notification" r="3" cx="17" cy="3" fill="red"/>
</svg>
<span><?php p($entry['name']); ?></span>
<div class="unread-counter" aria-hidden="true"><?php p($entry['unread']); ?></div>
<span class="app-title"><?php p($entry['name']); ?></span>
</a>
</li>
<?php endforeach; ?>
Expand Down
12 changes: 11 additions & 1 deletion lib/private/NavigationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class NavigationManager implements INavigationManager {
protected $entries = [];
protected $closureEntries = [];
protected $activeEntry;
protected $unreadCounters = [];

/** @var bool */
protected $init = false;
/** @var IAppManager|AppManager */
Expand Down Expand Up @@ -97,7 +99,11 @@ public function add($entry) {
if (!isset($entry['type'])) {
$entry['type'] = 'link';
}
$this->entries[$entry['id']] = $entry;

$id = $entry['id'];
$entry['unread'] = isset($this->unreadCounters[$id]) ? $this->unreadCounters[$id] : 0;

$this->entries[$id] = $entry;
}

/**
Expand Down Expand Up @@ -319,4 +325,8 @@ private function isSubadmin() {
}
return false;
}

public function setUnreadCounter(string $id, int $unreadCounter): void {
$this->unreadCounters[$id] = $unreadCounter;
}
}
Loading