atagen

malice

public
Star0
Watch0
d07bca5da4ae8096444c8411d8ca0c4bf01dee66
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/pack-preferences-model.tsTypescript81 lines2.8 KB
1
import type { ImagePack, QuickReaction } from './types';
2
3
export type DisabledPackImages = Record<string, string[]>;
4
5
function isRecord(value: unknown): value is Record<string, unknown> {
6
  return typeof value === 'object' && value !== null && !Array.isArray(value);
7
}
8
9
function setOwn<T>(record: Record<string, T>, key: string, value: T): void {
10
  Object.defineProperty(record, key, {
11
    configurable: true,
12
    enumerable: true,
13
    value,
14
    writable: true
15
  });
16
}
17
18
function hasOwn(record: object, key: string): boolean {
19
  return Object.prototype.hasOwnProperty.call(record, key);
20
}
21
22
export function parseDisabledPackImages(raw: unknown): DisabledPackImages {
23
  if (!isRecord(raw) || !isRecord(raw['disabled'])) return {};
24
  const disabled: DisabledPackImages = {};
25
  for (const [packId, rawShortcodes] of Object.entries(raw['disabled'])) {
26
    if (!Array.isArray(rawShortcodes)) continue;
27
    const seen = new Set<string>();
28
    const shortcodes = rawShortcodes.filter((value): value is string => {
29
      if (typeof value !== 'string' || value.length === 0 || seen.has(value)) return false;
30
      seen.add(value);
31
      return true;
32
    });
33
    if (shortcodes.length > 0) setOwn(disabled, packId, shortcodes);
34
  }
35
  return disabled;
36
}
37
38
export function imageEnabled(disabled: DisabledPackImages, packId: string, shortcode: string): boolean {
39
  return !hasOwn(disabled, packId) || !disabled[packId].includes(shortcode);
40
}
41
42
export function withImageEnabled(
43
  disabled: DisabledPackImages,
44
  packId: string,
45
  shortcode: string,
46
  enabled: boolean
47
): DisabledPackImages {
48
  const current = hasOwn(disabled, packId) ? disabled[packId] : [];
49
  const nextShortcodes = enabled
50
    ? current.filter((item) => item !== shortcode)
51
    : current.includes(shortcode) ? [...current] : [...current, shortcode];
52
  if (nextShortcodes.length === current.length && nextShortcodes.every((item, index) => item === current[index])) {
53
    return disabled;
54
  }
55
  const next = { ...disabled };
56
  if (nextShortcodes.length === 0) delete next[packId];
57
  else setOwn(next, packId, nextShortcodes);
58
  return next;
59
}
60
61
export function enabledPacks(packs: ImagePack[], disabled: DisabledPackImages): ImagePack[] {
62
  return packs.map((pack) => ({
63
    ...pack,
64
    images: pack.images.filter((image) => imageEnabled(disabled, pack.id, image.shortcode))
65
  }));
66
}
67
68
export function enabledQuickReactions(
69
  quick: QuickReaction[],
70
  packs: ImagePack[],
71
  disabled: DisabledPackImages
72
): QuickReaction[] {
73
  const hidden = new Set<string>();
74
  const enabled = new Set<string>();
75
  for (const pack of packs) {
76
    for (const image of pack.images) {
77
      (imageEnabled(disabled, pack.id, image.shortcode) ? enabled : hidden).add(image.reaction_key);
78
    }
79
  }
80
  return quick.filter((reaction) => !hidden.has(reaction.key) || enabled.has(reaction.key));
81
}