1// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- 2/*- 3 * Copyright (c) 2016-2016 elementary LLC. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 * Authored by: Artem Anufrij <artem.anufrij@live.de> 19 * 20 */ 21 22namespace Audience { 23 public class LibraryPage : Gtk.Grid { 24 25 public signal void filter_result_changed (bool has_results); 26 public signal void show_episodes (Audience.LibraryItem item, bool setup_only = false); 27 28 public Gtk.FlowBox view_movies; 29 public Audience.Services.LibraryManager manager; 30 public Gtk.ScrolledWindow scrolled_window; 31 bool posters_initialized = false; 32 string query; 33 34 public string last_filter { get; set; default = ""; } 35 36 public bool has_items { get { return view_movies.get_children ().length () > 0; } } 37 38 public static LibraryPage instance = null; 39 public static LibraryPage get_instance () { 40 if (instance == null) { 41 instance = new LibraryPage (); 42 } 43 return instance; 44 } 45 46 construct { 47 manager = Audience.Services.LibraryManager.get_instance (); 48 49 query = ""; 50 51 scrolled_window = new Gtk.ScrolledWindow (null, null); 52 scrolled_window.expand = true; 53 54 view_movies = new Gtk.FlowBox (); 55 view_movies.margin = 24; 56 view_movies.homogeneous = true; 57 view_movies.row_spacing = 12; 58 view_movies.column_spacing = 12; 59 view_movies.valign = Gtk.Align.START; 60 view_movies.selection_mode = Gtk.SelectionMode.NONE; 61 view_movies.child_activated.connect (play_video); 62 63 scrolled_window.add (view_movies); 64 65 manager = Audience.Services.LibraryManager.get_instance (); 66 manager.video_file_detected.connect (add_item); 67 manager.video_file_deleted.connect (remove_item_from_path); 68 manager.video_moved_to_trash.connect ((video) => { 69 Audience.App.get_instance ().mainwindow.set_app_notification (_("Video '%s' Removed.").printf (Path.get_basename (video))); 70 }); 71 72 manager.begin_scan (); 73 74 map.connect (() => { 75 if (!posters_initialized) { 76 posters_initialized = true; 77 poster_initialisation.begin (); 78 } 79 }); 80 81 view_movies.set_sort_func (video_sort_func); 82 view_movies.set_filter_func (video_filter_func); 83 84 add (scrolled_window); 85 } 86 87 private void play_video (Gtk.FlowBoxChild item) { 88 var selected = (item as Audience.LibraryItem); 89 90 if (selected.episodes.size == 1) { 91 string uri = selected.episodes.first ().video_file.get_uri (); 92 bool same_video = uri == settings.get_string ("current-video"); 93 bool playback_complete = settings.get_double ("last-stopped") == 0.0; 94 bool from_beginning = !same_video || playback_complete; 95 var window = App.get_instance ().mainwindow; 96 window.add_to_playlist (uri, !from_beginning); 97 window.play_file (uri, Window.NavigationPage.LIBRARY, from_beginning); 98 } else { 99 last_filter = query; 100 show_episodes (selected); 101 } 102 } 103 104 public void add_item (Audience.Objects.Video video) { 105 foreach (var child in view_movies.get_children ()) { 106 if (video.container != null && ((LibraryItem)(child)).episodes.first ().container == video.container) { 107 ((LibraryItem)(child)).add_episode (video); 108 return; 109 } 110 } 111 Audience.LibraryItem new_container = new Audience.LibraryItem (video, LibraryItemStyle.THUMBNAIL); 112 view_movies.add (new_container); 113 if (posters_initialized) { 114 video.initialize_poster.begin (); 115 new_container.show_all (); 116 } 117 } 118 119 private async void remove_item (LibraryItem item) { 120 foreach (var video in item.episodes) { 121 manager.clear_cache.begin (video.poster_cache_file); 122 } 123 item.dispose (); 124 } 125 126 private async void remove_item_from_path (string path ) { 127 foreach (var child in view_movies.get_children ()) { 128 if (((LibraryItem)(child)).episodes.size == 0 || 129 ((LibraryItem)(child)).episodes.first ().video_file.get_path ().has_prefix (path)) { 130 131 remove_item.begin (child as LibraryItem); 132 } 133 } 134 135 if (view_movies.get_children ().length () == 0) { 136 Audience.App.get_instance ().mainwindow.navigate_back (); 137 } 138 } 139 140 private async void poster_initialisation () { 141 foreach (var child in view_movies.get_children ()) { 142 var first_episode = ((LibraryItem)(child)).episodes.first (); 143 if (!first_episode.poster_initialized) { 144 first_episode.initialize_poster.begin (); 145 } 146 } 147 } 148 149 private bool video_filter_func (Gtk.FlowBoxChild child) { 150 if (query.length == 0) { 151 return true; 152 } 153 154 string[] filter_elements = query.split (" "); 155 var video_title = ((LibraryItem)(child)).get_title (); 156 157 foreach (string filter_element in filter_elements) { 158 if (!video_title.down ().contains (filter_element.down ())) { 159 return false; 160 } 161 } 162 return true; 163 } 164 165 private int video_sort_func (Gtk.FlowBoxChild child1, Gtk.FlowBoxChild child2) { 166 var item1 = (LibraryItem)child1; 167 var item2 = (LibraryItem)child2; 168 if (item1 != null && item2 != null) { 169 return item1.get_title ().collate (item2.get_title ()); 170 } 171 return 0; 172 } 173 174 public void filter (string text) { 175 query = text.strip (); 176 view_movies.invalidate_filter (); 177 filter_result_changed (has_child ()); 178 } 179 180 public bool has_child () { 181 if (view_movies.get_children ().length () > 0) { 182 foreach (unowned Gtk.Widget child in view_movies.get_children ()) { 183 if (child.get_child_visible ()) { 184 return true; 185 } 186 } 187 } 188 return false; 189 } 190 191 public Audience.Window.NavigationPage prepare_to_play (string file) { 192 if (!File.new_for_uri (file).has_prefix (File.new_for_path (settings.get_string ("library-folder")))) { 193 return Window.NavigationPage.WELCOME; 194 } 195 196 foreach (var child in view_movies.get_children ()) { 197 var item = child as LibraryItem; 198 var episodes = item.episodes; 199 foreach (var episode in episodes) { 200 string ep_file = episode.video_file.get_uri (); 201 if (ep_file == file) { 202 if (episodes.size > 1) { 203 var first_episode = episodes.first (); 204 if (!first_episode.poster_initialized) { 205 first_episode.initialize_poster.begin (); 206 } 207 show_episodes (item, true); 208 return Window.NavigationPage.EPISODES; 209 } else { 210 return Window.NavigationPage.LIBRARY; 211 } 212 } 213 } 214 } 215 return Window.NavigationPage.WELCOME; 216 } 217 } 218} 219