Add app bar for nody-greeter

pull/4/head
Warinyourself 3 years ago
parent 21ef3b0cdb
commit 39722d6614

@ -12,6 +12,8 @@ module.exports = {
indent: 'off', indent: 'off',
'multiline-ternary': 'off', 'multiline-ternary': 'off',
'space-before-function-paren': [2, 'never'], 'space-before-function-paren': [2, 'never'],
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': 'warn',
'vue/array-bracket-spacing': 'error', 'vue/array-bracket-spacing': 'error',
'vue/arrow-spacing': 'error', 'vue/arrow-spacing': 'error',
'vue/block-spacing': 'error', 'vue/block-spacing': 'error',

@ -12,7 +12,7 @@ yay -S lightdm-webkit-theme-osmos
### Manual installation ### Manual installation
Or set `greeter-session=lightdm-webkit2-greeter` in `/etc/lightdm/lightdm.conf`, then edit `/etc/lightdm/lightdm-webkit2-greeter.conf` to set `webkit_theme=lightdm-webkit-theme-osmos`. Or set `greeter-session=lightdm-webkit2-greeter` in `/etc/lightdm/lightdm.conf`, then edit `/etc/lightdm/lightdm-webkit2-greeter.conf` to set `webkit_theme=osmos`.
## Themes ## Themes
### [Random](https://warinyourself.github.io/lightdm-webkit-theme-osmos/?pxratio=0.8&animation-speed=5&symmetry=0.01&thickness=0.1&hue=360&brightness=1&invert=false&blur=false&no-transition=false&show-framerate=false&only-ui=true&themeName=Random) ### [Random](https://warinyourself.github.io/lightdm-webkit-theme-osmos/?pxratio=0.8&animation-speed=5&symmetry=0.01&thickness=0.1&hue=360&brightness=1&invert=false&blur=false&no-transition=false&show-framerate=false&only-ui=true&themeName=Random)
@ -35,3 +35,6 @@ Or set `greeter-session=lightdm-webkit2-greeter` in `/etc/lightdm/lightdm.conf`,
### [Infinity](https://warinyourself.github.io/lightdm-webkit-theme-osmos/?palette=3&size=11&amount=50&animation-speed=20&blur=false&no-transition=false&show-framerate=false&only-ui=true&themeName=Infinity) ### [Infinity](https://warinyourself.github.io/lightdm-webkit-theme-osmos/?palette=3&size=11&amount=50&animation-speed=20&blur=false&no-transition=false&show-framerate=false&only-ui=true&themeName=Infinity)
![Infinity](https://user-images.githubusercontent.com/83131232/153943210-e4cc3bc3-3ade-4323-a216-acf787b61d76.png) ![Infinity](https://user-images.githubusercontent.com/83131232/153943210-e4cc3bc3-3ade-4323-a216-acf787b61d76.png)
### Roadmap
- Integrates with

@ -0,0 +1,66 @@
const child_process = require('child_process')
// import * as child_process from 'child_process'
// import { logger } from '../logger'
const logger = {
error: console.error,
debug: console.log
}
type Callback = (data: string) => void;
class ACPIController {
public constructor() {
if (this.checkAcpi()) this.listen()
else logger.error('ACPI: acpi_listen does not exists')
}
protected tries = 0;
protected callbacks: Callback[] = [];
public connect(cb: Callback): void {
this.callbacks.push(cb)
}
public disconnect(cb: Callback): void {
const ind = this.callbacks.findIndex((c) => {
return c === cb
})
if (ind == -1) return
this.callbacks.splice(ind, 1)
}
private checkAcpi(): boolean {
const res = child_process.spawnSync('which', ['acpi_listen'], {
encoding: 'utf-8'
})
if (res.status == 0) return true
else return false
}
private listen(): void {
const acpi = child_process.spawn('acpi_listen')
acpi.on('error', (err) => {
logger.error('ACPI: ' + err.message)
})
acpi.on('close', () => {
if (this.tries < 5) {
this.tries++
logger.debug('Restarting acpi_listen')
return this.listen()
}
})
acpi.stdout.addListener('data', (d: Buffer) => {
const data = d.toString().trim()
this.callbacks.forEach((cb) => {
console.log({ data })
if (cb !== undefined) cb(data)
})
})
}
}
const ACPI = new ACPIController()
export { ACPI }

@ -4,6 +4,7 @@ import { AppModule } from '@/store/app'
import { PageModule } from './store/page' import { PageModule } from './store/page'
import { Debounce, focusInputPassword } from './utils/helper' import { Debounce, focusInputPassword } from './utils/helper'
import { hotkeys } from '@/utils/hotkeys' import { hotkeys } from '@/utils/hotkeys'
import { initTimer } from './utils/time'
@Component @Component
export default class MainApp extends Vue { export default class MainApp extends Vue {
@ -24,6 +25,7 @@ export default class MainApp extends Vue {
created() { created() {
AppModule.setUpSettings() AppModule.setUpSettings()
this.initKeybinds() this.initKeybinds()
initTimer()
} }
initKeybinds() { initKeybinds() {

@ -0,0 +1,35 @@
import { AppModule } from '@/store/app'
import { Component, Vue } from 'vue-property-decorator'
import AppIcon from './AppIcon.vue'
import timer from '@/utils/time'
import BatteryIcon from '../base/BatteryIcon'
@Component({
components: { AppIcon, BatteryIcon }
})
export default class AppSelector extends Vue {
get batteryLevel() {
return AppModule.batteryLevel
}
get brightLevel() {
return AppModule.brightness
}
get currentTime() {
return timer.longTime
}
render() {
return <div class="app-bar">
<div class="app-bar__time"> { timer.longTime } </div>
<div class="app-bar__info">
<BatteryIcon />
<div class="app-bar__bright">
<AppIcon name="brightness" class="brightness-icon"/>
{ this.brightLevel }
</div>
</div>
</div>
}
}

@ -48,6 +48,57 @@
/> />
</svg> </svg>
<svg
v-else-if="name === 'charge'"
width="29"
height="12"
viewBox="0 0 29 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.7573 6.98762L12.142 0.419995C12.1171 0.15406 12.3907 -0.0543317 12.6768 0.0126378L28.8393 3.79557C29.0764 3.85104 29.0417 4.16413 28.7973 4.1762L17.2789 4.74482C17.0429 4.75647 16.8619 4.9383 16.8741 5.15137L17.2434 11.5926C17.2584 11.8538 16.9882 12.053 16.7077 11.9874L0.160717 8.11679C-0.0792939 8.06065 -0.0397734 7.74266 0.208049 7.73595L12.3429 7.40719C12.5887 7.40053 12.778 7.2089 12.7573 6.98762Z"
fill="currentColor"
/>
</svg>
<svg
v-else-if="name === 'brightness'"
width="128"
height="128"
viewBox="0 0 128 128"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M64 103.226C60.5795 103.226 57.8065 105.999 57.8065 109.419V121.806C57.8065 125.227 60.5795 128 64 128C67.4205 128 70.1935 125.227 70.1935 121.807V109.42C70.1935 105.999 67.4205 103.226 64 103.226Z"
/>
<path
d="M64 0C60.5795 0 57.8065 2.773 57.8065 6.1935V18.5805C57.8065 22.001 60.5795 24.774 64 24.774C67.4205 24.774 70.1935 22.001 70.1935 18.5805V6.1935C70.1935 2.773 67.4205 0 64 0Z"
/>
<path
d="M64.0007 37.1613C49.2027 37.1618 37.163 49.2015 37.163 64C37.163 78.7985 49.202 90.838 64 90.8388C78.7992 90.8388 90.8402 78.799 90.8402 64C90.8402 49.201 78.8 37.1613 64.0007 37.1613Z"
/>
<path
d="M128 64C128 60.5795 125.227 57.8065 121.807 57.8065H109.42C105.999 57.8065 103.226 60.5795 103.226 64C103.226 67.4205 105.999 70.1935 109.42 70.1935H121.807C125.227 70.1935 128 67.4205 128 64Z"
/>
<path
d="M0 64C0 67.4205 2.773 70.1935 6.1935 70.1935H18.5805C22.001 70.1935 24.774 67.4205 24.774 64C24.774 60.5795 22.001 57.8065 18.5805 57.8065H6.1935C2.773 57.8065 0 60.5795 0 64Z"
/>
<path
d="M96.116 38.077C97.7007 38.077 99.2862 37.472 100.495 36.2627L109.255 27.5037C111.673 25.085 111.673 21.1635 109.255 18.7447C106.836 16.326 102.915 16.326 100.495 18.7447L91.7363 27.5037C89.3175 29.9225 89.3175 33.844 91.7363 36.2627C92.9463 37.4722 94.531 38.077 96.116 38.077Z"
/>
<path
d="M23.1248 111.069C24.71 111.069 26.295 110.464 27.504 109.255L36.2632 100.496C38.682 98.0775 38.682 94.1555 36.2632 91.7367C33.8447 89.318 29.923 89.318 27.5042 91.7367L18.745 100.496C16.3263 102.914 16.3263 106.836 18.745 109.255C19.9543 110.464 21.5395 111.069 23.1248 111.069Z"
/>
<path
d="M100.496 91.7367C98.0775 89.318 94.1555 89.318 91.7367 91.7367C89.318 94.155 89.318 98.077 91.7367 100.496L100.496 109.255C101.706 110.464 103.291 111.069 104.875 111.069C106.461 111.069 108.046 110.464 109.255 109.255C111.673 106.837 111.673 102.915 109.255 100.496L100.496 91.7367Z"
/>
<path
d="M27.5042 36.2627C28.7137 37.4722 30.2988 38.077 31.884 38.077C33.4693 38.077 35.0542 37.472 36.2632 36.2627C38.682 33.844 38.682 29.9225 36.2632 27.5037L27.504 18.7445C25.0857 16.326 21.1638 16.326 18.745 18.7445C16.3263 21.1632 16.3263 25.0847 18.745 27.5035L27.5042 36.2627Z"
/>
</svg>
<svg <svg
v-else-if="name === 'suspend'" v-else-if="name === 'suspend'"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

@ -86,14 +86,16 @@ export default class AppMenu extends Vue {
event.preventDefault() event.preventDefault()
} }
buildElementItem(item: AppMenuItem, index: number) { buildElementItem(item: AppMenuItem | string, index: number) {
const isSting = typeof item === 'string'
const { text, icon } = isSting ? { text: item, icon: null } : item
return <li return <li
class='menu-list-item' class='menu-list-item'
key={index} key={index}
onClick={() => { this.handleCallback(item) }} onClick={() => { this.handleCallback(item) }}
> >
{ item.text } { text }
{ item.icon && <AppIcon class='menu-icon' name={item.icon} /> } { icon && <AppIcon class='menu-icon' name={icon} /> }
</li> </li>
} }

@ -19,12 +19,13 @@ export default class AppSelector extends Vue implements AppSelectorProps {
selectedValue: null | AppMenuItem | string = null selectedValue: null | AppMenuItem | string = null
get fullItem() { get fullSelectedItem() {
const selected = this.value !== null ? this.value : this.selectedValue const selected = this.value !== null ? this.value : this.selectedValue
const finalSelectedValue = typeof selected === 'object' ? selected?.value : selected
return this.items.find(({ value }) => { return this.items.find((item) => {
const finalValue = typeof selected === 'object' ? selected?.value : selected const finalValue = typeof item === 'object' ? item?.value : item
return value === finalValue return finalValue === finalSelectedValue
}) })
} }
@ -37,7 +38,7 @@ export default class AppSelector extends Vue implements AppSelectorProps {
} }
get currentValueLabel() { get currentValueLabel() {
const selected = this.fullItem ?? this.selectedValue const selected = this.fullSelectedItem ?? this.selectedValue
return typeof selected === 'object' ? selected?.text : selected return typeof selected === 'object' ? selected?.text : selected
} }
@ -65,10 +66,10 @@ export default class AppSelector extends Vue implements AppSelectorProps {
} }
render() { render() {
const selectorIcon = this.fullItem?.icon ? <AppIcon {...{ const selectorIcon = this.fullSelectedItem?.icon ? <AppIcon {...{
class: 'menu-icon selector-icon', class: 'menu-icon selector-icon',
props: { props: {
name: this.fullItem.icon name: this.fullSelectedItem.icon
} }
}}/> : null }}/> : null

@ -0,0 +1,29 @@
import { AppModule } from '@/store/app'
import { Component, Vue } from 'vue-property-decorator'
import AppIcon from '@/components/app/AppIcon.vue'
@Component({
components: { AppIcon }
})
export default class BatteryIcon extends Vue {
get batteryLevel() {
return AppModule.batteryLevel
}
get isCharging() {
return AppModule.isCharging
}
render() {
return <div class="app-bar-battery">
<div class="app-bar-battery-icon">
<div
class={`app-bar-battery-icon__fill ${this.isCharging ? 'charging' : ''}`}
style={{ width: `${this.batteryLevel}%` }}
/>
{ this.isCharging && <AppIcon name="charge" class="app-bar-battery-icon__charge"/>}
</div>
<span class="app-bar-battery__percent"> { this.batteryLevel }% </span>
</div>
}
}

@ -4,30 +4,14 @@ import { AppModule } from '@/store/app'
import AppIcon from '@/components/app/AppIcon.vue' import AppIcon from '@/components/app/AppIcon.vue'
import { LightdmUsers } from '@/models/lightdm' import { LightdmUsers } from '@/models/lightdm'
import { PageModule } from '@/store/page' import { PageModule } from '@/store/page'
import { DateTimeFormatOptions } from 'vue-i18n' import timer from '@/utils/time'
@Component({ @Component({
components: { AppIcon } components: { AppIcon }
}) })
export default class UserAvatar extends Vue { export default class UserAvatar extends Vue {
updater = new Date().getTime()
get currentTime() { get currentTime() {
const options: DateTimeFormatOptions = { return this.isOpenSettings ? timer.longTime : timer.shortTime
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
hour12: false
}
if (this.isOpenSettings) {
options.month = 'long'
options.day = 'numeric'
options.weekday = 'short'
}
return new Intl.DateTimeFormat(this.locale, options).format(new Date())
} }
get isOpenSettings() { get isOpenSettings() {
@ -46,12 +30,6 @@ export default class UserAvatar extends Vue {
return AppModule.users return AppModule.users
} }
mounted() {
this.updater = new Date().getTime()
setInterval(() => { this.updater = new Date().getTime() }, 1000)
}
buildUserAvatar(image: string | undefined) { buildUserAvatar(image: string | undefined) {
const defaultAvatar = <AppIcon name='user'/> const defaultAvatar = <AppIcon name='user'/>
const userAvatar = <div const userAvatar = <div
@ -64,7 +42,7 @@ export default class UserAvatar extends Vue {
buildUser(user: LightdmUsers) { buildUser(user: LightdmUsers) {
return <div class='user-choice' key={ user.username }> return <div class='user-choice' key={ user.username }>
<p class='time' key={ this.updater }> { this.currentTime } </p> <p class='time'> { this.currentTime } </p>
{ this.buildUserAvatar(user?.image) } { this.buildUserAvatar(user?.image) }
<div class='user-name'> { user?.display_name } </div> <div class='user-name'> { user?.display_name } </div>
</div> </div>

@ -1,7 +1,7 @@
import { Component, Vue } from 'vue-property-decorator' import { Component, Vue } from 'vue-property-decorator'
import { AppModule } from '@/store/app' import { AppModule } from '@/store/app'
import { AppInputButton, AppInputColor, AppInputThemeGeneral, AppInputThemeSlider, AppTheme } from '@/models/app' import { AppInputButton, AppInputColor, AppInputThemeGeneral, AppInputThemePalette, AppInputThemeSelector, AppInputThemeSlider, AppTheme } from '@/models/app'
import AppSlider from '@/components/app/AppSlider' import AppSlider from '@/components/app/AppSlider'
import AppButton from '@/components/app/AppButton' import AppButton from '@/components/app/AppButton'
@ -53,6 +53,16 @@ export default class SettingsCustom extends Vue {
return <AppSlider {...{ props, on: { input: handler } } } /> return <AppSlider {...{ props, on: { input: handler } } } />
} }
buildSelector(input: AppInputThemeSelector) {
const { label, value, values } = input
const props = { label, value, items: values }
const handler = (value: number) => {
AppModule.changeSettingsThemeInput({ key: input.name, value })
}
return <AppSelector {...{ props, on: { input: handler } } } />
}
buildColor(input: AppInputThemeGeneral) { buildColor(input: AppInputThemeGeneral) {
const { label, value, options } = input const { label, value, options } = input
const props = { label, value } const props = { label, value }
@ -81,7 +91,7 @@ export default class SettingsCustom extends Vue {
return <AppCheckbox {...{ props, on: { input: handler } } }/> return <AppCheckbox {...{ props, on: { input: handler } } }/>
} }
buildPalette(input: AppInputThemeGeneral) { buildPalette(input: AppInputThemePalette) {
const { label, value, values } = input const { label, value, values } = input
const props = { label, value, values } const props = { label, value, values }
const handler = (value: boolean) => { const handler = (value: boolean) => {
@ -109,7 +119,8 @@ export default class SettingsCustom extends Vue {
slider: this.buildSlider, slider: this.buildSlider,
checkbox: this.buildCheckbox, checkbox: this.buildCheckbox,
palette: this.buildPalette, palette: this.buildPalette,
button: this.buildButton button: this.buildButton,
selector: this.buildSelector
} }
return <div class='user-settings-custom'> return <div class='user-settings-custom'>

@ -34,6 +34,10 @@ export default class SettingsGeneral extends Vue {
if (hasQyery) { this.$router.replace({}) } if (hasQyery) { this.$router.replace({}) }
} }
changeTheme() {
throw Error('Change theme')
}
render() { render() {
return <div class='user-settings-general'> return <div class='user-settings-general'>
<SettingsCheckboxes /> <SettingsCheckboxes />
@ -43,9 +47,12 @@ export default class SettingsGeneral extends Vue {
<SettingsHotkeys /> <SettingsHotkeys />
<div class="help-block"> <div class="help-block">
<AppButton onClick={ this.resetSettings } block> <AppButton onClick={ this.resetSettings } block class="mb-2">
{ this.$t('settings.reset-settings') } { this.$t('settings.reset-settings') }
</AppButton> </AppButton>
<AppButton onClick={ this.changeTheme } block>
{ this.$t('settings.change-theme') }
</AppButton>
</div> </div>
</div> </div>
} }

@ -3,7 +3,8 @@ import { AppModule } from '@/store/app'
import { Wavery } from './lib/wave' import { Wavery } from './lib/wave'
import { Debounce } from '@/utils/helper' import { Debounce } from '@/utils/helper'
import { changeHsl, hexToRgb, rgbToHsl } from '@/utils/color' import { changeHsl, hexToRgb, rgbToHsl } from '@/utils/color'
import { AppInputThemeGeneral } from '@/models/app' import { AppInputThemePalette } from '@/models/app'
import { AgidaTypes } from '@/utils/constant'
export const OPACITY_ARR = [0.265, 0.4, 0.53, 1] export const OPACITY_ARR = [0.265, 0.4, 0.53, 1]
export const topColors = ['#03C79C', '#00A5B2', '#0080A5', '#005A8D'] export const topColors = ['#03C79C', '#00A5B2', '#0080A5', '#005A8D']
@ -20,11 +21,7 @@ export default class AgidaTheme extends Vue {
width: 1200, width: 1200,
segmentCount: 5, segmentCount: 5,
layerCount: 4, layerCount: 4,
variance: 1, variance: 1
animation: {
steps: 2,
time: 40000
}
} }
screen = { screen = {
@ -33,7 +30,7 @@ export default class AgidaTheme extends Vue {
} }
get palette(): string[] { get palette(): string[] {
const input = AppModule.getThemeInput('palette') as AppInputThemeGeneral const input = AppModule.getThemeInput('palette') as AppInputThemePalette
const index = input?.value as number || 0 const index = input?.value as number || 0
const values = input?.values || ['#00CC99', '#6600FF'] const values = input?.values || ['#00CC99', '#6600FF']
@ -52,6 +49,10 @@ export default class AgidaTheme extends Vue {
return AppModule.getThemeInput('animation-speed')?.value as number || 40 return AppModule.getThemeInput('animation-speed')?.value as number || 40
} }
get type(): AgidaTypes {
return AppModule.getThemeInput('type')?.value as AgidaTypes || 'agida'
}
get topColors(): string[] { get topColors(): string[] {
const initHSL = rgbToHsl(hexToRgb(this.topColor)) const initHSL = rgbToHsl(hexToRgb(this.topColor))
const second = changeHsl(initHSL, 10, -3, -5) const second = changeHsl(initHSL, 10, -3, -5)
@ -71,13 +72,13 @@ export default class AgidaTheme extends Vue {
} }
get bottomActiveColor(): string { get bottomActiveColor(): string {
return this.bottomColor // this.bottomColors[3] return this.bottomColor
} }
get knifeSVG(): JSX.Element { get knifeSVG(): JSX.Element {
return <g> return <g style="transform: scale(0.7) translate(-27%, -7%);transform-origin: center">
<path d="M1233.68 556.289L490.85 201.979L400.013 392.424C1142.84 746.735 1233.68 556.289 1233.68 556.289Z" fill="url(#paint0_linear_602_754)"/> <path d="M1233.68 556.289L490.85 201.979L400.013 392.424C1142.84 746.735 1233.68 556.289 1233.68 556.289Z" fill="white"/>
<path d="M432.556 293.998L479.117 196.382L74.764 3.5156C59.8095 -3.61734 41.904 2.72332 34.7711 17.6778L3.55143 83.1312C-3.58151 98.0857 2.75915 115.991 17.7137 123.124L52.0107 139.483C65.6195 145.974 81.9138 140.204 88.4048 126.595C88.4048 126.595 102.294 97.911 145.302 118.425C188.31 138.938 173.495 170.432 173.495 170.432C173.495 170.432 188.648 139.1 231.655 159.613C274.663 180.127 259.849 211.621 259.849 211.621C259.849 211.621 274.692 180.141 318.009 200.802C361.326 221.463 346.203 252.809 346.203 252.809C346.203 252.809 361.355 221.477 404.363 241.991C447.371 262.504 432.556 293.998 432.556 293.998Z" fill="url(#paint1_linear_602_754)"/> <path d="M432.556 293.998L479.117 196.382L74.764 3.5156C59.8095 -3.61734 41.904 2.72332 34.7711 17.6778L3.55143 83.1312C-3.58151 98.0857 2.75915 115.991 17.7137 123.124L52.0107 139.483C65.6195 145.974 81.9138 140.204 88.4048 126.595C88.4048 126.595 102.294 97.911 145.302 118.425C188.31 138.938 173.495 170.432 173.495 170.432C173.495 170.432 188.648 139.1 231.655 159.613C274.663 180.127 259.849 211.621 259.849 211.621C259.849 211.621 274.692 180.141 318.009 200.802C361.326 221.463 346.203 252.809 346.203 252.809C346.203 252.809 361.355 221.477 404.363 241.991C447.371 262.504 432.556 293.998 432.556 293.998Z" fill="white"/>
</g> </g>
} }
@ -157,14 +158,20 @@ export default class AgidaTheme extends Vue {
} }
get yinYangSVG(): JSX.Element { get yinYangSVG(): JSX.Element {
return <g> return <g style="transform: translate(30px, 30px);">
<path fill-rule="evenodd" clip-rule="evenodd" d="M289.088 578.175C448.746 578.175 578.175 448.746 578.175 289.088C578.175 129.429 448.746 0 289.088 0C129.429 0 0 129.429 0 289.088C0 448.746 129.429 578.175 289.088 578.175ZM289.087 570.763C214.383 570.763 142.737 541.086 89.9132 488.262C37.0889 435.437 7.41248 363.792 7.41248 289.087C7.41248 214.383 37.0889 142.737 89.9132 89.9132C142.737 37.0889 214.383 7.41248 289.087 7.41248C326.44 7.41248 362.262 22.2507 388.675 48.6628C415.087 75.075 429.925 110.898 429.925 148.25C429.925 185.602 415.087 221.425 388.675 247.837C362.262 274.249 326.44 289.087 289.087 289.087C251.735 289.087 215.912 303.926 189.5 330.338C163.088 356.75 148.25 392.573 148.25 429.925C148.25 467.277 163.088 503.1 189.5 529.512C215.912 555.924 251.735 570.763 289.087 570.763ZM326.15 429.925C326.15 450.394 309.557 466.988 289.088 466.988C268.618 466.988 252.025 450.394 252.025 429.925C252.025 409.456 268.618 392.863 289.088 392.863C309.557 392.863 326.15 409.456 326.15 429.925Z" fill="white"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M289.088 578.175C448.746 578.175 578.175 448.746 578.175 289.088C578.175 129.429 448.746 0 289.088 0C129.429 0 0 129.429 0 289.088C0 448.746 129.429 578.175 289.088 578.175ZM289.087 570.763C214.383 570.763 142.737 541.086 89.9132 488.262C37.0889 435.437 7.41248 363.792 7.41248 289.087C7.41248 214.383 37.0889 142.737 89.9132 89.9132C142.737 37.0889 214.383 7.41248 289.087 7.41248C326.44 7.41248 362.262 22.2507 388.675 48.6628C415.087 75.075 429.925 110.898 429.925 148.25C429.925 185.602 415.087 221.425 388.675 247.837C362.262 274.249 326.44 289.087 289.087 289.087C251.735 289.087 215.912 303.926 189.5 330.338C163.088 356.75 148.25 392.573 148.25 429.925C148.25 467.277 163.088 503.1 189.5 529.512C215.912 555.924 251.735 570.763 289.087 570.763ZM326.15 429.925C326.15 450.394 309.557 466.988 289.088 466.988C268.618 466.988 252.025 450.394 252.025 429.925C252.025 409.456 268.618 392.863 289.088 392.863C309.557 392.863 326.15 409.456 326.15 429.925Z" fill="white"/>
<path d="M289.088 185.312C309.557 185.312 326.15 168.719 326.15 148.25C326.15 127.781 309.557 111.188 289.088 111.188C268.618 111.188 252.025 127.781 252.025 148.25C252.025 168.719 268.618 185.312 289.088 185.312Z" fill="white"/> <path d="M289.088 185.312C309.557 185.312 326.15 168.719 326.15 148.25C326.15 127.781 309.557 111.188 289.088 111.188C268.618 111.188 252.025 127.781 252.025 148.25C252.025 168.719 268.618 185.312 289.088 185.312Z" fill="white"/>
</g> </g>
} }
get activeFragment() { get activeFragment() {
return this.agidaSVG const objectMap: Record<AgidaTypes, JSX.Element> = {
agida: this.agidaSVG,
knife: this.knifeSVG,
'yin yang': this.yinYangSVG
}
return objectMap[this.type] || this.agidaSVG
} }
get width(): number { get width(): number {
@ -207,7 +214,6 @@ export default class AgidaTheme extends Vue {
generateWave(type: 'bottom' | 'top') { generateWave(type: 'bottom' | 'top') {
const wavery = new Wavery(this.wave) const wavery = new Wavery(this.wave)
const waveSvg = wavery.generateSvg() const waveSvg = wavery.generateSvg()
console.log('GENERATE WAVE')
const { height, width, xmlns, paths } = waveSvg.svg const { height, width, xmlns, paths } = waveSvg.svg
const isTop = type === 'top' const isTop = type === 'top'

@ -1,4 +1,4 @@
import { AppInputThemeGeneral, AppTheme } from '@/models/app' import { AppInputThemePalette, AppTheme } from '@/models/app'
import { AppModule } from '@/store/app' import { AppModule } from '@/store/app'
import { Component, Vue } from 'vue-property-decorator' import { Component, Vue } from 'vue-property-decorator'
import { CreateElement } from 'vue/types/umd' import { CreateElement } from 'vue/types/umd'
@ -10,7 +10,7 @@ export default class InfinityTheme extends Vue {
} }
get palette() { get palette() {
const input = AppModule.getThemeInput('palette') as AppInputThemeGeneral const input = AppModule.getThemeInput('palette') as AppInputThemePalette
const index = input?.value as number || 0 const index = input?.value as number || 0
const values = input?.values || [] const values = input?.values || []

@ -75,6 +75,7 @@
"general": "General", "general": "General",
"choice-themes": "Choice themes", "choice-themes": "Choice themes",
"customize-theme": "Customize theme", "customize-theme": "Customize theme",
"change-theme": "Сhange theme",
"reset-settings": "Reset settings", "reset-settings": "Reset settings",
"login-position": { "login-position": {
"title": "Position", "title": "Position",

@ -19,7 +19,8 @@
"invert": "Инвертировать", "invert": "Инвертировать",
"brightness": "Яркость", "brightness": "Яркость",
"random": "Случайно", "random": "Случайно",
"symmetry": "Симметрия" "symmetry": "Симметрия",
"thickness": "Толщина"
}, },
"text": { "text": {
"password": "пароль", "password": "пароль",
@ -71,6 +72,7 @@
"choice-themes": "Выбор темы", "choice-themes": "Выбор темы",
"customize-theme": "Настройка темы", "customize-theme": "Настройка темы",
"reset-settings": "Сбросить настройки", "reset-settings": "Сбросить настройки",
"change-theme": "Сменить тему",
"login-position": { "login-position": {
"title": "Положение", "title": "Положение",
"about": "Выбрать положение логина", "about": "Выбрать положение логина",

@ -25,8 +25,8 @@ export interface AppThemeSnapshot {
values: Record<string, AppInputThemeValue>; values: Record<string, AppInputThemeValue>;
} }
export type AppInputTheme = AppInputThemeGeneral | AppInputThemeSlider | AppInputButton export type AppInputTheme = AppInputThemeGeneral | AppInputThemeSlider | AppInputButton | AppInputThemePalette | AppInputThemeSelector
export type AppInputThemeType = 'color' | 'slider' | 'checkbox' | 'palette' | 'button' export type AppInputThemeType = 'color' | 'slider' | 'checkbox' | 'palette' | 'button' | 'selector'
export type AppInputThemeValue = string | boolean | string[] | number export type AppInputThemeValue = string | boolean | string[] | number
export interface AppInputThemeGeneral { export interface AppInputThemeGeneral {
@ -34,7 +34,6 @@ export interface AppInputThemeGeneral {
value: AppInputThemeValue; value: AppInputThemeValue;
label: string; label: string;
type: AppInputThemeType; type: AppInputThemeType;
values?: string[][];
options?: AppInputThemeOptions; options?: AppInputThemeOptions;
callback?: (value: AppInputThemeValue) => void; callback?: (value: AppInputThemeValue) => void;
} }
@ -45,6 +44,16 @@ export interface AppInputThemeSlider extends AppInputThemeGeneral {
options: AppInputThemeOptionsSlider; options: AppInputThemeOptionsSlider;
} }
export interface AppInputThemeSelector extends AppInputThemeGeneral {
type: 'selector';
values: Readonly<string[]>;
}
export interface AppInputThemePalette extends AppInputThemeGeneral {
type: 'palette';
values: string[][];
}
export interface AppInputButton { export interface AppInputButton {
// TODO: "name" and "value" useless property, need to delete them // TODO: "name" and "value" useless property, need to delete them
name: 'button'; name: 'button';

@ -1,55 +1,56 @@
import { Greeter, Signal } from 'nody-greeter-types'
export interface Lightdm {
can_suspend: boolean;
can_shutdown: boolean;
can_restart: boolean;
can_hibernate: boolean;
is_authenticated: boolean;
authentication_user?: string;
default_session: string;
sessions: LightdmSession[];
users: LightdmUsers[];
languages: LightdmLanguage[];
language: string;
has_guest_account: boolean;
start_authentication(username: string): void;
authenticate(username: string): void;
cancel_authentication(): void;
respond(password: string): void;
login(user: string, session: string): void;
shutdown(): void;
hibernate(): void;
suspend(): void;
restart(): void;
}
export interface LightdmUsers { export interface LightdmUsers {
display_name: string; display_name: string
username: string; username: string
image?: string; image?: string
} }
export interface LightdmLanguage { export interface LightdmLanguage {
name: string; name: string
code: string; code: string
} }
export interface LightdmSession { export interface LightdmSession {
name: string; name: string
key: string; key: string
comment?: string; comment?: string
}
export interface Lightdm {
can_suspend: boolean
can_shutdown: boolean
can_restart: boolean
can_hibernate: boolean
is_authenticated: boolean
authentication_user?: string
default_session: string
sessions: LightdmSession[]
users: LightdmUsers[]
languages: LightdmLanguage[]
language: string
has_guest_account: boolean
start_authentication(username: string): void
authenticate(username: string): void
cancel_authentication(): void
respond(password: string): void
login(user: string, session: string): void
shutdown(): void
hibernate(): void
suspend(): void
restart(): void
} }
declare global { declare global {
interface Window { interface Window {
authentication_complete(): void; authentication_complete(): void
lightdmLogin( lightdmLogin(
username: string, username: string,
password: string, password: string,
callback: () => void, callback: () => void,
): void; ): void;
show_prompt(text: string, type?: string): void; show_prompt(text: string, type?: string): void
show_message(text: string, type: any): void; show_message(text: string, type: any): void
lightdm_start(desktop: string): void;
lightdm_cancel_login(): void;
} }
} }

@ -22,14 +22,18 @@ import { isDifferentRoute, parseQueryValue, randomize, randomizeSettingsTheme }
import { AppThemes, defaultTheme } from '@/utils/constant' import { AppThemes, defaultTheme } from '@/utils/constant'
import { version } from '@/../package.json' import { version } from '@/../package.json'
import { LightdmHandler } from '@/utils/lightdm' import { LightdmHandler } from '@/utils/lightdm'
import { LightDMBattery } from 'nody-greeter-types'
export interface AppState extends AppSettings { export interface AppState extends AppSettings {
themes: AppTheme[]; themes: AppTheme[];
getMainSettings: AppSettings; getMainSettings: AppSettings;
activeTheme: AppTheme; activeTheme: AppTheme;
battery?: LightDMBattery;
brightness?: number;
username: string; username: string;
desktops: LightdmSession[]; desktops: LightdmSession[];
users: LightdmUsers[]; users: LightdmUsers[];
SET_STATE_APP: <S extends this, K extends keyof this>({ key, value }: { key: K; value: S[K] }) => void
} }
@Module({ dynamic: true, store, name: 'app' }) @Module({ dynamic: true, store, name: 'app' })
@ -38,9 +42,11 @@ class App extends VuexModule implements AppState {
currentTheme = '' currentTheme = ''
currentOs = 'arch-linux' currentOs = 'arch-linux'
desktop = LightdmHandler.defaultSession desktop = LightdmHandler.defaultSession
username = LightdmHandler?.username username = LightdmHandler.username
password = '' password = ''
defaultColor = '#6BBBED' defaultColor = '#6BBBED'
battery?: LightDMBattery = undefined
brightness = 0
users = LightdmHandler?.users users = LightdmHandler?.users
desktops = LightdmHandler?.sessions desktops = LightdmHandler?.sessions
@ -55,8 +61,16 @@ class App extends VuexModule implements AppState {
'only-ui': false 'only-ui': false
} }
get isAdvancedGreeted() { get isCharging() {
return LightdmHandler.isNode return this.battery?.status === 'Charging'
}
get batteryLevel() {
return this.battery?.level || 0
}
get isSupportFullApi() {
return LightdmHandler.isSupportFullApi
} }
// TODO: replace this on localStorageSettings // TODO: replace this on localStorageSettings

@ -0,0 +1,64 @@
.app-bar
--icon-size: 24px
position absolute
top 0
left 0
width 100%
font-size 0.875rem
background var(--background-block)
display flex
justify-content center
height var(--height-bar)
align-items center
padding 0 var(--gap)
.app-bar__info
display flex
gap var(--gap)
position absolute
right var(--gap)
.app-bar-battery
display flex
align-items center
.app-bar-battery-icon
position relative
width var(--icon-size)
height calc(var(--icon-size) / 2)
border calc(var(--icon-size) / 40) white solid
border-radius calc(var(--icon-size) / 9)
margin-right calc(var(--gap) / 2)
&::before
content ''
display block
top 50%
right 0px
background white
position absolute
border-radius 0 calc(var(--icon-size) / 30) calc(var(--icon-size) / 30) 0
width calc(var(--icon-size) / 10)
height calc(var(--icon-size) / 5)
transform translate(100%, -50%)
.app-bar-battery-icon__fill
max-width 100%
height 100%
background var(--color-unfocus)
&.charging
background var(--color-green)
.app-bar-battery-icon__charge
width 80%
position absolute
top 50%
left 50%
transform translate(-50%, -50%)
.app-bar__bright
gap calc(var(--gap) / 2)
display flex
align-items center
.brightness-icon
width 1.1rem

@ -1,3 +1,4 @@
@import './bar.styl'
@import './menu.styl' @import './menu.styl'
@import './login.styl' @import './login.styl'
@import './dialog.styl' @import './dialog.styl'
@ -20,12 +21,12 @@
justify-content center justify-content center
.frame-rate-block .frame-rate-block
top 0 top calc(var(--gap) + var(--height-bar))
right 0 right var(--gap)
color white color white
font-size 1.1rem font-size 1.1rem
padding 6px 12px padding calc(var(--gap) / 2) var(--gap)
z-index 10 z-index 10
position absolute position absolute
background var(--background-block) background var(--background-block)
border-radius 0 0 0 10px border-radius var(--gap)

@ -19,7 +19,7 @@
&.login-view--center &.login-view--center
transform translate(calc(100vw / 2 - 50%), calc(100vh / 2 - 50%)) transform translate(calc(100vw / 2 - 50%), calc(100vh / 2 - 50%))
&.login-view--top &.login-view--top
transform translate(calc(100vw / 2 - 50%), 12px) transform translate(calc(100vw / 2 - 50%), calc(var(--gap) + var(--height-bar)))
&.login-view--right &.login-view--right
transform translate(calc(100vw - 100% - 12px), calc(100vh / 2 - 50%)) transform translate(calc(100vw - 100% - 12px), calc(100vh / 2 - 50%))
&.login-view--bottom &.login-view--bottom
@ -58,12 +58,10 @@
width 60px width 60px
height 60px height 60px
margin 0 margin 0
.time
position absolute
transform translate(74px, 32px)
.user-name .user-name
margin 8px 12px margin 8px 12px
display flex
align-items center
.user-choice .user-choice
width 100% width 100%
@ -72,6 +70,10 @@
height 50px height 50px
.time .time
position absolute
top 0
left 50%
transform translateX(-50%)
text-align center text-align center
color var(--color-unfocus) color var(--color-unfocus)
font-size 0.95rem font-size 0.95rem
@ -82,7 +84,7 @@
height 100px height 100px
display block display block
transition .3s transition .3s
margin auto margin 24px auto 0
background-repeat no-repeat background-repeat no-repeat
background-size cover background-size cover
background-position center background-position center

@ -1,6 +1,7 @@
.selector .selector
padding 4px 8px padding 4px 8px
border-radius 4px border-radius 4px
max-height 36px
border 1px solid var(--color-unfocus) border 1px solid var(--color-unfocus)
color var(--color-unfocus) color var(--color-unfocus)
display flex display flex

@ -86,7 +86,7 @@
left auto left auto
right 0 right 0
height 0 height 0
width 10% width 100%
.app-slider__content .app-slider__content
white-space nowrap white-space nowrap

@ -12,8 +12,9 @@
--color-blue #04ded4 --color-blue #04ded4
--color-unfocus rgba(255, 255, 255, .5) --color-unfocus rgba(255, 255, 255, .5)
--color-focus white --color-focus white
--login-height: 14vmin
--background-block: rgba(0,0,0,0.45) --background-block: rgba(0,0,0,0.45)
--gap: 12px
--height-bar: 36px
font-size 16px font-size 16px
::-webkit-scrollbar ::-webkit-scrollbar
@ -37,3 +38,19 @@
animation-iteration-count 1 !important animation-iteration-count 1 !important
transition-duration 0.01ms !important transition-duration 0.01ms !important
scroll-behavior auto !important scroll-behavior auto !important
// @media screen and (-moz-min-device-pixel-ratio: 2),
// screen and (-o-min-device-pixel-ratio: 2/1),
// screen and (-webkit-min-device-pixel-ratio: 2),
// screen and (min-device-pixel-ratio: 2)
// body
// zoom 2
// @media screen and (-webkit-min-device-pixel-ratio: 2)
// body
// zoom 2
@media screen and (min-width: 3000px) and (min-height: 1200px)
body
zoom 2

@ -86,10 +86,6 @@ img:not([alt])
transition-duration 0.01ms !important transition-duration 0.01ms !important
scroll-behavior auto !important scroll-behavior auto !important
@media (resolution >= 2dppx)
body
zoom 2
section section
position relative position relative
box-sizing border-box box-sizing border-box

@ -31,6 +31,9 @@ export const defaultTheme: AppTheme = {
] ]
} }
const AGIDA_TYPES = ['agida', 'knife', 'yin yang'] as const
export type AgidaTypes = typeof AGIDA_TYPES[number]
export const AppThemes: AppTheme[] = [ export const AppThemes: AppTheme[] = [
{ {
name: 'Agida', name: 'Agida',
@ -55,6 +58,13 @@ export const AppThemes: AppTheme[] = [
['#fc5185', '#3fc1c9'], ['#fc5185', '#3fc1c9'],
['#f5f5f5', '#364f6b'] ['#f5f5f5', '#364f6b']
] ]
},
{
name: 'type',
label: 'type',
type: 'selector',
value: 'agida',
values: AGIDA_TYPES
} }
] ]
}, },

@ -1,4 +1,4 @@
import { AppInputButton, AppInputThemeGeneral, AppInputThemeSlider, AppInputThemeValue, AppTheme } from '@/models/app' import { AppInputButton, AppInputThemeGeneral, AppInputThemePalette, AppInputThemeSlider, AppInputThemeValue, AppTheme } from '@/models/app'
import { AppModule } from '@/store/app' import { AppModule } from '@/store/app'
import { PageModule } from '@/store/page' import { PageModule } from '@/store/page'
import { debounce, DebounceSettings } from 'lodash' import { debounce, DebounceSettings } from 'lodash'
@ -6,7 +6,6 @@ import { RawLocation } from 'vue-router'
import router from '../router' import router from '../router'
import { LightdmHandler } from '@/utils/lightdm' import { LightdmHandler } from '@/utils/lightdm'
const isFinalBuild = process.env.VUE_APP_VIEW === 'build'
export const modKey = 'ctrl' export const modKey = 'ctrl'
export const languageMap: Record<string, string> = { export const languageMap: Record<string, string> = {
ru: 'Русский', ru: 'Русский',
@ -162,18 +161,18 @@ export function hasSomeParentClass(element: HTMLElement, tag: string): boolean {
} }
export function randomizeSettingsTheme(theme: AppTheme) { export function randomizeSettingsTheme(theme: AppTheme) {
const generateValueObject: Record<string, (input: AppInputThemeSlider) => AppInputThemeValue> = { const generateValueObject: Record<string, (input: any) => any> = {
slider: (input: AppInputThemeSlider) => generateRandomSliderValue(input), slider: (input: AppInputThemeSlider) => generateRandomSliderValue(input),
checkbox: () => Math.random() > 0.5, checkbox: () => Math.random() > 0.5,
color: () => generateRandomColor(), color: () => generateRandomColor(),
palette: (input: AppInputThemeGeneral) => Math.floor(randomize(0, (input.values?.length || 2) - 1)) palette: (input: AppInputThemePalette) => Math.floor(randomize(0, (input.values?.length || 2) - 1))
} }
return theme.settings?.map(input => { return theme.settings?.map(input => {
const changeValueFunction = generateValueObject[input.type] const changeValueFunction = generateValueObject[input.type]
if (changeValueFunction) { if (changeValueFunction) {
input.value = changeValueFunction(input as AppInputThemeSlider) input.value = changeValueFunction(input)
} }
return input return input

@ -1,19 +1,68 @@
import { Lightdm } from '@/models/lightdm' import { AppState } from '@/store/app'
import { Greeter } from 'nody-greeter-types'
/**
* INFO: To avoid recoursive requires modules (lightdm and AppModule)
* @returns AppState
*/
async function getAppModule(): Promise<AppState> {
const module = await import('@/store/app') as any
return module.AppModule
}
const DEBUG_PASSWORD = 'password' const DEBUG_PASSWORD = 'password'
const lightdmDebug = window.lightdm === undefined const lightdmDebug = window.lightdm === undefined
const localLight = window.lightdm as unknown as Lightdm
function setIsAuthenticated(value: boolean) {
(window.lightdm as any).is_authenticated = value
}
if (lightdmDebug) { if (lightdmDebug) {
window.lightdm = { window.lightdm = {
is_authenticated: false, is_authenticated: false,
authentication_user: undefined, authentication_user: undefined,
default_session: 'plasma-shell', default_session: 'plasma-shell',
can_access_battery: true,
can_access_brightness: true,
can_suspend: true, can_suspend: true,
can_restart: true, can_restart: true,
can_hibernate: true, can_hibernate: true,
can_shutdown: true, can_shutdown: true,
battery_data: {
level: Math.ceil(Math.random() * 99 + 1),
ac_status: true
},
brightness: Math.ceil(Math.random() * 99 + 1),
battery_update: {
_callbacks: [],
_emit: () => {
window.lightdm?.battery_update._callbacks.forEach((cb) => cb())
},
connect: (callback: () => void) => {
window.lightdm?.battery_update._callbacks.push(callback)
}
},
authentication_complete: {
_callbacks: [],
_emit: () => {
console.log(window.lightdm?.authentication_complete._callbacks)
window.lightdm?.authentication_complete._callbacks.forEach((cb) => cb())
},
connect: (callback: () => void) => {
window.lightdm?.authentication_complete._callbacks.push(callback)
}
},
brightness_update: {
_callbacks: [],
_emit: () => {
window.lightdm?.brightness_update._callbacks.forEach((cb) => cb())
},
connect: (callback: () => void) => {
window.lightdm?.brightness_update._callbacks.push(callback)
}
},
sessions: [ sessions: [
{ {
name: 'i3wm', name: 'i3wm',
@ -60,39 +109,48 @@ if (lightdmDebug) {
} }
], ],
languages: [ languages: [
{
name: 'American English',
code: 'en_US.utf8'
},
{ {
name: 'Русский', name: 'Русский',
code: 'ru_RU.utf8' code: 'ru_RU.utf8'
},
{
name: 'American English',
code: 'en_US.utf8'
} }
], ],
language: 'American English', language: { code: 'en_US', name: 'American English' },
start_authentication: (username: string) => { start_authentication: (username: string) => {
console.log(`Starting authenticating here: '${username}'`) console.log(`Starting authenticating here: '${username}'`)
const inputNode = document.getElementById('password') as HTMLInputElement const inputNode = document.getElementById('password') as HTMLInputElement
localLight.respond(inputNode?.value || '') window.lightdm?.respond(inputNode?.value || '')
}, },
authenticate: (username: string) => { authenticate: (username: string) => {
const inputNode = document.getElementById('password') as HTMLInputElement
console.log(`Starting authenticating user: '${username}'`) console.log(`Starting authenticating user: '${username}'`)
if (window.lightdm) {
(window.lightdm as any).authentication_user = username
}
window.lightdm?.respond(inputNode?.value || '')
}, },
cancel_authentication: () => { cancel_authentication: () => {
console.log('Auth cancelled') console.log('Auth cancelled')
}, },
start_session(session: string) {
alert(`Start session: ${session}`)
},
respond: (password: string) => { respond: (password: string) => {
console.log(`Password provided : '${password}'`) console.log(`Password provided : '${password}'`)
if (password === DEBUG_PASSWORD) { if (password === DEBUG_PASSWORD) {
localLight.is_authenticated = true setIsAuthenticated(true)
} else {
setIsAuthenticated(false)
} }
window.lightdm?.authentication_complete._emit()
window.authentication_complete()
},
login(user: string, session: string) {
alert(`Logged with '${user}' (Session: '${session}') !`)
}, },
shutdown() { shutdown() {
alert('(DEBUG: System is shutting down)') alert('(DEBUG: System is shutting down)')
@ -109,21 +167,17 @@ if (lightdmDebug) {
} as any } as any
} }
const isNode = 'batteryData' in (window.lightdm || {}) const isSupportFullApi = 'battery_data' in (window.lightdm || {})
class LightdmWebkit { class LightdmWebkit {
protected _inputErrorTimer!: null | NodeJS.Timeout protected _inputErrorTimer!: null | NodeJS.Timeout
// get session() {
// return ''
// }
get defaultSession() { get defaultSession() {
return this.sessions[0]?.key || window.lightdm?.default_session || 'i3' return this.sessions[0]?.key || window.lightdm?.default_session || 'i3'
} }
get isNode() { get isSupportFullApi() {
return isNode return isSupportFullApi
} }
get sessions() { get sessions() {
@ -195,96 +249,50 @@ class LightdmWebkit {
} }
} }
class LightdmPython extends LightdmWebkit {
private _password = ''
private _completeCallback!: () => void
constructor() {
super()
this.init()
}
get light() {
return window.lightdm as unknown as Lightdm
}
public login(username: string, password: string, session?: string): void {
this.lightdmLogin(username, password, () => this.lightdmStart(session || this.defaultSession))
}
private lightdmStart(session: string): void {
this.light.login(this.light.authentication_user || '', session)
}
private lightdmLogin(username: string, password: string, callback: () => void) {
this._completeCallback = callback
this._password = password
this.light.start_authentication(username)
}
private init() {
window.authentication_complete = () => {
if (window.lightdm?.is_authenticated && this._completeCallback) {
this._completeCallback()
} else {
this.light.cancel_authentication()
this._setInputError()
}
}
window.show_message = (text) => {
alert(text)
}
window.show_prompt = (text) => {
if (text === 'Password: ') {
if (window.lightdm) {
window.lightdm.respond(this._password)
}
}
}
}
}
class LightdmNode extends LightdmWebkit { class LightdmNode extends LightdmWebkit {
private _username!: string public _username!: string
private _password!: string public _password!: string
private _session!: undefined | string public _session!: string
constructor() { constructor() {
super() super()
this.init() this.init()
} }
get light() {
return window.lightdm as Greeter
}
public login(username: string, password: string, session?: string): void { public login(username: string, password: string, session?: string): void {
this._username = username this._username = username
this._password = password this._password = password
this._session = session this._session = session || this.defaultSession
this.light.authenticate(null) window.lightdm?.authenticate(username)
} }
public setAuthenticationDone(): void { public setAuthenticationDone(): void {
this.light.authentication_complete.connect(() => { window.lightdm?.authentication_complete?.connect(() => {
if (this.light.is_authenticated) { if (window.lightdm?.is_authenticated) {
this.light.start_session(this._session || this.light.default_session) window.lightdm?.start_session(this._session || window.lightdm?.default_session)
} else { } else {
this._authenticationFailed() this._authenticationFailed()
} }
}) })
window.lightdm_cancel_login = () => {
window.lightdm?.cancel_authentication()
}
} }
public _authenticationFailed(): void { private _authenticationFailed(): void {
this.light.cancel_authentication() this._setInputError()
window.lightdm?.cancel_authentication()
} }
public setSignalHandler(): void { public setSignalHandler(): void {
this.light.show_prompt.connect((_message, type) => { window.lightdm?.show_message?.connect(function(text, type) {
console.log({ text, type })
})
window.lightdm?.show_prompt?.connect((_message, type) => {
console.log({ _message, type })
if (!window.lightdm) return if (!window.lightdm) return
if (type === 0) { if (type === 0) {
window.lightdm.respond(this._username) window.lightdm.respond(this._username)
@ -292,6 +300,26 @@ class LightdmNode extends LightdmWebkit {
window.lightdm.respond(this._password) window.lightdm.respond(this._password)
} }
}) })
if (window.lightdm?.can_access_brightness) {
this.updateBrightData()
window.lightdm?.brightness_update.connect(this.updateBrightData)
}
if (window.lightdm?.can_access_battery) {
this.updateBatteryData()
window.lightdm?.battery_update.connect(this.updateBatteryData)
}
}
public async updateBatteryData(): Promise<void> {
const module = await getAppModule()
module.SET_STATE_APP({ key: 'battery', value: window.lightdm?.battery_data })
}
public async updateBrightData(): Promise<void> {
const module = await getAppModule()
module.SET_STATE_APP({ key: 'brightness', value: window.lightdm?.brightness })
} }
public init(): void { public init(): void {
@ -300,4 +328,26 @@ class LightdmNode extends LightdmWebkit {
} }
} }
export const LightdmHandler = isNode ? new LightdmNode() : new LightdmPython() export const LightdmHandler = new LightdmNode()
window.lightdm_cancel_login = () => {
window.lightdm?.cancel_authentication()
}
window.lightdm_start = (desktop: string) => {
window.lightdm?.start_session(desktop)
}
window.show_prompt = (text, type) => {
if (text === 'Password: ' && LightdmHandler._password !== undefined) {
window.lightdm?.respond(LightdmHandler._password)
}
}
window.authentication_complete = () => {
if (window.lightdm?.is_authenticated) {
window.lightdm_start(LightdmHandler._session)
} else if (document.head.dataset.wintype === 'primary') {
window.lightdm?.cancel_authentication()
}
}

@ -0,0 +1,41 @@
import { PageModule } from '@/store/page'
import Vue from 'vue'
import { DateTimeFormatOptions } from 'vue-i18n'
const timeRef = Vue.observable({
time: new Date(),
shortTime: '',
longTime: ''
})
const formatTime = (type: 'long' | 'short' = 'short') => {
const options: DateTimeFormatOptions = {
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
hour12: false
}
if (type === 'long') {
options.month = 'long'
options.weekday = 'long'
}
return new Intl.DateTimeFormat(PageModule.locale, options).format(new Date())
}
export const initTimer = () => {
setInterval(updateTime, 1000)
}
const updateTime = () => {
timeRef.time = new Date()
timeRef.shortTime = formatTime('short')
timeRef.longTime = formatTime('long')
}
updateTime()
export default timeRef

@ -4,6 +4,7 @@ import { LoginPosition } from '@/models/page'
import { AppModule } from '@/store/app' import { AppModule } from '@/store/app'
import { PageModule } from '@/store/page' import { PageModule } from '@/store/page'
import AppBar from '@/components/app/AppBar'
import AppMenu from '@/components/app/AppMenu' import AppMenu from '@/components/app/AppMenu'
import AppDialog from '@/components/app/AppDialog' import AppDialog from '@/components/app/AppDialog'
import SettingsComponent from '@/components/base/SettingsComponent' import SettingsComponent from '@/components/base/SettingsComponent'
@ -66,6 +67,10 @@ export default class HomePage extends Vue {
return !this.isViewThemeOnly && this.isOpenLogin return !this.isViewThemeOnly && this.isOpenLogin
} }
get isSupportFullApi() {
return AppModule.isSupportFullApi
}
created() { created() {
// Set language // Set language
const language = localStorage.getItem('language') || 'en' const language = localStorage.getItem('language') || 'en'
@ -112,6 +117,7 @@ export default class HomePage extends Vue {
{ !this.isViewThemeOnly && <ShutdownButton /> } { !this.isViewThemeOnly && <ShutdownButton /> }
{ this.showGithubButton && <GithubButton /> } { this.showGithubButton && <GithubButton /> }
{ this.isSupportFullApi && <AppBar /> }
<AppDialog /> <AppDialog />
<AppMenu /> <AppMenu />

@ -1,5 +1,6 @@
#!/bin/bash #!/bin/bash
dm-tool add-nested-seat --screen 1366x768 lightdm-webkit2-greeter
# dm-tool add-nested-seat --screen 1366x768
# nody-greeter --debug # yarn build && sudo sh ./install.sh && nody-greeter --debug

Loading…
Cancel
Save