diff --git a/package-lock.json b/package-lock.json index a4cd0222..6dcee2e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,7 @@ { "name": "sengi", "version": "0.31.1", + "version": "0.27.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/app/app.component.html b/src/app/app.component.html index fd202f74..929daad4 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -16,6 +16,11 @@ +
+ +
+ diff --git a/src/app/app.component.scss b/src/app/app.component.scss index aef18c8b..3aac2af3 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -171,4 +171,27 @@ app-streams-selection-footer { } } } +} + +.enhanced-tutorial { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0,0,0,0.9); + z-index: 9999999; + opacity: 0; + transition: all .4s; + + &__visible { + opacity: 1; + } + + &__content { + display: block; + padding: 25px; + width: calc(100%); + height: calc(100%); + } } \ No newline at end of file diff --git a/src/app/app.component.ts b/src/app/app.component.ts index dd3e8bad..777a2efd 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -62,9 +62,6 @@ export class AppComponent implements OnInit, OnDestroy { } ngOnInit(): void { - // disable tutorial for future update - localStorage.setItem('tutorial', JSON.stringify(true)); - this.paramsSub = this.activatedRoute.queryParams.subscribe(params => { const code = params['code']; if (!code) { @@ -130,6 +127,8 @@ export class AppComponent implements OnInit, OnDestroy { this.columnEditorSub = this.navigationService.activatedPanelSubject.subscribe((event: OpenLeftPanelEvent) => { if (event.type === LeftPanelType.Closed) { this.floatingColumnActive = false; + + this.checkEnhancedTutorial(); } else { this.floatingColumnActive = true; } @@ -158,6 +157,29 @@ export class AppComponent implements OnInit, OnDestroy { }); } + enhancedTutorialActive: boolean; + enhancedTutorialVisible: boolean; + private checkEnhancedTutorial() { + let enhancedTutorialDesactivated = JSON.parse(localStorage.getItem('tutorial')); + if (!this.floatingColumnActive && !this.tutorialActive && !enhancedTutorialDesactivated) { + setTimeout(() => { + this.enhancedTutorialActive = true; + setTimeout(() => { + this.enhancedTutorialVisible = true; + }, 100); + }, 500); + } + } + + closeTutorial(){ + localStorage.setItem('tutorial', JSON.stringify(true)); + + this.enhancedTutorialVisible = false; + setTimeout(() => { + this.enhancedTutorialActive = false; + }, 400); + } + ngOnDestroy(): void { this.streamSub.unsubscribe(); this.columnEditorSub.unsubscribe(); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 20ea0dc1..582e1230 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -86,7 +86,10 @@ import { AttachementImageComponent } from './components/stream/status/attachemen import { EnsureHttpsPipe } from './pipes/ensure-https.pipe'; import { UserFollowsComponent } from './components/stream/user-follows/user-follows.component'; import { AccountComponent } from './components/common/account/account.component'; - +import { TutorialEnhancedComponent } from './components/tutorial-enhanced/tutorial-enhanced.component'; +import { NotificationsTutorialComponent } from './components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component'; +import { LabelsTutorialComponent } from './components/tutorial-enhanced/labels-tutorial/labels-tutorial.component'; +import { ThankyouTutorialComponent } from './components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component'; const routes: Routes = [ { path: "", component: StreamsMainDisplayComponent }, @@ -152,7 +155,11 @@ const routes: Routes = [ AttachementImageComponent, EnsureHttpsPipe, UserFollowsComponent, - AccountComponent + AccountComponent, + TutorialEnhancedComponent, + NotificationsTutorialComponent, + LabelsTutorialComponent, + ThankyouTutorialComponent ], entryComponents: [ EmojiPickerComponent diff --git a/src/app/components/floating-column/settings/settings.component.html b/src/app/components/floating-column/settings/settings.component.html index 8977c6a0..193f8845 100644 --- a/src/app/components/floating-column/settings/settings.component.html +++ b/src/app/components/floating-column/settings/settings.component.html @@ -148,7 +148,8 @@

About

Sengi version: {{version}}
- check for updates + open tutorial
+ check for updates

diff --git a/src/app/components/floating-column/settings/settings.component.ts b/src/app/components/floating-column/settings/settings.component.ts index 190a0c56..838135b3 100644 --- a/src/app/components/floating-column/settings/settings.component.ts +++ b/src/app/components/floating-column/settings/settings.component.ts @@ -8,6 +8,7 @@ import { UserNotificationService, NotificationSoundDefinition } from '../../../s import { ServiceWorkerService } from '../../../services/service-worker.service'; import { ContentWarningPolicy, ContentWarningPolicyEnum, TimeLineModeEnum, TimeLineHeaderEnum } from '../../../states/settings.state'; import { NotificationService } from '../../../services/notification.service'; +import { NavigationService } from '../../../services/navigation.service'; @Component({ selector: 'app-settings', @@ -60,6 +61,7 @@ export class SettingsComponent implements OnInit { } constructor( + private readonly navigationService: NavigationService, private formBuilder: FormBuilder, private serviceWorkersService: ServiceWorkerService, private readonly toolsService: ToolsService, @@ -250,6 +252,12 @@ export class SettingsComponent implements OnInit { notifyRestartNeeded(){ this.notificationService.notifyRestartNotification('Reload to apply changes'); } + + openTutorial(): boolean { + localStorage.setItem('tutorial', JSON.stringify(false)); + this.navigationService.closePanel(); + return false; + } } enum ColumnShortcut { diff --git a/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.html b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.html new file mode 100644 index 00000000..956ccf98 --- /dev/null +++ b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.html @@ -0,0 +1,69 @@ +
+

Labels

+

+ Sengi uses labels on statuses to describe them properly:
+
+
+

+ + +

Definitions

+
+
+
+ BOT +
+
+ The account is tagged as a bot +
+
+
+
+ REPLIES +
+
+ The status has replies +
+
+
+
+ THREAD +
+
+ The status is part of a thread +
+
+
+
+ X-POST +
+
+ The status was cross-posted using a software like MOA.
+ This functionality is limited to Local TL/Accounts due to API limitation. +
+
+
+
+ OLD +
+
+ The status was posted more than 3 months ago. +
+
+
+
+ REMOTE +
+
+ The status wasn't federated with your instance and was fetched remotely.
+ This functionality bypasses the blocking rules of your account/instance, you can disable it in the settings. +
+
+ + + + +

+ +

+
\ No newline at end of file diff --git a/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.scss b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.scss new file mode 100644 index 00000000..506a0740 --- /dev/null +++ b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.scss @@ -0,0 +1,60 @@ +.doc-label-wrapper { + margin-bottom: 15px; +} + +.doc-label { + width: 70px; + // height: 15px; + color: white; + text-align: center; + padding: 3px 0 2px 0; + font-size: 11px; + border-radius: 3px; + float: left; + + &__bot { + background-color: #017282; + } + + &__replies { + background-color: #59028f; + } + + &__thread { + background-color: #007233; + } + + &__xpost { + background-color: #9f5d00; + } + + &__old { + background-color: #960000; + } + + &__remote { + background-color: #264d94; + } +} + +.doc-label-definition { + margin-left: 85px; + position: relative; + // top: -1px; + + & a { + color: white; + text-decoration: underline; + + &:hover, &:active, &:focus { + color: rgb(218, 218, 218); + } + } + + &__gray { + display: inline-block; + margin-top: 5px; + color: #0f111a; + color: #9497a5; + } +} \ No newline at end of file diff --git a/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.spec.ts b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.spec.ts new file mode 100644 index 00000000..d72f59e7 --- /dev/null +++ b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LabelsTutorialComponent } from './labels-tutorial.component'; + +xdescribe('LabelsTutorialComponent', () => { + let component: LabelsTutorialComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LabelsTutorialComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LabelsTutorialComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.ts b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.ts new file mode 100644 index 00000000..e134f15e --- /dev/null +++ b/src/app/components/tutorial-enhanced/labels-tutorial/labels-tutorial.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-labels-tutorial', + templateUrl: './labels-tutorial.component.html', + styleUrls: ['../tutorial-enhanced.component.scss', 'labels-tutorial.component.scss'] +}) +export class LabelsTutorialComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.html b/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.html new file mode 100644 index 00000000..bd9b54cc --- /dev/null +++ b/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.html @@ -0,0 +1,32 @@ +
+

And... you're all set! 🎉

+

+ Please find below more information about Sengi.
+
+

+ +

Notifications

+

+ By default, Sengi doesn't need notification timelines: it has its own way to do it.
+
+ When your account will receive a new mention, follow, boost, favorite and other kind of notifications, your + avatar's icon will start flashing this way:
+
+ +
+ If you right-click on your avatar, the account panel will automatically open and switch to the related + subsection (mentions or notifications) and show you the last entries.
+ The flashing animation will then automatically stop:
+
+ +
+ The aim of this mechanism is to prevent the flood of notification timelines (one per account) in the interface, + especially if you add a lot of accounts in Sengi.
+
+ Of course, you can disable various parts of this mechanism in the settings like "disable avatar notification", "disable account's panel autofocus", etc.
+

+
\ No newline at end of file diff --git a/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.scss b/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.spec.ts b/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.spec.ts new file mode 100644 index 00000000..4169c5fe --- /dev/null +++ b/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NotificationsTutorialComponent } from './notifications-tutorial.component'; + +xdescribe('NotificationsTutorialComponent', () => { + let component: NotificationsTutorialComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ NotificationsTutorialComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NotificationsTutorialComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.ts b/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.ts new file mode 100644 index 00000000..5eeb6fdc --- /dev/null +++ b/src/app/components/tutorial-enhanced/notifications-tutorial/notifications-tutorial.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-notifications-tutorial', + templateUrl: './notifications-tutorial.component.html', + styleUrls: ['../tutorial-enhanced.component.scss'] +}) +export class NotificationsTutorialComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.html b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.html new file mode 100644 index 00000000..1e014e8b --- /dev/null +++ b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.html @@ -0,0 +1,36 @@ +
+

Thank you!

+

+ Thank you for downloading Sengi, I hope you will enjoy using this app as much as I did when making it.
+
+ Please find below some useful informations and... that's it!
+
+

+

The app's account

+

+ +
+
+ + +

+

Alternative builds

+

+ Official Docker + build
+ Official Snap build
+
+

+

Other ressources

+

+ Official + page
+ Github + Repository
+ Maintainer's dev + blog
+
+

+
\ No newline at end of file diff --git a/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.scss b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.scss new file mode 100644 index 00000000..43200572 --- /dev/null +++ b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.scss @@ -0,0 +1,29 @@ +.follow { + color: white; + display: block; + border: 1px solid rgb(0, 84, 122); + border-radius: 5px; + width: 200px; + text-align: center; + padding: 10px 0; + margin: 0 auto 30px auto; + transition: all .2s; + box-shadow: inset 0 0 5px rgb(0, 84, 122); + + &:hover, + &:focus { + text-decoration: none; + background-color: rgb(0, 84, 122); + } + + &__disabled { + opacity: .15; + border: 1px solid gray; + + &:hover, + &:focus { + text-decoration: none; + background-color: gray; + } + } +} \ No newline at end of file diff --git a/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.spec.ts b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.spec.ts new file mode 100644 index 00000000..a7660d20 --- /dev/null +++ b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ThankyouTutorialComponent } from './thankyou-tutorial.component'; + +describe('ThankyouTutorialComponent', () => { + let component: ThankyouTutorialComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ThankyouTutorialComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ThankyouTutorialComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.ts b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.ts new file mode 100644 index 00000000..6f636013 --- /dev/null +++ b/src/app/components/tutorial-enhanced/thankyou-tutorial/thankyou-tutorial.component.ts @@ -0,0 +1,41 @@ +import { Component, OnInit } from '@angular/core'; + +import { ToolsService } from '../../../services/tools.service'; +import { MastodonWrapperService } from '../../../services/mastodon-wrapper.service'; +import { NotificationService } from '../../../services/notification.service'; + +@Component({ + selector: 'app-thankyou-tutorial', + templateUrl: './thankyou-tutorial.component.html', + styleUrls: ['../tutorial-enhanced.component.scss', './thankyou-tutorial.component.scss'] +}) +export class ThankyouTutorialComponent implements OnInit { + followingDisabled: boolean; + + constructor( + private readonly notificationService: NotificationService, + private readonly mastodonService: MastodonWrapperService, + private readonly toolsService: ToolsService) { } + + ngOnInit() { + } + + follow(): boolean { + if(this.followingDisabled) return; + this.followingDisabled = true; + + const accounts = this.toolsService.getAllAccounts(); + for (let acc of accounts) { + this.toolsService.findAccount(acc, "@sengi_app@mastodon.social") + .then(sengi => { + return this.mastodonService.follow(acc, sengi); + }) + .catch(err => { + this.followingDisabled = false; + this.notificationService.notifyHttpError(err, acc); + }); + } + + return false; + } +} diff --git a/src/app/components/tutorial-enhanced/tutorial-enhanced.component.html b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.html new file mode 100644 index 00000000..54dfbb98 --- /dev/null +++ b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.html @@ -0,0 +1,20 @@ +
+
+ + + +
+ +
\ No newline at end of file diff --git a/src/app/components/tutorial-enhanced/tutorial-enhanced.component.scss b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.scss new file mode 100644 index 00000000..80d11ac2 --- /dev/null +++ b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.scss @@ -0,0 +1,133 @@ +@import"variables"; +@import "commons"; +@import "panel"; + +$border-color: #1d2335; +$footer-height: 30px; + +.tutorial { + border: 1px solid $border-color; + background-color: $color-primary; + height: calc(100%); + border-radius: 2px; + + &__content { + height: calc(100% - #{$footer-height}); + } + + &__footer { + border-top: 1px solid $border-color; + height: $footer-height; + + &--button { + text-transform: uppercase; + font-size: 15px; + text-align: center; + display: inline-block; + height: $footer-height; + width: calc(33.33333% - 1px); + color: white; + padding-top: 4px; + transition: all .2s; + + &:not(:last-child) { + border-right: 1px solid $border-color; + } + + &--close { + &:hover { + text-decoration: none; + background-color: rgb(95, 0, 0); + } + } + + &--navigate { + &:hover { + text-decoration: none; + background-color: rgb(0, 117, 172); + } + } + + &--next { + background-color: rgb(230, 230, 230); + background-color: rgb(0, 74, 109); + background-color: rgb(0, 84, 122); + color: white; + + // font-weight: bold; + &:hover { + text-decoration: none; + background-color: rgb(0, 74, 109); + background-color: rgb(0, 117, 172); + } + } + + &--disabled { + color: #4e5672; + + &:hover { + cursor: default; + text-decoration: none; + background-color: rgba(0, 0, 0, 0); + } + } + } + } +} + +.tutorial-content { + font-size: 14px; + + padding: 5px 10px; + overflow-y: auto; + height: calc(100%); + + &__title { + font-size: 20px; + + } + + &__title-important { + font-size: 20px; + margin: 5px 0 15px 10px; + } + + &__subtitle { + font-size: 16px; + + } +} + +.content { + &__center { + margin: auto; + width: 48px; + display: block; + } + + &__expand { + margin: auto; + width: calc(100%); + max-width: 380px; + display: block; + + &--smaller { + max-width: 270px; + } + } +} + +.link { + color: white; + text-decoration: underline; + + &:hover, + &:active, + &:focus { + color: rgb(218, 218, 218); + } + + &__tab { + padding-left: 10px; + } +} \ No newline at end of file diff --git a/src/app/components/tutorial-enhanced/tutorial-enhanced.component.spec.ts b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.spec.ts new file mode 100644 index 00000000..e129ba7d --- /dev/null +++ b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TutorialEnhancedComponent } from './tutorial-enhanced.component'; + +xdescribe('TutorialEnhancedComponent', () => { + let component: TutorialEnhancedComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TutorialEnhancedComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TutorialEnhancedComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/tutorial-enhanced/tutorial-enhanced.component.ts b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.ts new file mode 100644 index 00000000..32bfd2d4 --- /dev/null +++ b/src/app/components/tutorial-enhanced/tutorial-enhanced.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit, Output, EventEmitter } from '@angular/core'; + +@Component({ + selector: 'app-tutorial-enhanced', + templateUrl: './tutorial-enhanced.component.html', + styleUrls: ['./tutorial-enhanced.component.scss'] +}) +export class TutorialEnhancedComponent implements OnInit { + @Output() closeEvent = new EventEmitter(); + + previousAvailable = false; + nextAvailable = true; + index = 0; + tutorialEnded = false; + private maxIndex = 3; + + constructor() { } + + ngOnInit() { + } + + close(): boolean { + this.closeEvent.next(); + return false; + } + + previous(): boolean { + if (this.index > 0) { + this.index--; + this.checkState(); + } + return false; + } + + next(): boolean { + this.index++; + this.checkState(); + return false; + } + + private checkState() { + if(this.index >= this.maxIndex - 1){ + this.tutorialEnded = true; + } else { + this.tutorialEnded = false; + } + + if (this.index === 0) { + this.previousAvailable = false; + } else { + this.previousAvailable = true; + } + + if (this.index === this.maxIndex){ + this.close(); + } + } +} diff --git a/src/app/services/tools.service.ts b/src/app/services/tools.service.ts index 2e68a03f..001d9912 100644 --- a/src/app/services/tools.service.ts +++ b/src/app/services/tools.service.ts @@ -119,6 +119,11 @@ export class ToolsService { return regAccounts.filter(x => x.isSelected); } + getAllAccounts(): AccountInfo[] { + let regAccounts = this.store.snapshot().registeredaccounts.accounts; + return regAccounts; + } + getAccountById(accountId: string): AccountInfo { let regAccounts = this.store.snapshot().registeredaccounts.accounts; return regAccounts.find(x => x.id === accountId); diff --git a/src/assets/img/account.png b/src/assets/img/account.png new file mode 100644 index 00000000..5a59a301 Binary files /dev/null and b/src/assets/img/account.png differ diff --git a/src/assets/img/labels.png b/src/assets/img/labels.png new file mode 100644 index 00000000..e55d89ff Binary files /dev/null and b/src/assets/img/labels.png differ diff --git a/src/assets/video/flashing.mp4 b/src/assets/video/flashing.mp4 new file mode 100644 index 00000000..6b20318c Binary files /dev/null and b/src/assets/video/flashing.mp4 differ diff --git a/src/assets/video/notification.mp4 b/src/assets/video/notification.mp4 new file mode 100644 index 00000000..61b503c3 Binary files /dev/null and b/src/assets/video/notification.mp4 differ