~unity-team/unity-lens-music/6.0

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
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * Copyright (C) 2011 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authored by Alex Launi <alex.launi@canonical.com>
 *
 */

using GLib;

namespace Unity.MusicLens
{
  public abstract class SimpleScope : Object
  {
    public Unity.Scope scope { get; protected set; }

    protected abstract int num_results_without_search { get; }
    protected abstract int num_results_global_search { get; }
    protected abstract int num_results_lens_search { get; }

    protected abstract async void perform_search (LensSearch search,
                                                  SearchType search_type,
                                                  owned List<FilterParser> filters,
                                                  int max_results = -1,
                                                  Cancellable? cancellable = null);

    public SimpleScope ()
    {
    }

    protected void initialize ()
    {
      /* Listen for filter changes */
      scope.filters_changed.connect (() => {
        scope.queue_search_changed (SearchType.DEFAULT);
      });

      scope.active_sources_changed.connect (() => {
        scope.queue_search_changed (SearchType.DEFAULT);
      });

      /* No need to search if only the whitespace changes */
      scope.generate_search_key.connect ((lens_search) => {
        return lens_search.search_string.strip ();
      });

      /* Listen for changes to the lens search entry */
      scope.search_changed.connect ((search, search_type, cancellable) => {
        update_search_async.begin (search, search_type, cancellable);
      });
    }
    
    private async void update_search_async (LensSearch search,
                                            SearchType search_type,
                                            Cancellable cancellable)
    {
      int max_results;
      /*
       * results for a global search from just hitting Super.
       * Here we want to return a smaller number of results with 0 filters.
       */
      if (search_type == SearchType.GLOBAL)
        max_results = num_results_global_search;
      else if (is_search_empty (search))
        max_results = num_results_without_search;
      else
        max_results = num_results_lens_search;

      yield prepare_search (search, search_type, max_results, cancellable);
    }

    private async void prepare_search (LensSearch search,
                                       SearchType search_type,
                                       int max_results,
                                       Cancellable cancellable)
    {
      var results_model = search.results_model;

      List<FilterParser> filters = new List<FilterParser> ();
      // don't apply filters to global searches
      if (search_type != SearchType.GLOBAL)
      {
        Filter filter = scope.get_filter ("genre");
        if (filter.filtering)
          filters.append (new GenreFilterParser (filter as CheckOptionFilterCompact));

        filter = scope.get_filter ("decade");
        if (filter.filtering)
          filters.append (new DecadeFilterParser (filter as MultiRangeFilter));
      }

      results_model.clear ();

      // don't perform search is all sources are inactive
      if (scope.sources.options.length () > 0 && scope.sources.filtering)
      {
        bool any_active = false;
        foreach (var source in scope.sources.options)
        {
          if (source.active) any_active = true;
        }
        if (!any_active)
        {
          search.finished ();
          return;
        }
      }

      yield perform_search (search, search_type, (owned) filters, max_results, cancellable);

      if (results_model.get_n_rows () == 0)
      {
        search.set_reply_hint ("no-results-hint",
          _("Sorry, there is no music that matches your search."));
      }

      search.finished ();
    }

    protected bool is_search_empty (LensSearch search)
      requires (search.search_string != null)
    {
      return search.search_string.strip () == "";
    }
  }
}