summaryrefslogtreecommitdiff
path: root/lib/apps/apps.vala
diff options
context:
space:
mode:
Diffstat (limited to 'lib/apps/apps.vala')
-rw-r--r--lib/apps/apps.vala172
1 files changed, 172 insertions, 0 deletions
diff --git a/lib/apps/apps.vala b/lib/apps/apps.vala
new file mode 100644
index 0000000..2a0d507
--- /dev/null
+++ b/lib/apps/apps.vala
@@ -0,0 +1,172 @@
+namespace AstalApps {
+public class Apps : Object {
+ private string cache_directory;
+ private string cache_file;
+ private List<Application> _list;
+ private HashTable<string, int> frequents { get; private set; }
+
+ public bool show_hidden { get; set; }
+ public List<weak Application> list { owned get { return _list.copy(); } }
+
+ public double min_score { get; set; default = 0.5; }
+
+ public double name_multiplier { get; set; default = 2; }
+ public double entry_multiplier { get; set; default = 1; }
+ public double executable_multiplier { get; set; default = 1; }
+ public double description_multiplier { get; set; default = 0.5; }
+
+ public bool include_name { get; set; default = true; }
+ public bool include_entry { get; set; default = false; }
+ public bool include_executable { get; set; default = false; }
+ public bool include_description { get; set; default = false; }
+
+ construct {
+ cache_directory = Environment.get_user_cache_dir() + "/astal";
+ cache_file = cache_directory + "/apps-frequents.json";
+ frequents = new HashTable<string, int>(str_hash, str_equal);
+
+ AppInfoMonitor.get().changed.connect(() => {
+ reload();
+ });
+
+ if (FileUtils.test(cache_file, FileTest.EXISTS)) {
+ try {
+ uint8[] content;
+ File.new_for_path(cache_file).load_contents(null, out content, null);
+
+ var parser = new Json.Parser();
+ parser.load_from_data((string)content);
+ var obj = parser.get_root().get_object();
+ foreach (var member in obj.get_members()) {
+ var v = obj.get_member(member).get_value().get_int64();
+ frequents.set(member, (int)v);
+ }
+ } catch (Error err) {
+ critical("cannot read cache: %s\n", err.message);
+ }
+ }
+
+ reload();
+ }
+
+ private double score (string search, Application a, bool exact) {
+ var am = exact ? a.exact_match(search) : a.fuzzy_match(search);
+ double r = 0;
+
+ if (include_name)
+ r += am.name * name_multiplier;
+ if (include_entry)
+ r += am.entry * entry_multiplier;
+ if (include_executable)
+ r += am.executable * executable_multiplier;
+ if (include_description)
+ r += am.description * description_multiplier;
+
+ return r;
+ }
+
+ public List<weak Application> query(string? search = "", bool exact = false) {
+ if (search == null)
+ search = "";
+
+ var arr = list.copy();
+
+ // empty search, sort by frequency
+ if (search == "") {
+ arr.sort_with_data((a, b) => {
+ return (int)b.frequency - (int)a.frequency;
+ });
+
+ return arr;
+ }
+
+ // single character, sort by frequency and exact match
+ if (search.length == 1) {
+ foreach (var app in list) {
+ if (score(search, app, true) == 0)
+ arr.remove(app);
+ }
+
+ arr.sort_with_data((a, b) => {
+ return (int)b.frequency - (int)a.frequency;
+ });
+
+ return arr;
+ }
+
+ // filter
+ foreach (var app in list) {
+ if (score(search, app, exact) < min_score)
+ arr.remove(app);
+ }
+
+ // sort by score, frequency
+ arr.sort_with_data((a, b) => {
+ var s1 = score(search, a, exact);
+ var s2 = score(search, b, exact);
+
+ if (s1 == s2)
+ return (int)b.frequency - (int)a.frequency;
+
+ return s1 < s2 ? 1 : -1;
+ });
+
+ return arr;
+ }
+
+ public List<weak Application> fuzzy_query(string? search = "") {
+ return query(search, false);
+ }
+
+ public List<weak Application> exact_query(string? search = "") {
+ return query(search, true);
+ }
+
+ public void reload() {
+ var arr = AppInfo.get_all();
+
+ _list = new List<Application>();
+ foreach (var app in arr) {
+ if (!show_hidden && !app.should_show())
+ continue;
+
+ var a = new Application(
+ app.get_id(),
+ frequents.get(app.get_id())
+ );
+ a.notify.connect((pspec) => {
+ if (pspec.name != "frequency")
+ return;
+
+ var f = frequents.get(app.get_id());
+ frequents.set(app.get_id(), ++f);
+
+ _list.sort((a, b) => {
+ return (int)a.frequency - (int)b.frequency;
+ });
+ cache();
+ });
+ _list.append(a);
+ }
+
+ cache();
+ }
+
+ private void cache() {
+ var json = new Json.Builder().begin_object();
+ foreach (string key in frequents.get_keys())
+ json.set_member_name(key).add_int_value(frequents.get(key));
+
+ try {
+ if (!FileUtils.test(cache_directory, FileTest.EXISTS))
+ File.new_for_path(cache_directory).make_directory_with_parents(null);
+
+ var generator = new Json.Generator();
+ generator.set_root(json.end_object().get_root());
+ FileUtils.set_contents_full(cache_file, generator.to_data(null));
+ } catch (Error err) {
+ critical("cannot cache frequents: %s", err.message);
+ }
+ }
+}
+}