Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Part-Button-View-Mode #183

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion apps/app/src/electron/EverythingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
} from '../lib/util'
import { PartialDeep } from 'type-fest'
import deepExtend from 'deep-extend'
import { Group, PlayingPart } from '../models/rundown/Group'
import { Group, GroupViewMode, PlayingPart } from '../models/rundown/Group'
import { Part } from '../models/rundown/Part'
import {
TSRTimelineObj,
Expand Down Expand Up @@ -2162,6 +2162,56 @@ export class EverythingService implements ConvertToServerSide<IPCServerMethods>
ledgerKey: arg.rundownId,
}
}
async setGroupViewMode(arg: {
rundownId: string
groupId: string
viewMode: GroupViewMode
}): Promise<UndoableResult<void>> {
const { rundown, group } = this.getGroup(arg)
const originalValue = group.viewMode

group.viewMode = arg.viewMode

this._saveUpdates({ rundownId: arg.rundownId, rundown, group, noEffectOnPlayout: true })

return {
undo: () => {
const { rundown, group } = this.getGroup(arg)

group.viewMode = originalValue

this._saveUpdates({ rundownId: arg.rundownId, rundown, group, noEffectOnPlayout: true })
},
description: ActionDescription.ToggleGroupCollapse,
}
}
async setAllGroupsViewMode(arg: { rundownId: string; viewMode: GroupViewMode }): Promise<UndoableResult<void>> {
const { rundown } = this.getRundown(arg)

const originalValues = new Map<string, GroupViewMode>(rundown.groups.map((g) => [g.id, g.viewMode]))

for (const group of rundown.groups) {
group.viewMode = arg.viewMode
}

this._saveUpdates({ rundownId: arg.rundownId, rundown, noEffectOnPlayout: true })

return {
undo: () => {
const { rundown } = this.getRundown(arg)

for (const group of rundown.groups) {
const originalValue = originalValues.get(group.id)
if (originalValue !== undefined) {
group.viewMode = originalValue
}
}

this._saveUpdates({ rundownId: arg.rundownId, rundown, noEffectOnPlayout: true })
},
description: ActionDescription.ToggleAllGroupsCollapse,
}
}
async refreshResources(): Promise<void> {
this.callbacks.refreshResources()
}
Expand Down
20 changes: 19 additions & 1 deletion apps/app/src/electron/api/GroupService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PartialDeep } from 'type-fest/source/partial-deep'
import { ClientEventBus } from '../ClientEventBus'
import { ResourceAny } from '@shared/models'
import { MoveTarget } from '../../lib/util'
import { Group } from '../../models/rundown/Group'
import { Group, GroupViewMode } from '../../models/rundown/Group'
import { ServiceTypes } from '../../ipc/IPCAPI'

interface GroupData {
Expand Down Expand Up @@ -96,4 +96,22 @@ export class GroupService extends EventEmitter {
const result = await this.everythingService.duplicateGroup(data)
if (!result) throw new GeneralError()
}

async setViewMode(data: { rundownId: string; groupId: string; viewMode: GroupViewMode }): Promise<void> {
// TODO: access control
const result = await this.everythingService.setGroupViewMode({
rundownId: data.rundownId,
groupId: data.groupId,
viewMode: data.viewMode,
})
if (!result) throw new GeneralError()
}
async setAllViewMode(data: { rundownId: string; viewMode: GroupViewMode }): Promise<void> {
// TODO: access control
const result = await this.everythingService.setAllGroupsViewMode({
rundownId: data.rundownId,
viewMode: data.viewMode,
})
if (!result) throw new GeneralError()
}
}
4 changes: 4 additions & 0 deletions apps/app/src/electron/storageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ensureValidId, ensureValidObject } from '../lib/TimelineObj'
import { AnalogInput } from '../models/project/AnalogInput'
import { ValidatorCache } from 'graphics-data-definition'
import { Bridge } from '../models/project/Bridge'
import { GroupViewMode } from '../models/rundown/Group'

const fsWriteFile = fs.promises.writeFile
const fsAppendFile = fs.promises.appendFile
Expand Down Expand Up @@ -1245,6 +1246,9 @@ export class StorageHandler extends EventEmitter {
playingParts: {},
}
}
if (group.viewMode === undefined) {
group.viewMode = GroupViewMode.TIMELINE
}
if (!group.autoFill) {
group.autoFill = getDefaultGroup().autoFill
}
Expand Down
6 changes: 5 additions & 1 deletion apps/app/src/ipc/IPCAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ResourceAny, ResourceId, MetadataAny, SerializedProtectedMap, TSRDevice
import { Rundown } from '../models/rundown/Rundown'
import { TimelineObj } from '../models/rundown/TimelineObj'
import { Part } from '../models/rundown/Part'
import { Group } from '../models/rundown/Group'
import { Group, GroupViewMode } from '../models/rundown/Group'
import { AppData } from '../models/App/AppData'
import { PeripheralArea, PeripheralStatus } from '../models/project/Peripheral'
import { ActiveTrigger, ActiveTriggers, ApplicationTrigger, RundownTrigger } from '../models/rundown/Trigger'
Expand Down Expand Up @@ -64,6 +64,8 @@ export const ClientMethods: ServiceKeyArrays = {
'playPrev',
'remove',
'update',
'setViewMode',
'setAllViewMode',
],
[ServiceName.LEGACY]: [],
[ServiceName.PARTS]: [
Expand Down Expand Up @@ -303,6 +305,8 @@ export interface IPCServerMethods {
toggleGroupLock: (arg: { rundownId: string; groupId: string; value: boolean }) => void
toggleGroupCollapse: (arg: { rundownId: string; groupId: string; value: boolean }) => void
toggleAllGroupsCollapse: (arg: { rundownId: string; value: boolean }) => void
setGroupViewMode: (arg: { rundownId: string; groupId: string; viewMode: GroupViewMode }) => void
setAllGroupsViewMode: (arg: { rundownId: string; viewMode: GroupViewMode }) => void
refreshResources: () => void
refreshResourcesSetAuto: (arg: { interval: number }) => void
triggerHandleAutoFill: () => void
Expand Down
3 changes: 2 additions & 1 deletion apps/app/src/lib/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Project } from '../models/project/Project'
import { Rundown } from '../models/rundown/Rundown'
import { AutoFillMode, AutoFillSortMode, Group, PlayoutMode } from '../models/rundown/Group'
import { AutoFillMode, AutoFillSortMode, Group, GroupViewMode, PlayoutMode } from '../models/rundown/Group'
import { INTERNAL_BRIDGE_ID } from '../models/project/Bridge'
import { DeviceType, MappingCasparCG, TimelineContentTypeCasparCg } from 'timeline-state-resolver-types'
import { literal } from '@shared/lib'
Expand Down Expand Up @@ -241,6 +241,7 @@ export function getDefaultGroup(): Omit<Group, 'id' | 'name'> {
type: RepeatingType.NO_REPEAT,
},
},
viewMode: GroupViewMode.TIMELINE,
}
}
export function getDefaultPart(): Omit<Part, 'id' | 'name'> {
Expand Down
9 changes: 5 additions & 4 deletions apps/app/src/lib/partTimeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ interface SortedLayer {
layerId: string
objectIds: string[]
}
export interface TimelineObjectsOnLayer {
layerId: string
objectsOnLayer: Array<{ resolved: ResolvedTimelineObject['resolved']; timelineObj: TimelineObj }>
}
export function timelineObjsOntoLayers(
sortedLayers: SortedLayer[],
resolvedTimeline: ResolvedTimeline,
timeline: TimelineObj[]
): Array<{
layerId: string
objectsOnLayer: Array<{ resolved: ResolvedTimelineObject['resolved']; timelineObj: TimelineObj }>
}> {
): Array<TimelineObjectsOnLayer> {
return sortedLayers.map(({ layerId, objectIds }) => {
const objectsOnLayer: {
resolved: ResolvedTimelineObject['resolved']
Expand Down
8 changes: 8 additions & 0 deletions apps/app/src/models/rundown/Group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export interface GroupBase {
/** Whether or not this Group should be visually collapsed in the app view. Does not affect playout. */
collapsed?: boolean

/** How the group is displayed in the GUI. Defaults to Timeline. */
viewMode: GroupViewMode

/** An additional, optional ID to be used by API clients to track the Groups they are responsible for */
externalId?: string
}
Expand Down Expand Up @@ -104,3 +107,8 @@ export interface ScheduleSettings {
startTime?: DateTimeObject
repeating: RepeatingSettingsAny
}

export enum GroupViewMode {
TIMELINE = 0, // default
BUTTONS = 1,
}
6 changes: 6 additions & 0 deletions apps/app/src/react/api/ApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ export class ApiClient {
): ServerReturn<'toggleAllGroupsCollapse'> {
return this.invokeServerMethod('toggleAllGroupsCollapse', ...args)
}
async setGroupViewMode(...args: ServerArgs<'setGroupViewMode'>): ServerReturn<'setGroupViewMode'> {
return this.groupService.setViewMode(...args)
}
async setAllGroupsViewMode(...args: ServerArgs<'setAllGroupsViewMode'>): ServerReturn<'setAllGroupsViewMode'> {
return this.groupService.setAllViewMode(...args)
}
async refreshResources(...args: ServerArgs<'refreshResources'>): ServerReturn<'refreshResources'> {
return this.invokeServerMethod('refreshResources', ...args)
}
Expand Down
16 changes: 8 additions & 8 deletions apps/app/src/react/components/inputs/Btn/style.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
@use 'sass:color';
@import './../../../styles/foundation/variables';

$btnTextColor: #fff;
$btnBgColor: #545a78;

.btn {
cursor: pointer;
display: inline-flex;
Expand All @@ -19,18 +23,13 @@
text-transform: uppercase;
border-radius: 4px;

color: #fff;
background: #545a78;
color: $btnTextColor;
background: $btnBgColor;
padding: 6px 16px;
min-width: 22px;
min-height: 22px;
border: none;
// background: none;
// opacity: 0.3;

// &.selected {
// opacity: 1;
// }
transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, border-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
Expand All @@ -48,7 +47,8 @@
}

&.disabled {
opacity: 0.5;
color: color.adjust($btnTextColor, $lightness: -40%);
background: color.adjust($btnBgColor, $lightness: -10%);
pointer-events: none;
cursor: inherit;
}
Expand Down
Loading
Loading