Toggle pills

This commit is contained in:
WBHarry 2026-06-09 23:38:29 +02:00
parent afd8a83241
commit 208e8192b4
14 changed files with 223 additions and 92 deletions

View file

@ -35,7 +35,7 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio
static PARTS = {
countdowns: {
template: 'systems/daggerheart/templates/ui/countdown-edit.hbs',
template: 'systems/daggerheart/templates/ui/countdowns/countdown-edit.hbs',
scrollable: ['.expanded-view', '.edit-content']
}
};
@ -45,7 +45,7 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio
context.isGM = game.user.isGM;
context.ownershipDefaultOptions = CONFIG.DH.GENERAL.basicOwnershiplevels;
context.defaultOwnership = this.data.defaultOwnership;
context.countdownBaseTypes = CONFIG.DH.GENERAL.countdownBaseTypes;
context.countdownTypes = CONFIG.DH.GENERAL.countdownType;
context.countdownProgressionTypes = CONFIG.DH.GENERAL.countdownProgressionTypes;
context.countdownLoopingTypes = CONFIG.DH.GENERAL.countdownLoopingTypes;
context.hideNewCountdowns = this.hideNewCountdowns;
@ -62,7 +62,7 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio
const randomizeValid = !new Roll(countdown.progress.startFormula ?? '').isDeterministic;
acc[key] = {
...countdown,
typeName: game.i18n.localize(CONFIG.DH.GENERAL.countdownBaseTypes[countdown.type].label),
typeName: game.i18n.localize(CONFIG.DH.GENERAL.countdownType[countdown.type].label),
progress: {
...countdown.progress,
typeName: game.i18n.localize(

View file

@ -11,9 +11,14 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
*/
export default class DhCountdowns extends HandlebarsApplicationMixin(ApplicationV2) {
previusCountdownData = null;
countdownChangeAnimationTimeout = null;
constructor(options = {}) {
super(options);
this.previusCountdownData =
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).countdowns;
this.setupHooks();
}
@ -32,6 +37,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
},
actions: {
toggleViewMode: DhCountdowns.#onToggleViewMode,
onToggleCountdownTypes: DhCountdowns.#onToggleCountdownTypes,
editCountdowns: DhCountdowns.#onEditCountdowns,
loopCountdown: DhCountdowns.#onLoopCountdown,
decreaseCountdown: (_, target) => this.editCountdown(false, target),
@ -48,7 +54,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
static PARTS = {
resources: {
root: true,
template: 'systems/daggerheart/templates/ui/countdowns.hbs'
template: 'systems/daggerheart/templates/ui/countdowns/countdowns-view.hbs'
}
};
@ -76,16 +82,14 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
return values.filter(v => v.ownership !== CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE);
}
/** @override */
async _prepareContext(options) {
const context = await super._prepareContext(options);
context.isGM = game.user.isGM;
context.iconOnly =
game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode) ===
CONFIG.DH.GENERAL.countdownAppMode.iconOnly;
_getCountdownData() {
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
context.countdowns = this.#getCountdowns().reduce((acc, { key, countdown, ownership }) => {
const typeModes = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes) ?? [];
return this.#getCountdowns().reduce((acc, { key, countdown, ownership }) => {
if (!typeModes.includes(countdown.type))
return acc;
const playersWithAccess = game.users.reduce((acc, user) => {
const ownership = DhCountdowns.#getPlayerOwnership(user, setting, countdown);
if (!user.isGM && ownership && ownership !== CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE) {
@ -118,6 +122,27 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
};
return acc;
}, {});
}
/** @override */
async _prepareContext(options) {
const context = await super._prepareContext(options);
context.isGM = game.user.isGM;
this.previusCountdownData =
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).countdowns;
context.iconOnly =
game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode) ===
CONFIG.DH.GENERAL.countdownAppMode.iconOnly;
const userCountdownTypes = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes) ?? [];
context.typeToggles = Object.values(CONFIG.DH.GENERAL.countdownType).map(type => ({
type: type.id,
label: game.i18n.localize(type.label),
active: userCountdownTypes.includes(type.id)
}));
context.countdowns = this._getCountdownData();
return context;
}
@ -158,6 +183,36 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
this.render();
}
static async #onToggleCountdownTypes(event, target) {
const currentTypes = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes) ?? [];
const { type } = target.dataset;
const newTypes = event.shiftKey ?
[type] :
currentTypes.includes(type) ? currentTypes.filter(x => x !== type) : [...currentTypes, type];
await game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownTypeModes, newTypes);
for (const type of Object.keys(CONFIG.DH.GENERAL.countdownType)) {
const toggleElement = this.element.querySelector(`.header-type-toggles .header-type[data-type="${type}"]`);
if (newTypes.includes(type))
toggleElement.classList.remove('inactive');
else
toggleElement.classList.add('inactive');
}
const updatedCountdownsElement = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/ui/countdowns/parts/countdowns.hbs',
{
countdowns: this._getCountdownData(),
iconOnly: game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode) ===
CONFIG.DH.GENERAL.countdownAppMode.iconOnly,
isGM: game.user.isGM
}
);
this.element.querySelector('#countdowns .countdowns-container').innerHTML = updatedCountdownsElement;
}
static async #onEditCountdowns() {
new game.system.api.applications.ui.CountdownEdit().render(true);
}
@ -212,6 +267,10 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
}
static async gmSetSetting(data) {
// if(Object.keys(data).some(x => x.includes('countdowns'))) {
// this.previusCountdownData = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).countdowns;
// }
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data);
game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.Refresh,
@ -270,6 +329,20 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
});
}
/**
*
* @param {*} context
* @param {*} options
*/
async performChangeAnimations(changedCountdowns) {
if (this.countdownChangeAnimationTimeout)
clearTimeout(this.countdownChangeAnimationTimeout);
this.countdownChangeAnimationTimeout = setTimeout(() => {
}, 3000);
}
async _onRender(context, options) {
await super._onRender(context, options);
this.element.hidden = !game.user.isGM && this.#getCountdowns().length === 0;

View file

@ -24,7 +24,8 @@ export const itemAttachmentSource = 'attachmentSource';
export const userFlags = {
welcomeMessage: 'welcome-message',
countdownMode: 'countdown-mode'
countdownMode: 'countdown-mode',
countdownTypeModes: 'countdown-type-modes'
};
export const combatToggle = 'combat-toggle-origin';

View file

@ -935,17 +935,6 @@ export const simpleOwnershiplevels = {
...basicOwnershiplevels
};
export const countdownBaseTypes = {
narrative: {
id: 'narrative',
label: 'DAGGERHEART.APPLICATIONS.Countdown.types.narrative'
},
encounter: {
id: 'encounter',
label: 'DAGGERHEART.APPLICATIONS.Countdown.types.encounter'
}
};
export const countdownLoopingTypes = {
noLooping: {
id: 'noLooping',
@ -970,6 +959,17 @@ export const countdownAppMode = {
iconOnly: 'icon-only'
};
export const countdownType = {
shortterm: {
id: 'shortterm',
label: 'Short'
},
longterm: {
id: 'longterm',
label: 'Long'
}
};
export const sceneRangeMeasurementSetting = {
disable: {
id: 'disable',

View file

@ -13,6 +13,33 @@ export default class DhCountdowns extends foundry.abstract.DataModel {
})
};
}
handleChange() {
const previousCountdowns = foundry.ui.countdowns.previusCountdownData;
const changedCountdowns = Object.values(this.countdowns).reduce((acc, [key, countdown]) => {
const previousCountdown = previousCountdowns[key];
if (!previousCountdown || (previousCountdown.current !== countdown.current)) {
acc.push(key);
}
return acc;
}, []);
foundry.ui.performChangeAnimations(changedCountdowns);
}
migrateData(source) {
for (const countdown of source.countdowns) {
switch (countdown.type) {
case 'narrative':
countdown.type = CONFIG.DH.GENERAL.countdownType.longterm.id;
break;
case 'encounter':
countdown.type = CONFIG.DH.GENERAL.countdownType.shortterm.id;
break;
}
}
}
}
export class DhCountdown extends foundry.abstract.DataModel {
@ -21,7 +48,8 @@ export class DhCountdown extends foundry.abstract.DataModel {
return {
type: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.countdownBaseTypes,
choices: CONFIG.DH.GENERAL.countdownType,
initial: CONFIG.DH.GENERAL.countdownType.shortterm.id,
label: 'DAGGERHEART.GENERAL.type'
}),
name: new fields.StringField({
@ -85,7 +113,7 @@ export class DhCountdown extends foundry.abstract.DataModel {
: undefined;
return {
type: type ?? CONFIG.DH.GENERAL.countdownBaseTypes.narrative.id,
type: type ?? CONFIG.DH.GENERAL.countdownType.shortterm.id,
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Countdown.newCountdown'),
img: 'icons/magic/time/hourglass-yellow-green.webp',
ownership: ownership,

View file

@ -8,8 +8,8 @@ export default class CountdownField extends fields.ArrayField {
...game.system.api.data.countdowns.DhCountdown.defineSchema(),
type: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.countdownBaseTypes,
initial: CONFIG.DH.GENERAL.countdownBaseTypes.encounter.id,
choices: CONFIG.DH.GENERAL.countdownType,
initial: CONFIG.DH.GENERAL.countdownType.shortterm.id,
label: 'DAGGERHEART.GENERAL.type'
}),
name: new fields.StringField({

View file

@ -50,6 +50,7 @@ export const preloadHandlebarsTemplates = async function () {
'systems/daggerheart/templates/ui/chat/parts/target-part.hbs',
'systems/daggerheart/templates/ui/chat/parts/button-part.hbs',
'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs',
'systems/daggerheart/templates/ui/countdowns/parts/countdowns.hbs',
'systems/daggerheart/templates/scene/dh-config.hbs',
'systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs',
'systems/daggerheart/templates/sheets/activeEffect/typeChanges/armorChange.hbs'

View file

@ -178,8 +178,8 @@ export async function runMigrations() {
await countdownSettings.updateSource({
countdowns: {
...getCountdowns(countdownSettings.narrative, CONFIG.DH.GENERAL.countdownBaseTypes.narrative.id),
...getCountdowns(countdownSettings.encounter, CONFIG.DH.GENERAL.countdownBaseTypes.encounter.id)
...getCountdowns(countdownSettings.narrative, 'narrative'),
...getCountdowns(countdownSettings.encounter, 'encounter')
}
});
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, countdownSettings);

View file

@ -199,7 +199,10 @@ const registerNonConfigSettings = () => {
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, {
scope: 'world',
config: false,
type: DhCountdowns
type: DhCountdowns,
onChange: value => {
value.handleChange();
}
});
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings, {