aboutsummaryrefslogtreecommitdiff
path: root/.config/ags/widget/launcher/AppLauncher.ts
blob: 08258dee45b202895c940cd5f9c4b07550f1d28d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { type Application } from 'types/service/applications';
import { launchApp, icon } from 'lib/utils';
import options from 'options';
import icons from 'lib/icons';

const apps = await Service.import('applications');
const { query } = apps;
const { iconSize } = options.launcher.apps;

const QuickAppButton = (app: Application) =>
  Widget.Button({
    hexpand: true,
    tooltip_text: app.name,
    on_clicked: () => {
      App.closeWindow('launcher');
      launchApp(app);
    },
    child: Widget.Icon({
      size: iconSize.bind(),
      icon: icon(app.icon_name, icons.fallback.executable),
    }),
  });

const AppItem = (app: Application) => {
  const title = Widget.Label({
    class_name: 'title',
    label: app.name,
    hexpand: true,
    xalign: 0,
    vpack: 'center',
    truncate: 'end',
  });

  const description = Widget.Label({
    class_name: 'description',
    label: app.description || '',
    hexpand: true,
    wrap: true,
    max_width_chars: 30,
    xalign: 0,
    justification: 'left',
    vpack: 'center',
  });

  const appicon = Widget.Icon({
    icon: icon(app.icon_name, icons.fallback.executable),
    size: iconSize.bind(),
  });

  const textBox = Widget.Box({
    vertical: true,
    vpack: 'center',
    children: app.description ? [title, description] : [title],
  });

  return Widget.Button({
    class_name: 'app-item',
    attribute: { app },
    child: Widget.Box({
      children: [appicon, textBox],
    }),
    on_clicked: () => {
      App.closeWindow('launcher');
      launchApp(app);
    },
  });
};
export function Favorites() {
  const favs = options.launcher.apps.favorites.bind();
  return Widget.Revealer({
    visible: favs.as(f => f.length > 0),
    child: Widget.Box({
      vertical: true,
      children: favs.as(favs =>
        favs.flatMap(fs => [
          Widget.Separator(),
          Widget.Box({
            class_name: 'quicklaunch horizontal',
            children: fs
              .map(f => query(f)?.[0])
              .filter(f => f)
              .map(QuickAppButton),
          }),
        ]),
      ),
    }),
  });
}

export function Launcher() {
  const applist = Variable(query(''));
  const max = options.launcher.apps.max;
  let first = applist.value[0];

  function SeparatedAppItem(app: Application) {
    return Widget.Revealer({ attribute: { app } }, Widget.Box({ vertical: true }, Widget.Separator(), AppItem(app)));
  }

  const list = Widget.Box({
    vertical: true,
    children: applist.bind().as(list => list.map(SeparatedAppItem)),
    setup: self => self.hook(apps, () => (applist.value = query('')), 'notify::frequents'),
  });

  return Object.assign(list, {
    filter(text: string | null) {
      first = query(text || '')[0];
      list.children.reduce((i, item) => {
        if (!text || i >= max.value) {
          item.reveal_child = false;
          return i;
        }
        if (item.attribute.app.match(text)) {
          item.reveal_child = true;
          return ++i;
        }
        item.reveal_child = false;
        return i;
      }, 0);
    },
    launchFirst() {
      launchApp(first);
    },
  });
}