feat(focus-mode): show flowtime and countdown timer in browser tab ti… (#7640)

* feat(focus-mode): show flowtime and countdown timer in browser tab title and removes app name during timer

* fix(focus-mode): correct flowtime break browser title behavior
This commit is contained in:
Het Savani 2026-05-19 18:31:09 +05:30 committed by GitHub
parent 71787a199f
commit fb0f4bc747
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 106 additions and 28 deletions

View file

@ -56,7 +56,7 @@ describe('BrowserTitleService', () => {
});
describe('_getTitle', () => {
it('should return base title when not in Pomodoro mode', () => {
it('should show elapsed time for Flowtime mode when running', () => {
const result = (service as any)._getTitle(
FocusModeMode.Flowtime,
1500000,
@ -64,10 +64,80 @@ describe('BrowserTitleService', () => {
true,
false,
false,
30000,
);
expect(result).toBe('00:30');
});
it('should show "Paused" for Flowtime mode when paused and time has elapsed', () => {
const result = (service as any)._getTitle(
FocusModeMode.Flowtime,
0,
false,
false,
true,
false,
120000,
);
expect(result).toBe('Paused 02:00');
});
it('should show remaining time for Flowtime break offer (not running, zero elapsed)', () => {
const result = (service as any)._getTitle(
FocusModeMode.Flowtime,
300000,
true,
false,
true,
false,
0,
);
expect(result).toBe('Super Productivity');
expect(result).toBe('05:00 (Break)');
});
it('should show remaining time for active Flowtime break', () => {
const result = (service as any)._getTitle(
FocusModeMode.Flowtime,
270000,
true,
true,
false,
false,
30000,
);
expect(result).toBe('04:30 (Break)');
});
it('should show "Paused" and remaining time for paused Flowtime break', () => {
const result = (service as any)._getTitle(
FocusModeMode.Flowtime,
270000,
true,
false,
true,
false,
30000,
);
expect(result).toBe('Paused 04:30 (Break)');
});
it('should show remaining time for Countdown mode when running', () => {
const result = (service as any)._getTitle(
FocusModeMode.Countdown,
600000,
false,
true,
false,
false,
0,
);
expect(result).toBe('10:00');
});
it('should return base title when in Pomodoro but not running or paused', () => {
@ -95,7 +165,7 @@ describe('BrowserTitleService', () => {
0,
);
expect(result).toBe('(25:00) Super Productivity');
expect(result).toBe('25:00');
});
it('should show "Paused" when paused', () => {
@ -109,7 +179,7 @@ describe('BrowserTitleService', () => {
0,
);
expect(result).toBe('(Paused 25:00) Super Productivity');
expect(result).toBe('Paused 25:00');
});
it('should show "Break" when break is active', () => {
@ -123,10 +193,10 @@ describe('BrowserTitleService', () => {
0,
);
expect(result).toBe('(05:00 Break) Super Productivity');
expect(result).toBe('05:00 (Break)');
});
it('should show both "Paused" and "Break" when both are active', () => {
it('should show both "Paused" and "Break" when both are active and time elapsed', () => {
const result = (service as any)._getTitle(
FocusModeMode.Pomodoro,
300000,
@ -134,10 +204,10 @@ describe('BrowserTitleService', () => {
false,
true,
false,
0,
1000,
);
expect(result).toBe('(Paused 05:00 Break) Super Productivity');
expect(result).toBe('Paused 05:00 (Break)');
});
it('should show elapsed time during overtime', () => {
@ -151,7 +221,7 @@ describe('BrowserTitleService', () => {
1560000,
);
expect(result).toBe('(26:00) Super Productivity');
expect(result).toBe('26:00');
});
it('should show elapsed break time during overtime', () => {
@ -165,7 +235,7 @@ describe('BrowserTitleService', () => {
360000,
);
expect(result).toBe('(06:00 Break) Super Productivity');
expect(result).toBe('06:00 (Break)');
});
it('should pad single digit minutes correctly', () => {
@ -179,7 +249,7 @@ describe('BrowserTitleService', () => {
0,
);
expect(result).toBe('(05:00) Super Productivity');
expect(result).toBe('05:00');
});
});
@ -190,25 +260,22 @@ describe('BrowserTitleService', () => {
TestBed.flushEffects();
expect(titleService.setTitle).toHaveBeenCalledWith('(24:59) Super Productivity');
expect(titleService.setTitle).toHaveBeenCalledWith('24:59');
focusModeServiceMock.isBreakActive.set(true);
focusModeServiceMock.timeRemaining.set(299000);
TestBed.flushEffects();
expect(titleService.setTitle).toHaveBeenCalledWith(
'(04:59 Break) Super Productivity',
);
expect(titleService.setTitle).toHaveBeenCalledWith('04:59 (Break)');
focusModeServiceMock.isRunning.set(false);
focusModeServiceMock.isSessionPaused.set(true);
focusModeServiceMock.timeElapsed.set(1000);
TestBed.flushEffects();
expect(titleService.setTitle).toHaveBeenCalledWith(
'(Paused 04:59 Break) Super Productivity',
);
expect(titleService.setTitle).toHaveBeenCalledWith('Paused 04:59 (Break)');
focusModeServiceMock.isSessionPaused.set(false);
focusModeServiceMock.isRunning.set(true);
@ -217,11 +284,17 @@ describe('BrowserTitleService', () => {
TestBed.flushEffects();
expect(titleService.setTitle).toHaveBeenCalledWith(
'(26:00 Break) Super Productivity',
);
expect(titleService.setTitle).toHaveBeenCalledWith('26:00 (Break)');
focusModeServiceMock.mode.set(FocusModeMode.Flowtime);
focusModeServiceMock.timeElapsed.set(60000);
TestBed.flushEffects();
expect(titleService.setTitle).toHaveBeenCalledWith('01:00 (Break)');
focusModeServiceMock.isRunning.set(false);
focusModeServiceMock.isSessionPaused.set(false);
TestBed.flushEffects();

View file

@ -41,8 +41,9 @@ export class BrowserTitleService {
isInOvertime: boolean,
timeElapsed: number,
): string {
if (mode === FocusModeMode.Pomodoro && (isRunning || isSessionPaused)) {
const displayTime = isInOvertime ? timeElapsed : timeRemaining;
if (isRunning || isSessionPaused) {
const isCountTimeDown = mode !== FocusModeMode.Flowtime || isBreakActive;
const displayTime = isCountTimeDown && !isInOvertime ? timeRemaining : timeElapsed;
const timeStr = msToMinuteClockString(displayTime);
@ -50,14 +51,18 @@ export class BrowserTitleService {
const formattedTime = `${minutes.padStart(2, '0')}:${seconds}`;
const breakStr = isBreakActive
? ` ${this._translateService.instant(T.F.FOCUS_MODE.BROWSER_TITLE_BREAK)}`
? ` (${this._translateService.instant(T.F.FOCUS_MODE.BROWSER_TITLE_BREAK)})`
: '';
const pausedStr = isSessionPaused
? `${this._translateService.instant(T.F.FOCUS_MODE.BROWSER_TITLE_PAUSED)} `
: '';
const isActuallyPaused = isSessionPaused && !(isBreakActive && timeElapsed === 0);
return `(${pausedStr}${formattedTime}${breakStr}) ${this._baseTitle}`;
if (isActuallyPaused) {
return `${this._translateService.instant(
T.F.FOCUS_MODE.BROWSER_TITLE_PAUSED,
)} ${formattedTime}${breakStr}`;
}
return `${formattedTime}${breakStr}`;
}
return this._baseTitle;