Skip to content

Commit

Permalink
Added app-specific settings
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsRiprod committed Oct 30, 2024
1 parent 0becf2e commit 7103801
Show file tree
Hide file tree
Showing 20 changed files with 561 additions and 158 deletions.
99 changes: 99 additions & 0 deletions DeskThingServer/src/main/handlers/musicHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import dataListener, { MESSAGE_TYPES } from '../utils/events'
import settingsStore from '../stores/settingsStore'
import { Settings, SocketData } from '@shared/types'
import { sendMessageToApp } from '../services/apps'
import { getAppByName } from './configHandler'

export class MusicHandler {
private static instance: MusicHandler
private refreshInterval: NodeJS.Timeout | null = null
private currentApp: string | null = null

private constructor() {
this.initializeRefreshInterval()
}

public static getInstance(): MusicHandler {
if (!MusicHandler.instance) {
MusicHandler.instance = new MusicHandler()
}
return MusicHandler.instance
}

private async initializeRefreshInterval(): Promise<void> {
const settings = await settingsStore.getSettings() // Get from your settings store
this.updateRefreshInterval(settings.refreshInterval)
dataListener.on(MESSAGE_TYPES.SETTINGS, this.handleSettingsUpdate)
}

private handleSettingsUpdate = (settings: Settings): void => {
this.updateRefreshInterval(settings.refreshInterval)

if (settings.playbackLocation && settings.playbackLocation !== this.currentApp) {
this.currentApp = settings.playbackLocation
}
}

public updateRefreshInterval(refreshRate: number): void {
if (this.refreshInterval) {
clearInterval(this.refreshInterval)
}

if (refreshRate < 0) {
dataListener.asyncEmit(MESSAGE_TYPES.LOGGING, `[MusicHandler]: Cancelling Refresh Interval!`)
return
}

this.refreshInterval = setInterval(() => {
this.refreshMusicData()
}, refreshRate)
}

private async refreshMusicData(): Promise<void> {
if (!this.currentApp || this.currentApp.length == 0) {
dataListener.asyncEmit(MESSAGE_TYPES.ERROR, `[MusicHandler]: No current app set!`)
return
}

const app = await getAppByName(this.currentApp)

if (!app || app.running == false) {
dataListener.asyncEmit(
MESSAGE_TYPES.ERROR,
`[MusicHandler]: App ${this.currentApp} not found or not running!!`
)
}

try {
await sendMessageToApp(this.currentApp, { type: 'get', request: 'refresh', payload: '' })
dataListener.asyncEmit(MESSAGE_TYPES.LOGGING, `[MusicHandler]: Refreshing Music Data!`)
} catch (error) {
dataListener.asyncEmit(MESSAGE_TYPES.ERROR, `[MusicHandler]: Music refresh failed: ${error}`)
}
}

public async handleClientRequest(request: SocketData): Promise<void> {
if (!this.currentApp) return
if (request.app != 'music' && request.app != 'utility') return

if (request.app == 'utility') {
dataListener.asyncEmit(
MESSAGE_TYPES.LOGGING,
`[MusicHandler]: Legacy Name called! Support for this will be dropped in future updates. Migrate your app to use 'music' instead!`
)
}

dataListener.asyncEmit(
MESSAGE_TYPES.LOGGING,
`[MusicHandler]: ${request.type} ${request.request}`
)

sendMessageToApp(this.currentApp, {
type: request.type,
request: request.request,
payload: request.payload
})
}
}

export default MusicHandler.getInstance()
12 changes: 11 additions & 1 deletion DeskThingServer/src/main/services/client/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
sendSettingsData
} from './clientCom'
import { sendIpcData } from '../..'
import MusicHandler from '../../handlers/musicHandler'

export let server: WebSocketServer | null = null
export let httpServer: HttpServer
Expand Down Expand Up @@ -177,14 +178,23 @@ export const setupServer = async (): Promise<void> => {
messageThrottles.set(messageKey, now)

// Handle non-server messages
if (messageData.app && messageData.app !== 'server') {
if (
messageData.app &&
messageData.app !== 'server' &&
messageData.app !== 'utility' &&
messageData.app !== 'music'
) {
sendMessageToApp(messageData.app.toLowerCase(), {
type: messageData.type,
request: messageData.request,
payload: messageData.payload
})
} else if (messageData.app === 'server') {
// Handle server requests
handleServerMessage(socket, client, messageData)
} else if (messageData.app === 'utility' || messageData.app === 'music') {
// Handle music requests
MusicHandler.handleClientRequest(messageData)
}

// Cleanup throttle
Expand Down
6 changes: 4 additions & 2 deletions DeskThingServer/src/main/stores/settingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import dataListener, { MESSAGE_TYPES } from '../utils/events'
import os from 'os'
import { Settings } from '@shared/types'

const settingsVersion = '0.9.0'
const version_code = 9.0
const settingsVersion = '0.9.1'
const version_code = 9.1

class SettingsStore {
private settings: Settings
Expand Down Expand Up @@ -116,6 +116,8 @@ class SettingsStore {
minimizeApp: true,
globalADB: false,
autoDetectADB: false,
refreshInterval: -1,
playbackLocation: undefined,
localIp: getLocalIpAddress(),
appRepos: ['https://github.com/ItsRiprod/deskthing-apps'],
clientRepos: ['https://github.com/ItsRiprod/deskthing-client']
Expand Down
21 changes: 21 additions & 0 deletions DeskThingServer/src/renderer/src/assets/icons/icon/IconMusic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Icon } from '.'

function IconMusic(props): JSX.Element {
return (
<Icon {...props}>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
>
<circle cx="8" cy="18" r="4" />
<path d="M12 18V2l7 4" />
</svg>
</Icon>
)
}

export default IconMusic
18 changes: 18 additions & 0 deletions DeskThingServer/src/renderer/src/assets/icons/icon/IconStop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Icon, IconProps } from '.'

function IconStop(props: IconProps): JSX.Element {
return (
<Icon {...props}>
<svg viewBox="0 0 16 16" fill={props.fill || 'none'}>
<path
d="M3.28683 3.28634L12.7135 12.713M14.6668 7.99967C14.6668 11.6816 11.6821 14.6663 8.00016 14.6663C4.31826 14.6663 1.3335 11.6816 1.3335 7.99967C1.3335 4.31778 4.31826 1.33301 8.00016 1.33301C11.6821 1.33301 14.6668 4.31778 14.6668 7.99967Z"
stroke="white"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</Icon>
)
}

export default IconStop
25 changes: 25 additions & 0 deletions DeskThingServer/src/renderer/src/assets/icons/icon/IconTrash.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Icon } from '.'

function IconTrash(props): JSX.Element {
return (
<Icon {...props}>
<svg viewBox="0 0 17 16" fill="none">
<g clipPath="url(#clip0_268_267)">
<path
d="M2.16699 3.99967H3.50033M3.50033 3.99967H14.167M3.50033 3.99967V13.333C3.50033 13.6866 3.6408 14.0258 3.89085 14.2758C4.1409 14.5259 4.48004 14.6663 4.83366 14.6663H11.5003C11.8539 14.6663 12.1931 14.5259 12.4431 14.2758C12.6932 14.0258 12.8337 13.6866 12.8337 13.333V3.99967M5.50033 3.99967V2.66634C5.50033 2.31272 5.6408 1.97358 5.89085 1.72353C6.1409 1.47348 6.48004 1.33301 6.83366 1.33301H9.50033C9.85395 1.33301 10.1931 1.47348 10.4431 1.72353C10.6932 1.97358 10.8337 2.31272 10.8337 2.66634V3.99967M6.83366 7.33301V11.333M9.50033 7.33301V11.333"
stroke={'white'}
strokeLinecap="round"
strokeLinejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_268_267">
<rect width="16" height="16" fill="white" transform="translate(0.166992)" />
</clipPath>
</defs>
</svg>
</Icon>
)
}

export default IconTrash
6 changes: 3 additions & 3 deletions DeskThingServer/src/renderer/src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export { default as IconLogoGear } from './icon/IconLogoGear'
export { default as IconLogo } from './icon/IconLogo'
export { default as IconLogs } from './icon/IconLogs'
export { default as IconLink } from './icon/IconLink'
export { default as IconMusic } from './icon/IconMusic'
export { default as IconTrash } from './icon/IconTrash'
export { default as IconToggle } from './icon/IconToggle'
export { default as IconMobile } from './icon/IconMobile'
export { default as IconCheckCircle } from './icon/IconCheckCircle'
Expand All @@ -42,15 +44,13 @@ export { default as IconFolderOpen } from './icon/IconFolderOpen'
export { default as IconComputer } from './icon/IconComputer'
export { default as IconX } from './icon/IconX'
export { default as IconGlobe } from './icon/IconGlobe'

export { default as IconStop } from './icon/IconStop'
export { default as IconEye } from './icon/IconEye'

export { default as IconPulsing } from './icon/IconPulsing'
export { default as IconReload } from './icon/IconReload'
export { default as IconSave } from './icon/IconSave'
export { default as IconServer } from './icon/IconServer'
export { default as IconDetails } from './icon/IconDetails'

export { default as IconGear } from './icon/IconGear'
export { default as IconHeart } from './icon/IconHeart'
export { default as IconHeartActive } from './icon/IconHeartActive'
Expand Down
2 changes: 1 addition & 1 deletion DeskThingServer/src/renderer/src/components/Connection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ const ConnectionComponent: React.FC<ConnectionComponentProps> = ({ client }) =>
{!client.connected && offline ? (
<p className="text-red-500 italic">Device Offline!</p>
) : (
<p className="text-red-500 italic">Not Connected!</p>
!client.connected && <p className="text-red-500 italic">Not Connected!</p>
)}
{client.adbId && !offline && (
<>
Expand Down
69 changes: 59 additions & 10 deletions DeskThingServer/src/renderer/src/overlays/apps/AppActions.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,72 @@
import React from 'react'
import { AppSettingProps } from './AppsOverlay'
import Button from '@renderer/components/Button'
import { IconPlay, IconX } from '@renderer/assets/icons'
import { IconPlay, IconStop, IconTrash, IconX } from '@renderer/assets/icons'
import { useAppStore } from '@renderer/stores'

const AppActions: React.FC<AppSettingProps> = ({ app }: AppSettingProps) => {
const stopApp = useAppStore((state) => state.stopApp)
const runApp = useAppStore((state) => state.runApp)
const disableApp = useAppStore((state) => state.disableApp)
const enableApp = useAppStore((state) => state.enableApp)

const handlePurge = (): void => {
window.electron.purgeApp(app.name)
}

return (
<div className="w-full h-full p-4 flex flex-col divide-y-2 divide-gray-500">
<Button>
<IconPlay />
<p>Do Stuff</p>
</Button>
<Button onClick={handlePurge} className="hover:bg-red-500">
<IconX />
<p>Purge</p>
</Button>
<div className="w-full h-full p-4 flex flex-col">
<div className="flex w-full gap-5">
<Button
onClick={handlePurge}
className="justify-center gap-2 hover:bg-red-500 border-red-500 border w-full"
>
<IconTrash className="stroke-2" />
<p>Purge</p>
</Button>

{app.enabled ? (
<Button
onClick={() => disableApp(app.name)}
className="justify-center gap-2 hover:bg-red-500 border-red-500 border w-full"
>
<IconStop className="stroke-2" />
<p>Disable</p>
</Button>
) : (
<Button
onClick={() => enableApp(app.name)}
className="justify-center gap-2 border hover:bg-green-500 border-green-500 w-full"
>
<IconPlay className="stroke-2" />
<p>Enable</p>
</Button>
)}
{app.running ? (
<Button
onClick={() => stopApp(app.name)}
className="justify-center gap-2 hover:bg-red-500 border-red-500 border w-full"
>
<IconX className="stroke-2" />
<p>Stop</p>
</Button>
) : (
<Button
onClick={() => runApp(app.name)}
className={`justify-center gap-2 border ${app.enabled ? 'hover:bg-cyan-500 border-cyan-500' : 'hover:bg-cyan-950 border-cyan-900'} w-full`}
disabled={!app.enabled}
>
<IconPlay className="stroke-2" />
<p>Run</p>
</Button>
)}
</div>
<div className="text-xs text-gray-500 font-geistMono mt-4">
<h1>
{app.manifest?.label || app.name} is {app.running ? 'running' : 'not running'}
</h1>
<h1>App will {app.enabled ? 'Start Automatically' : 'Not Start Automatically'}</h1>
</div>
</div>
)
}
Expand Down
Loading

0 comments on commit 7103801

Please sign in to comment.