mirror of
https://github.com/Eugeny/tabby.git
synced 2025-06-08 13:30:02 +00:00
260 lines
8.3 KiB
TypeScript
260 lines
8.3 KiB
TypeScript
import { Component, Inject, Input, HostListener, HostBinding } from '@angular/core'
|
|
import { trigger, style, animate, transition, state } from '@angular/animations'
|
|
import { DomSanitizer } from '@angular/platform-browser'
|
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
|
|
|
import { ElectronService } from '../services/electron.service'
|
|
import { HostAppService, Platform } from '../services/hostApp.service'
|
|
import { HotkeysService } from '../services/hotkeys.service'
|
|
import { Logger, LogService } from '../services/log.service'
|
|
import { ConfigService } from '../services/config.service'
|
|
import { DockingService } from '../services/docking.service'
|
|
import { ThemesService } from '../services/themes.service'
|
|
import { UpdaterService } from '../services/updater.service'
|
|
import { TouchbarService } from '../services/touchbar.service'
|
|
|
|
import { BaseTabComponent } from './baseTab.component'
|
|
import { SafeModeModalComponent } from './safeModeModal.component'
|
|
import { AppService, ToolbarButton, ToolbarButtonProvider } from '../api'
|
|
|
|
/** @hidden */
|
|
@Component({
|
|
selector: 'app-root',
|
|
template: require('./appRoot.component.pug'),
|
|
styles: [require('./appRoot.component.scss')],
|
|
animations: [
|
|
trigger('animateTab', [
|
|
state('in', style({
|
|
'flex-basis': '200px',
|
|
width: '200px',
|
|
})),
|
|
transition(':enter', [
|
|
style({
|
|
'flex-basis': '1px',
|
|
width: '1px',
|
|
}),
|
|
animate('250ms ease-in-out', style({
|
|
'flex-basis': '200px',
|
|
width: '200px',
|
|
})),
|
|
]),
|
|
transition(':leave', [
|
|
style({
|
|
'flex-basis': '200px',
|
|
width: '200px',
|
|
}),
|
|
animate('250ms ease-in-out', style({
|
|
'flex-basis': '1px',
|
|
width: '1px',
|
|
})),
|
|
]),
|
|
]),
|
|
],
|
|
})
|
|
export class AppRootComponent {
|
|
Platform = Platform
|
|
@Input() ready = false
|
|
@Input() leftToolbarButtons: ToolbarButton[]
|
|
@Input() rightToolbarButtons: ToolbarButton[]
|
|
@HostBinding('class.platform-win32') platformClassWindows = process.platform === 'win32'
|
|
@HostBinding('class.platform-darwin') platformClassMacOS = process.platform === 'darwin'
|
|
@HostBinding('class.platform-linux') platformClassLinux = process.platform === 'linux'
|
|
@HostBinding('class.no-tabs') noTabs = true
|
|
tabsDragging = false
|
|
unsortedTabs: BaseTabComponent[] = []
|
|
updateIcon: string
|
|
updatesAvailable = false
|
|
private logger: Logger
|
|
|
|
private constructor (
|
|
private docking: DockingService,
|
|
private electron: ElectronService,
|
|
private hotkeys: HotkeysService,
|
|
private updater: UpdaterService,
|
|
private touchbar: TouchbarService,
|
|
public hostApp: HostAppService,
|
|
public config: ConfigService,
|
|
public app: AppService,
|
|
private domSanitizer: DomSanitizer,
|
|
@Inject(ToolbarButtonProvider) private toolbarButtonProviders: ToolbarButtonProvider[],
|
|
log: LogService,
|
|
ngbModal: NgbModal,
|
|
_themes: ThemesService,
|
|
) {
|
|
this.logger = log.create('main')
|
|
this.logger.info('v', electron.app.getVersion())
|
|
|
|
this.leftToolbarButtons = this.getToolbarButtons(false)
|
|
this.rightToolbarButtons = this.getToolbarButtons(true)
|
|
|
|
this.updateIcon = require('../icons/gift.svg')
|
|
|
|
this.hotkeys.matchedHotkey.subscribe((hotkey: string) => {
|
|
if (hotkey.startsWith('tab-')) {
|
|
const index = parseInt(hotkey.split('-')[1])
|
|
if (index <= this.app.tabs.length) {
|
|
this.app.selectTab(this.app.tabs[index - 1])
|
|
}
|
|
}
|
|
if (this.app.activeTab) {
|
|
if (hotkey === 'close-tab') {
|
|
this.app.closeTab(this.app.activeTab, true)
|
|
}
|
|
if (hotkey === 'toggle-last-tab') {
|
|
this.app.toggleLastTab()
|
|
}
|
|
if (hotkey === 'next-tab') {
|
|
this.app.nextTab()
|
|
}
|
|
if (hotkey === 'previous-tab') {
|
|
this.app.previousTab()
|
|
}
|
|
}
|
|
if (hotkey === 'toggle-fullscreen') {
|
|
this.hostApp.toggleFullscreen()
|
|
}
|
|
})
|
|
|
|
this.docking.dock()
|
|
this.hostApp.shown.subscribe(() => {
|
|
this.docking.dock()
|
|
})
|
|
|
|
this.hostApp.secondInstance$.subscribe(() => {
|
|
this.presentWindow()
|
|
})
|
|
this.hotkeys.globalHotkey.subscribe(() => {
|
|
this.onGlobalHotkey()
|
|
})
|
|
|
|
this.hostApp.windowCloseRequest$.subscribe(async () => {
|
|
await this.app.closeAllTabs() && this.hostApp.closeWindow()
|
|
})
|
|
|
|
if (window['safeModeReason']) {
|
|
ngbModal.open(SafeModeModalComponent)
|
|
}
|
|
|
|
this.updater.check().then(available => {
|
|
this.updatesAvailable = available
|
|
})
|
|
|
|
this.touchbar.update()
|
|
|
|
config.changed$.subscribe(() => this.updateVibrancy())
|
|
this.updateVibrancy()
|
|
|
|
let lastProgress = null
|
|
this.app.tabOpened$.subscribe(tab => {
|
|
this.unsortedTabs.push(tab)
|
|
tab.progress$.subscribe(progress => {
|
|
if (lastProgress === progress) {
|
|
return
|
|
}
|
|
if (progress !== null) {
|
|
this.hostApp.getWindow().setProgressBar(progress / 100.0, { mode: 'normal' })
|
|
} else {
|
|
this.hostApp.getWindow().setProgressBar(-1, { mode: 'none' })
|
|
}
|
|
lastProgress = progress
|
|
})
|
|
this.noTabs = false
|
|
})
|
|
|
|
this.app.tabClosed$.subscribe(tab => {
|
|
this.unsortedTabs = this.unsortedTabs.filter(x => x !== tab)
|
|
this.noTabs = app.tabs.length === 0
|
|
})
|
|
}
|
|
|
|
onGlobalHotkey () {
|
|
if (this.hostApp.getWindow().isFocused()) {
|
|
this.hideWindow()
|
|
} else {
|
|
this.presentWindow()
|
|
}
|
|
}
|
|
|
|
presentWindow () {
|
|
if (!this.hostApp.getWindow().isVisible()) {
|
|
// unfocused, invisible
|
|
this.hostApp.getWindow().show()
|
|
this.hostApp.getWindow().focus()
|
|
} else {
|
|
if (this.config.store.appearance.dock === 'off') {
|
|
// not docked, visible
|
|
setTimeout(() => {
|
|
this.hostApp.getWindow().focus()
|
|
})
|
|
} else {
|
|
// docked, visible
|
|
this.hostApp.getWindow().hide()
|
|
}
|
|
}
|
|
}
|
|
|
|
hideWindow () {
|
|
this.electron.loseFocus()
|
|
this.hostApp.getWindow().blur()
|
|
if (this.hostApp.platform !== Platform.macOS) {
|
|
this.hostApp.getWindow().hide()
|
|
}
|
|
}
|
|
|
|
async ngOnInit () {
|
|
this.ready = true
|
|
|
|
this.app.emitReady()
|
|
}
|
|
|
|
@HostListener('dragover')
|
|
onDragOver () {
|
|
return false
|
|
}
|
|
|
|
@HostListener('drop')
|
|
onDrop () {
|
|
return false
|
|
}
|
|
|
|
updateApp () {
|
|
this.updater.update()
|
|
}
|
|
|
|
onTabDragStart () {
|
|
this.tabsDragging = true
|
|
}
|
|
|
|
onTabDragEnd () {
|
|
setTimeout(() => {
|
|
this.tabsDragging = false
|
|
this.app.emitTabsChanged()
|
|
})
|
|
}
|
|
|
|
async generateButtonSubmenu (button: ToolbarButton) {
|
|
if (button.submenu) {
|
|
button.submenuItems = await button.submenu()
|
|
}
|
|
}
|
|
|
|
sanitizeIcon (icon: string): any {
|
|
return this.domSanitizer.bypassSecurityTrustHtml(icon || '')
|
|
}
|
|
|
|
private getToolbarButtons (aboveZero: boolean): ToolbarButton[] {
|
|
let buttons: ToolbarButton[] = []
|
|
this.config.enabledServices(this.toolbarButtonProviders).forEach(provider => {
|
|
buttons = buttons.concat(provider.provide())
|
|
})
|
|
return buttons
|
|
.filter(button => button.weight > 0 === aboveZero)
|
|
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0))
|
|
}
|
|
|
|
private updateVibrancy () {
|
|
this.hostApp.setVibrancy(this.config.store.appearance.vibrancy, this.config.store.appearance.vibrancyType)
|
|
this.hostApp.getWindow().setOpacity(this.config.store.appearance.opacity)
|
|
}
|
|
}
|