Skip to content

Commit 823fe5d

Browse files
authored
Initial run of disabling and enabling activity bar badges (microsoft#158781)
* Initial run of disabling and enabling activity bar badges * Activity Badge -> Badge
1 parent 8f047c0 commit 823fe5d

File tree

5 files changed

+140
-27
lines changed

5 files changed

+140
-27
lines changed

src/vs/workbench/browser/parts/activitybar/activitybarActions.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
1616
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
1717
import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
1818
import { IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
19-
import { ActivityAction, ActivityActionViewItem, IActivityActionViewItemOptions, IActivityHoverOptions, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
19+
import { ActivityAction, ActivityActionViewItem, IActivityActionViewItemOptions, IActivityHoverOptions, ICompositeBar, ICompositeBarColors, ToggleCompositeBadgeAction, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
2020
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
2121
import { IActivity } from 'vs/workbench/common/activity';
2222
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_PROFILE_BACKGROUND, ACTIVITY_BAR_PROFILE_HOVER_FOREGROUND } from 'vs/workbench/common/theme';
@@ -126,7 +126,7 @@ abstract class AbstractGlobalActivityActionViewItem extends ActivityActionViewIt
126126
@IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService,
127127
@IKeybindingService keybindingService: IKeybindingService,
128128
) {
129-
super(action, options, themeService, hoverService, configurationService, keybindingService);
129+
super(action, options, () => true, themeService, hoverService, configurationService, keybindingService);
130130
}
131131

132132
override render(container: HTMLElement): void {
@@ -419,6 +419,17 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne
419419
}
420420
}
421421

422+
export class PlaceHolderToggleCompositeBadgeAction extends ToggleCompositeBadgeAction {
423+
424+
constructor(id: string, compositeBar: ICompositeBar) {
425+
super({ id, name: id, cssClass: undefined }, compositeBar);
426+
}
427+
428+
setActivity(activity: IActivity): void {
429+
this.label = activity.name;
430+
}
431+
}
432+
422433
class SwitchSideBarViewAction extends Action2 {
423434

424435
constructor(

src/vs/workbench/browser/parts/activitybar/activitybarPart.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
88
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
99
import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIVITY_ID } from 'vs/workbench/common/activity';
1010
import { Part } from 'vs/workbench/browser/part';
11-
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActivityActionViewItem, ProfilesActivityActionViewItem, IProfileActivity } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
11+
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActivityActionViewItem, ProfilesActivityActionViewItem, IProfileActivity, PlaceHolderToggleCompositeBadgeAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
1212
import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
1313
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
1414
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -23,7 +23,7 @@ import { Dimension, createCSSRule, asCSSUrl, addDisposableListener, EventType, i
2323
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
2424
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
2525
import { URI, UriComponents } from 'vs/base/common/uri';
26-
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity, IActivityHoverOptions } from 'vs/workbench/browser/parts/compositeBarActions';
26+
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity, IActivityHoverOptions, ToggleCompositeBadgeAction } from 'vs/workbench/browser/parts/compositeBarActions';
2727
import { IViewDescriptorService, ViewContainer, IViewContainerModel, ViewContainerLocation } from 'vs/workbench/common/views';
2828
import { getEnabledViewContainerContextKey } from 'vs/workbench/common/contextkeys';
2929
import { IContextKeyService, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey';
@@ -58,6 +58,7 @@ interface IPlaceholderViewContainer {
5858
interface IPinnedViewContainer {
5959
readonly id: string;
6060
readonly pinned: boolean;
61+
readonly badgeEnabled: boolean;
6162
readonly order?: number;
6263
readonly visible: boolean;
6364
}
@@ -67,6 +68,7 @@ interface ICachedViewContainer {
6768
name?: string;
6869
icon?: URI | ThemeIcon;
6970
readonly pinned: boolean;
71+
readonly badgeEnabled: boolean;
7072
readonly order?: number;
7173
visible: boolean;
7274
isBuiltin?: boolean;
@@ -112,7 +114,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
112114

113115
private readonly accountsActivity: ICompositeActivity[] = [];
114116

115-
private readonly compositeActions = new Map<string, { activityAction: ViewContainerActivityAction; pinnedAction: ToggleCompositePinnedAction }>();
117+
private readonly compositeActions = new Map<string, { activityAction: ViewContainerActivityAction; pinnedAction: ToggleCompositePinnedAction; badgeAction: ToggleCompositeBadgeAction }>();
116118
private readonly viewContainerDisposables = new Map<string, IDisposable>();
117119

118120
private readonly keyboardNavigationDisposables = this._register(new DisposableStore());
@@ -156,7 +158,8 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
156158
name: container.name,
157159
visible: container.visible,
158160
order: container.order,
159-
pinned: container.pinned
161+
badgeEnabled: container.badgeEnabled,
162+
pinned: container.pinned,
160163
}));
161164

162165
return this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, {
@@ -169,6 +172,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
169172
},
170173
getActivityAction: compositeId => this.getCompositeActions(compositeId).activityAction,
171174
getCompositePinnedAction: compositeId => this.getCompositeActions(compositeId).pinnedAction,
175+
getCompositeBadgeAction: compositeId => this.getCompositeActions(compositeId).badgeAction,
172176
getOnCompositeClickAction: compositeId => toAction({ id: compositeId, label: '', run: async () => this.paneCompositePart.getActivePaneComposite()?.getId() === compositeId ? this.paneCompositePart.hideActivePaneComposite() : this.paneCompositePart.openPaneComposite(compositeId) }),
173177
fillExtraContextMenuActions: (actions, e?: MouseEvent | GestureEvent) => {
174178
// Menu
@@ -623,21 +627,23 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
623627
};
624628
}
625629

626-
private getCompositeActions(compositeId: string): { activityAction: ViewContainerActivityAction; pinnedAction: ToggleCompositePinnedAction } {
630+
private getCompositeActions(compositeId: string): { activityAction: ViewContainerActivityAction; pinnedAction: ToggleCompositePinnedAction; badgeAction: ToggleCompositeBadgeAction } {
627631
let compositeActions = this.compositeActions.get(compositeId);
628632
if (!compositeActions) {
629633
const viewContainer = this.getViewContainer(compositeId);
630634
if (viewContainer) {
631635
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
632636
compositeActions = {
633637
activityAction: this.instantiationService.createInstance(ViewContainerActivityAction, this.toActivity(viewContainerModel), this.paneCompositePart),
634-
pinnedAction: new ToggleCompositePinnedAction(this.toActivity(viewContainerModel), this.compositeBar)
638+
pinnedAction: new ToggleCompositePinnedAction(this.toActivity(viewContainerModel), this.compositeBar),
639+
badgeAction: new ToggleCompositeBadgeAction(this.toActivity(viewContainerModel), this.compositeBar)
635640
};
636641
} else {
637642
const cachedComposite = this.cachedViewContainers.filter(c => c.id === compositeId)[0];
638643
compositeActions = {
639644
activityAction: this.instantiationService.createInstance(PlaceHolderViewContainerActivityAction, ActivitybarPart.toActivity(compositeId, compositeId, cachedComposite?.icon, undefined), this.paneCompositePart),
640-
pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar)
645+
pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar),
646+
badgeAction: new PlaceHolderToggleCompositeBadgeAction(compositeId, this.compositeBar)
641647
};
642648
}
643649

@@ -887,6 +893,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
887893
id: cachedViewContainer.id,
888894
name: cachedViewContainer.name,
889895
order: cachedViewContainer.order,
896+
badgeEnabled: cachedViewContainer.badgeEnabled,
890897
pinned: cachedViewContainer.pinned,
891898
visible: !!compositeItems.find(({ id }) => id === cachedViewContainer.id)
892899
});
@@ -934,12 +941,13 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
934941
icon: URI.isUri(viewContainerModel.icon) && this.environmentService.remoteAuthority ? undefined : viewContainerModel.icon, /* Donot cache uri icons with remote connection */
935942
views,
936943
pinned: compositeItem.pinned,
944+
badgeEnabled: compositeItem.badgeEnabled,
937945
order: compositeItem.order,
938946
visible: compositeItem.visible,
939947
isBuiltin: !viewContainer.extensionId
940948
});
941949
} else {
942-
state.push({ id: compositeItem.id, pinned: compositeItem.pinned, order: compositeItem.order, visible: false, isBuiltin: false });
950+
state.push({ id: compositeItem.id, pinned: compositeItem.pinned, badgeEnabled: compositeItem.badgeEnabled, order: compositeItem.order, visible: false, isBuiltin: false });
943951
}
944952
}
945953

src/vs/workbench/browser/parts/compositeBar.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface ICompositeBarItem {
3030

3131
name?: string;
3232
pinned: boolean;
33+
badgeEnabled: boolean;
3334
order?: number;
3435
visible: boolean;
3536
}
@@ -152,6 +153,7 @@ export interface ICompositeBarOptions {
152153

153154
readonly getActivityAction: (compositeId: string) => ActivityAction;
154155
readonly getCompositePinnedAction: (compositeId: string) => IAction;
156+
readonly getCompositeBadgeAction: (compositeId: string) => IAction;
155157
readonly getOnCompositeClickAction: (compositeId: string) => IAction;
156158
readonly fillExtraContextMenuActions: (actions: IAction[], e?: MouseEvent | GestureEvent) => void;
157159
readonly getContextMenuActionsForComposite: (compositeId: string) => IAction[];
@@ -222,6 +224,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
222224
{ draggable: true, colors: this.options.colors, icon: this.options.icon, hoverOptions: this.options.activityHoverOptions },
223225
action as ActivityAction,
224226
item.pinnedAction,
227+
item.toggleBadgeAction,
225228
compositeId => this.options.getContextMenuActionsForComposite(compositeId),
226229
() => this.getContextMenuActions(),
227230
this.options.dndHandler,
@@ -410,6 +413,27 @@ export class CompositeBar extends Widget implements ICompositeBar {
410413
}
411414
}
412415

416+
areBadgesEnabled(compositeId: string): boolean {
417+
const item = this.model?.findItem(compositeId);
418+
// Old restored views can have undefined badge enablement
419+
if (item && item.badgeEnabled === undefined) {
420+
item.badgeEnabled = true;
421+
}
422+
return item?.badgeEnabled;
423+
}
424+
425+
toggleBadgeEnablement(compositeId: string): void {
426+
if (this.model.setBadgeEnablement(compositeId, !this.areBadgesEnabled(compositeId))) {
427+
this.updateCompositeSwitcher();
428+
const item = this.model.findItem(compositeId);
429+
if (item) {
430+
// TODO @lramos15 how do we tell the activity to re-render the badge? This triggers an onDidChange but isn't the right way to do it.
431+
// I could add another specific function like `activity.updateBadgeEnablement` would then the activity store the sate?
432+
item.activityAction.setBadge(item.activityAction.getBadge(), item.activityAction.getClass());
433+
}
434+
}
435+
}
436+
413437
private resetActiveComposite(compositeId: string) {
414438
const defaultCompositeId = this.options.getDefaultCompositeId();
415439

@@ -668,6 +692,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
668692
interface ICompositeBarModelItem extends ICompositeBarItem {
669693
readonly activityAction: ActivityAction;
670694
readonly pinnedAction: IAction;
695+
readonly toggleBadgeAction: IAction;
671696
readonly activity: ICompositeActivity[];
672697
}
673698

@@ -692,7 +717,7 @@ class CompositeBarModel {
692717
const result: ICompositeBarModelItem[] = [];
693718
let hasChanges: boolean = false;
694719
if (!this.items || this.items.length === 0) {
695-
this._items = items.map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.visible));
720+
this._items = items.map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.badgeEnabled, i.visible));
696721
hasChanges = true;
697722
} else {
698723
const existingItems = this.items;
@@ -711,7 +736,7 @@ class CompositeBarModel {
711736
result.push(existingItem);
712737
}
713738
} else {
714-
result.push(this.createCompositeBarItem(newItem.id, newItem.name, newItem.order, newItem.pinned, newItem.visible));
739+
result.push(this.createCompositeBarItem(newItem.id, newItem.name, newItem.order, newItem.pinned, newItem.badgeEnabled, newItem.visible));
715740
hasChanges = true;
716741
}
717742
}
@@ -729,16 +754,19 @@ class CompositeBarModel {
729754
return this.items.filter(item => item.visible && item.pinned);
730755
}
731756

732-
private createCompositeBarItem(id: string, name: string | undefined, order: number | undefined, pinned: boolean, visible: boolean): ICompositeBarModelItem {
757+
private createCompositeBarItem(id: string, name: string | undefined, order: number | undefined, pinned: boolean, badgeEnabled: boolean, visible: boolean): ICompositeBarModelItem {
733758
const options = this.options;
734759
return {
735-
id, name, pinned, order, visible,
760+
id, name, pinned, order, visible, badgeEnabled,
736761
activity: [],
737762
get activityAction() {
738763
return options.getActivityAction(id);
739764
},
740765
get pinnedAction() {
741766
return options.getCompositePinnedAction(id);
767+
},
768+
get toggleBadgeAction() {
769+
return options.getCompositeBadgeAction(id);
742770
}
743771
};
744772
}
@@ -759,7 +787,7 @@ class CompositeBarModel {
759787

760788
return changed;
761789
} else {
762-
const item = this.createCompositeBarItem(id, name, order, true, true);
790+
const item = this.createCompositeBarItem(id, name, order, true, true, true);
763791
if (!isUndefinedOrNull(requestedIndex)) {
764792
let index = 0;
765793
let rIndex = requestedIndex;
@@ -839,6 +867,19 @@ class CompositeBarModel {
839867
return false;
840868
}
841869

870+
setBadgeEnablement(id: string, isEnabled: boolean): boolean {
871+
for (const item of this.items) {
872+
if (item.id === id) {
873+
if (item.badgeEnabled !== isEnabled) {
874+
item.badgeEnabled = isEnabled;
875+
return true;
876+
}
877+
return false;
878+
}
879+
}
880+
return false;
881+
}
882+
842883
addActivity(id: string, activity: ICompositeActivity): boolean {
843884
const item = this.findItem(id);
844885
if (item) {

src/vs/workbench/browser/parts/compositeBarActions.ts

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ export interface ICompositeBar {
4949
*/
5050
isPinned(compositeId: string): boolean;
5151

52+
/**
53+
* Returns if badges are enabled for that specified composite.
54+
* @param compositeId The id of the composite to check
55+
*/
56+
areBadgesEnabled(compositeId: string): boolean;
57+
58+
/**
59+
* Toggles whether or not badges are shown on that particular composite.
60+
* @param compositeId The composite to toggle badge enablement for
61+
*/
62+
toggleBadgeEnablement(compositeId: string): void;
63+
5264
/**
5365
* Reorder composite ordering by moving a composite to the location of another composite.
5466
*/
@@ -160,6 +172,7 @@ export class ActivityActionViewItem extends BaseActionViewItem {
160172
constructor(
161173
action: ActivityAction,
162174
options: IActivityActionViewItemOptions,
175+
private readonly badgesEnabled: (compositeId: string) => boolean,
163176
@IThemeService protected readonly themeService: IThemeService,
164177
@IHoverService private readonly hoverService: IHoverService,
165178
@IConfigurationService protected readonly configurationService: IConfigurationService,
@@ -293,7 +306,9 @@ export class ActivityActionViewItem extends BaseActionViewItem {
293306
clearNode(this.badgeContent);
294307
hide(this.badge);
295308

296-
if (badge) {
309+
const shouldRenderBadges = this.badgesEnabled(this.activity.id);
310+
311+
if (badge && shouldRenderBadges) {
297312

298313
// Number
299314
if (badge instanceof NumberBadge) {
@@ -475,7 +490,7 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI
475490
@IConfigurationService configurationService: IConfigurationService,
476491
@IKeybindingService keybindingService: IKeybindingService,
477492
) {
478-
super(action, { icon: true, colors, hasPopup: true, hoverOptions }, themeService, hoverService, configurationService, keybindingService);
493+
super(action, { icon: true, colors, hasPopup: true, hoverOptions }, () => true, themeService, hoverService, configurationService, keybindingService);
479494
}
480495

481496
showMenu(): void {
@@ -546,6 +561,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
546561
options: IActivityActionViewItemOptions,
547562
private readonly compositeActivityAction: ActivityAction,
548563
private readonly toggleCompositePinnedAction: IAction,
564+
private readonly toggleCompositeBadgeAction: IAction,
549565
private readonly compositeContextMenuActionsProvider: (compositeId: string) => IAction[],
550566
private readonly contextMenuActionsProvider: () => IAction[],
551567
private readonly dndHandler: ICompositeDragAndDrop,
@@ -557,7 +573,15 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
557573
@IHoverService hoverService: IHoverService,
558574
@IConfigurationService configurationService: IConfigurationService,
559575
) {
560-
super(compositeActivityAction, options, themeService, hoverService, configurationService, keybindingService);
576+
super(
577+
compositeActivityAction,
578+
options,
579+
compositeBar.areBadgesEnabled.bind(compositeBar),
580+
themeService,
581+
hoverService,
582+
configurationService,
583+
keybindingService
584+
);
561585

562586
if (!CompositeActionViewItem.manageExtensionAction) {
563587
CompositeActionViewItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
@@ -657,7 +681,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
657681
}
658682

659683
private showContextMenu(container: HTMLElement): void {
660-
const actions: IAction[] = [this.toggleCompositePinnedAction];
684+
const actions: IAction[] = [this.toggleCompositePinnedAction, this.toggleCompositeBadgeAction];
661685

662686
const compositeContextMenuActions = this.compositeContextMenuActionsProvider(this.activity.id);
663687
if (compositeContextMenuActions.length) {
@@ -677,6 +701,13 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
677701
this.toggleCompositePinnedAction.label = localize('keep', "Keep '{0}'", this.activity.name);
678702
}
679703

704+
const isBadgeEnabled = this.compositeBar.areBadgesEnabled(this.activity.id);
705+
if (isBadgeEnabled) {
706+
this.toggleCompositeBadgeAction.label = localize('hideBadge', "Hide Badge");
707+
} else {
708+
this.toggleCompositeBadgeAction.label = localize('showBadge', "Show Badge");
709+
}
710+
680711
const otherActions = this.contextMenuActionsProvider();
681712
if (otherActions.length) {
682713
actions.push(new Separator());
@@ -752,3 +783,19 @@ export class ToggleCompositePinnedAction extends Action {
752783
}
753784
}
754785
}
786+
787+
export class ToggleCompositeBadgeAction extends Action {
788+
constructor(
789+
private activity: IActivity | undefined,
790+
private compositeBar: ICompositeBar
791+
) {
792+
super('show.toggleCompositeBadge', activity ? activity.name : localize('toggleBadge', "Toggle View Badge"));
793+
794+
this.checked = false;
795+
}
796+
797+
override async run(context: string): Promise<void> {
798+
const id = this.activity ? this.activity.id : context;
799+
this.compositeBar.toggleBadgeEnablement(id);
800+
}
801+
}

0 commit comments

Comments
 (0)