Merge lp:~alcinnz/audience/audience into lp:~audience-members/audience/trunk

Proposed by Adrian Cochrane
Status: Needs review
Proposed branch: lp:~alcinnz/audience/audience
Merge into: lp:~audience-members/audience/trunk
Diff against target: 1340 lines (+595/-331)
10 files modified
src/CMakeLists.txt (+1/-0)
src/Consts.vala (+1/-1)
src/Utils.vala (+15/-0)
src/Widgets/Library/EpisodesPage.vala (+14/-5)
src/Widgets/Library/LibraryPage.vala (+46/-4)
src/Widgets/Player/BottomBar.vala (+13/-27)
src/Widgets/Player/PlayerPage.vala (+106/-26)
src/Widgets/TitleBar.vala (+309/-0)
src/Widgets/WelcomePage.vala (+53/-23)
src/Window.vala (+37/-245)
To merge this branch: bzr merge lp:~alcinnz/audience/audience
Reviewer Review Type Date Requested Status
Felipe Escoto (community) Needs Fixing
Adam Bieńkowski (community) code Needs Fixing
Danielle Foré Needs Fixing
Review via email: mp+314892@code.launchpad.net

Description of the change

This code makes the titlebar disappear while a movie is playing.

Involves significant refactoring which moves the headerbar(s) into the widget hierarchy and moves code out of the containing window and into the "pages".

I realized late that there was already a proposal from Lains for fixing this, but I believe I've addressed all your concerns on that proposal.

To post a comment you must log in.
Revision history for this message
Adam Bieńkowski (donadigo) wrote :

Please, resolve merge conflicts.

review: Needs Fixing (code)
lp:~alcinnz/audience/audience updated
713. By Adrian Cochrane

Merge changes.

Apologies for undoing some translation refactoring, it didn't fit with my refactoring. Will try to bring it back in.

714. By Adrian Cochrane

Restore navigation animations to communicate forward & backward navigation

715. By Adrian Cochrane

Fixed translations on the back button.

(Again after a previous fix by Leonardo Lemos made his fix prior to my refactoring)

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

> Please, resolve merge conflicts.

They have been resolved, and I verified the translation fix still works.

Revision history for this message
Danielle Foré (danrabbit) wrote :

Please make sure to use Gtk.Grid and not Gtk.VBox. Gtk.VBox has been deprecated and as we understand it, Gtk.Box is scheduled to be deprecated in the future.

review: Needs Fixing
Revision history for this message
Danielle Foré (danrabbit) wrote :

It seems like this branch completely removes fullscreen

Revision history for this message
Cody Garver (codygarver) wrote :

Double click to fullscreen is broken, f key still works.

lp:~alcinnz/audience/audience updated
716. By Adrian Cochrane

Switch from deprecated Gtk.VBox to Gtk.Grid.

717. By Adrian Cochrane

Remove misleading comments I put in.

718. By Adrian Cochrane

Standardize the means of accessing the application window.

I'm sorry to say much of the inconsistancy came from me.

Also I added a bit of dead code that's now been removed.

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

> It seems like this branch completely removes fullscreen

I did have trouble preserving "double click to make fullscreen" functionality while retaining standard window controls.

Easiest fix would be restore "maximize to make fullscreen", but there was already a note in the code as to why that's not being done.

On the bright side not going fullscreen is less of a nuisance as now there's a single bar at the top of the screen instead of two, and as noted pressing "f" still works.

lp:~alcinnz/audience/audience updated
719. By Adrian Cochrane

Restore double click to make fullscreen

Made a cleaner fix to the new unfullscreen button grabbing focus.

720. By Adrian Cochrane

Merging from upstream

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

> > It seems like this branch completely removes fullscreen
>
> I did have trouble preserving "double click to make fullscreen" functionality
> while retaining standard window controls.
>
> Easiest fix would be restore "maximize to make fullscreen", but there was
> already a note in the code as to why that's not being done.
>
> On the bright side not going fullscreen is less of a nuisance as now there's a
> single bar at the top of the screen instead of two, and as noted pressing "f"
> still works.

Got it back to the original behaviour of double-clicking titlebar minimizes/maximizes and content fullscreens/unfullscreens.

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

> Please make sure to use Gtk.Grid and not Gtk.VBox. Gtk.VBox has been
> deprecated and as we understand it, Gtk.Box is scheduled to be deprecated in
> the future.

This fix has been made a while back, along with a fix to the double click behaviour to make fullscreen behaviour. Haven't heard anything for a while.

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

> Please make sure to use Gtk.Grid and not Gtk.VBox. Gtk.VBox has been
> deprecated and as we understand it, Gtk.Box is scheduled to be deprecated in
> the future.

This fix has been made a while back, along with a fix to the double click behaviour to make fullscreen behaviour. Haven't heard anything for a while.

lp:~alcinnz/audience/audience updated
721. By Adrian Cochrane

Merging translation fix for "search not found" screen.

Revision history for this message
Adam Bieńkowski (donadigo) wrote :

Just my two cents: match_keycode has mutliple definitions in the app while there should be only one declared statically. Also, you seem to be overusing it in methods like key_press_event. You repeadetely call match_keycode which is not very good for overall performance. I strongly recommend to copy the code from match_keycode to those methods and check for each key in one go e.g:

Gdk.Keymap keymap = Gdk.Keymap.get_default ();
if (keymap.get_entries_for_keyval (keyval, out keys)) {
    foreach (var key in keys) {
        case Gdk.Key.p:
            // do something here
            break;
    }
}

Another thing is, in the key_press_event method, you return true in every if statement you have. This is not needed since you did it at the very end of the method, so there is no need for these "return true" lines. I also recommend you to look at the documentation of this method to make sure that returning true always is the right thing to do in this case.

In the multipress_gesture_pressed_cb method I would like to see a switch () statement being used for better code redability rather than using a couple of if's and elseif's.

review: Needs Fixing (code)
lp:~alcinnz/audience/audience updated
722. By Adrian Cochrane

Reunifying match_keycode method, minor tidyups from copy-paste.

723. By Adrian Cochrane

Use switch statements instead if/else-if in titlebar event handling.

For code readability.

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

> Just my two cents: match_keycode has mutliple definitions in the app while
> there should be only one declared statically. Also, you seem to be overusing
> it in methods like key_press_event. You repeadetely call match_keycode which
> is not very good for overall performance. I strongly recommend to copy the
> code from match_keycode to those methods and check for each key in one go e.g:
>
> Gdk.Keymap keymap = Gdk.Keymap.get_default ();
> if (keymap.get_entries_for_keyval (keyval, out keys)) {
> foreach (var key in keys) {
> case Gdk.Key.p:
> // do something here
> break;
> }
> }
>
> Another thing is, in the key_press_event method, you return true in every if
> statement you have. This is not needed since you did it at the very end of the
> method, so there is no need for these "return true" lines. I also recommend
> you to look at the documentation of this method to make sure that returning
> true always is the right thing to do in this case.
>
> In the multipress_gesture_pressed_cb method I would like to see a switch ()
> statement being used for better code redability rather than using a couple of
> if's and elseif's.

I made these fixes you suggested for code cleanliness.

The only exception is that I didn't inline match_keycode into the key_pressed event handlers because that simply doesn't work. The probably with your recommendation there is that the method uses the Keymap to check what hardware keycodes the Gdk.Key constants refer to, and not what constants the event keycode refer to.

Thanks for your feedback.

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

> > Just my two cents: match_keycode has mutliple definitions in the app while
> > there should be only one declared statically. Also, you seem to be overusing
> > it in methods like key_press_event. You repeadetely call match_keycode which
> > is not very good for overall performance. I strongly recommend to copy the
> > code from match_keycode to those methods and check for each key in one go
> e.g:
> >
> > Gdk.Keymap keymap = Gdk.Keymap.get_default ();
> > if (keymap.get_entries_for_keyval (keyval, out keys)) {
> > foreach (var key in keys) {
> > case Gdk.Key.p:
> > // do something here
> > break;
> > }
> > }
> >
> > Another thing is, in the key_press_event method, you return true in every if
> > statement you have. This is not needed since you did it at the very end of
> the
> > method, so there is no need for these "return true" lines. I also recommend
> > you to look at the documentation of this method to make sure that returning
> > true always is the right thing to do in this case.
> >
> > In the multipress_gesture_pressed_cb method I would like to see a switch ()
> > statement being used for better code redability rather than using a couple
> of
> > if's and elseif's.
>
> I made these fixes you suggested for code cleanliness.
>
> The only exception is that I didn't inline match_keycode into the key_pressed
> event handlers because that simply doesn't work. The probably with your
> recommendation there is that the method uses the Keymap to check what hardware
> keycodes the Gdk.Key constants refer to, and not what constants the event
> keycode refer to.
>
> Thanks for your feedback.

Typo. "The problem", not "The probably".

Revision history for this message
Adrian Cochrane (alcinnz) wrote :

Any more feedback?

Revision history for this message
Felipe Escoto (philip.scott) wrote :

I've been testing and there seems to be problems where it sometimes does not detect the keypresses such as space. (Why are you touching that code anyways to add the hiding headerbar? (Small diff is best diff))

Anyways.... We will be moving Audience to GitHub soon if the other branches land before you can fix it :)

review: Needs Fixing
Revision history for this message
Danielle Foré (danrabbit) wrote :

Audience has migrated to GitHub. Please resubmit as a PR here: https://github.com/elementary/videos

Unmerged revisions

723. By Adrian Cochrane

Use switch statements instead if/else-if in titlebar event handling.

For code readability.

722. By Adrian Cochrane

Reunifying match_keycode method, minor tidyups from copy-paste.

721. By Adrian Cochrane

Merging translation fix for "search not found" screen.

720. By Adrian Cochrane

Merging from upstream

719. By Adrian Cochrane

Restore double click to make fullscreen

Made a cleaner fix to the new unfullscreen button grabbing focus.

718. By Adrian Cochrane

Standardize the means of accessing the application window.

I'm sorry to say much of the inconsistancy came from me.

Also I added a bit of dead code that's now been removed.

717. By Adrian Cochrane

Remove misleading comments I put in.

716. By Adrian Cochrane

Switch from deprecated Gtk.VBox to Gtk.Grid.

715. By Adrian Cochrane

Fixed translations on the back button.

(Again after a previous fix by Leonardo Lemos made his fix prior to my refactoring)

714. By Adrian Cochrane

Restore navigation animations to communicate forward & backward navigation

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/CMakeLists.txt'
2--- src/CMakeLists.txt 2016-11-02 23:59:41 +0000
3+++ src/CMakeLists.txt 2017-01-28 06:32:01 +0000
4@@ -53,6 +53,7 @@
5 Widgets/WelcomePage.vala
6 Widgets/NavigationButton.vala
7 Widgets/Toast.vala
8+ Widgets/TitleBar.vala
9
10 Widgets/Player/BottomBar.vala
11 Widgets/Player/SettingsPopover.vala
12
13=== modified file 'src/Consts.vala'
14--- src/Consts.vala 2014-06-30 14:54:30 +0000
15+++ src/Consts.vala 2017-01-28 06:32:01 +0000
16@@ -4,4 +4,4 @@
17 // 204/255 = 80% opacity
18 public const uint GLOBAL_OPACITY = 204;
19
20-}
21\ No newline at end of file
22+}
23
24=== modified file 'src/Utils.vala'
25--- src/Utils.vala 2016-08-01 18:46:23 +0000
26+++ src/Utils.vala 2017-01-28 06:32:01 +0000
27@@ -104,4 +104,19 @@
28 var file = File.new_for_uri (uri);
29 return file.query_exists ();
30 }
31+
32+ /** Returns true if the code parameter matches the keycode of the keyval parameter for
33+ * any keyboard group or level (in order to allow for non-QWERTY keyboards) **/
34+ public bool match_keycode (int keyval, uint code) {
35+ Gdk.KeymapKey [] keys;
36+ Gdk.Keymap keymap = Gdk.Keymap.get_default ();
37+ if (keymap.get_entries_for_keyval (keyval, out keys)) {
38+ foreach (var key in keys) {
39+ if (code == key.keycode)
40+ return true;
41+ }
42+ }
43+
44+ return false;
45+ }
46 }
47
48=== modified file 'src/Widgets/Library/EpisodesPage.vala'
49--- src/Widgets/Library/EpisodesPage.vala 2017-01-25 22:40:27 +0000
50+++ src/Widgets/Library/EpisodesPage.vala 2017-01-28 06:32:01 +0000
51@@ -31,8 +31,17 @@
52 string query;
53
54 construct {
55+ orientation = Gtk.Orientation.VERTICAL;
56 query = "";
57
58+ var titlebar = new TitleBar ();
59+ titlebar.show_back (Audience.Window.page_label_library);
60+ titlebar.add_searchbox (filter);
61+ add (titlebar);
62+
63+ var grid = new Gtk.Grid ();
64+ add (grid);
65+
66 poster = new Gtk.Image ();
67 poster.margin = 24;
68 poster.margin_right = 0;
69@@ -57,10 +66,10 @@
70 alert_view.get_style_context ().remove_class (Gtk.STYLE_CLASS_VIEW);
71 alert_view.hide ();
72
73- expand = true;
74- attach (poster, 0, 1, 1, 1);
75- attach (scrolled_window, 1, 1, 1, 1);
76- attach (alert_view, 1, 1, 1, 1);
77+ grid.expand = true;
78+ grid.attach (poster, 0, 1, 1, 1);
79+ grid.attach (scrolled_window, 1, 1, 1, 1);
80+ grid.attach (alert_view, 1, 1, 1, 1);
81
82 manager = Audience.Services.LibraryManager.get_instance ();
83 manager.video_file_deleted.connect (remove_item_from_path);
84@@ -138,7 +147,7 @@
85 }
86
87 if (Audience.App.get_instance ().mainwindow.get_visible_child () == this && view_episodes.get_children ().length () == 0) {
88- Audience.App.get_instance ().mainwindow.navigate_back ();
89+ Audience.App.get_instance ().mainwindow.show_page ("library");
90 }
91 }
92
93
94=== modified file 'src/Widgets/Library/LibraryPage.vala'
95--- src/Widgets/Library/LibraryPage.vala 2016-11-02 23:59:41 +0000
96+++ src/Widgets/Library/LibraryPage.vala 2017-01-28 06:32:01 +0000
97@@ -22,12 +22,13 @@
98 namespace Audience {
99 public class LibraryPage : Gtk.Grid {
100
101- public signal void filter_result_changed (bool has_results);
102 public signal void show_episodes (Audience.LibraryItem item);
103
104 public Gtk.FlowBox view_movies;
105 public Audience.Services.LibraryManager manager;
106 public Gtk.ScrolledWindow scrolled_window;
107+ private Granite.Widgets.AlertView alert_view;
108+ private Gtk.Stack main_stack;
109 bool poster_initialized = false;
110 string query;
111
112@@ -44,10 +45,17 @@
113 }
114
115 construct {
116+ orientation = Gtk.Orientation.VERTICAL;
117+
118 manager = Audience.Services.LibraryManager.get_instance ();
119
120 query = "";
121
122+ var title_bar = new TitleBar ();
123+ title_bar.add_searchbox (filter);
124+ title_bar.show_back (Audience.Window.page_label_welcomescreen);
125+ add (title_bar);
126+
127 scrolled_window = new Gtk.ScrolledWindow (null, null);
128 scrolled_window.expand = true;
129
130@@ -61,6 +69,11 @@
131 view_movies.child_activated.connect (play_video);
132
133 scrolled_window.add (view_movies);
134+
135+ alert_view = new Granite.Widgets.AlertView ("", "", "");
136+ alert_view.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL);
137+ alert_view.set_vexpand (true);
138+ alert_view.no_show_all = true;
139
140 manager = Audience.Services.LibraryManager.get_instance ();
141 manager.video_file_detected.connect (add_item);
142@@ -76,12 +89,18 @@
143 poster_initialized = true;
144 poster_initialisation.begin ();
145 }
146+
147+ App.get_instance ().mainwindow.title = _("Videos");
148 });
149
150 view_movies.set_sort_func (video_sort_func);
151 view_movies.set_filter_func (video_filter_func);
152
153- add (scrolled_window);
154+ main_stack = new Gtk.Stack ();
155+ main_stack.add_named (alert_view, "alert");
156+ main_stack.add_named (scrolled_window, "library");
157+
158+ add (main_stack);
159 }
160
161 private void play_video (Gtk.FlowBoxChild item) {
162@@ -126,7 +145,7 @@
163 }
164
165 if (view_movies.get_children ().length () == 0) {
166- Audience.App.get_instance ().mainwindow.navigate_back ();
167+ Audience.App.get_instance ().mainwindow.show_page (Audience.Window.page_label_welcomescreen);
168 }
169 }
170
171@@ -164,7 +183,30 @@
172 public void filter (string text) {
173 query = text.strip ();
174 view_movies.invalidate_filter ();
175- filter_result_changed (has_child ());
176+ filter_result_changed (has_child (), text);
177+ }
178+
179+ private void filter_result_changed (bool has_results, string search) {
180+ if (!has_results) {
181+ show_alert (_("No Results for “%s”").printf (search), _("Try changing search terms."), "edit-find-symbolic");
182+ } else {
183+ hide_alert ();
184+ }
185+ }
186+
187+ public void show_alert (string primary_text, string secondary_text, string icon_name) {
188+ alert_view.no_show_all = false;
189+ alert_view.show_all ();
190+ alert_view.title = primary_text;
191+ alert_view.description = secondary_text;
192+ alert_view.icon_name = icon_name;
193+ main_stack.visible_child = alert_view;
194+ }
195+
196+ public void hide_alert () {
197+ alert_view.no_show_all = true;
198+ main_stack.visible_child_name = "library";
199+ alert_view.hide ();
200 }
201
202 public bool has_child () {
203
204=== modified file 'src/Widgets/Player/BottomBar.vala'
205--- src/Widgets/Player/BottomBar.vala 2016-11-02 23:59:41 +0000
206+++ src/Widgets/Player/BottomBar.vala 2017-01-28 06:32:01 +0000
207@@ -24,12 +24,10 @@
208 private const string PULSE_TYPE = "attention";
209
210 public signal void play_toggled ();
211- public signal void unfullscreen ();
212 public signal void seeked (double val);
213
214 public bool playing { get; set; default=false; }
215 public bool hovered { get; set; default=false; }
216- public bool fullscreen { get; set; default=false; }
217 public SettingsPopover preferences_popover;
218 public PlaylistPopover playlist_popover;
219 public TimeWidget time_widget;
220@@ -37,7 +35,7 @@
221 private Gtk.Button play_button;
222 private Gtk.Button preferences_button;
223 private Gtk.Button playlist_button;
224- private Gtk.Revealer unfullscreen_revealer;
225+ private Gtk.Revealer titlebar_revealer;
226 private uint hiding_timer = 0;
227 private bool playlist_glowing = false;
228
229@@ -106,14 +104,6 @@
230 }
231 });
232
233- notify["fullscreen"].connect (() => {
234- if (fullscreen == true && child_revealed == true) {
235- unfullscreen_revealer.set_reveal_child (true);
236- } else if (fullscreen == false && child_revealed == true) {
237- unfullscreen_revealer.set_reveal_child (false);
238- }
239- });
240-
241 play_button.clicked.connect (() => {
242 playing = !playing;
243 });
244@@ -148,25 +138,21 @@
245 }
246 }
247
248- public Gtk.Revealer get_unfullscreen_button () {
249- unfullscreen_revealer = new Gtk.Revealer ();
250- unfullscreen_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN;
251-
252- var unfullscreen_button = new Gtk.Button.from_icon_name ("view-restore-symbolic", Gtk.IconSize.BUTTON);
253- unfullscreen_button.tooltip_text = _("Unfullscreen");
254- unfullscreen_button.clicked.connect (() => {unfullscreen ();});
255- unfullscreen_revealer.add (unfullscreen_button);
256- unfullscreen_revealer.show_all ();
257- return unfullscreen_revealer;
258+ public TitleBar titlebar;
259+
260+ public Gtk.Revealer get_titlebar () {
261+ titlebar_revealer = new Gtk.Revealer ();
262+ titlebar_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN;
263+
264+ titlebar = new TitleBar ();
265+ titlebar_revealer.add (titlebar);
266+ titlebar_revealer.show_all ();
267+ return titlebar_revealer;
268 }
269
270 private new void set_reveal_child (bool reveal) {
271 base.set_reveal_child (reveal);
272- if (reveal == true && fullscreen == true) {
273- unfullscreen_revealer.set_reveal_child (reveal);
274- } else if (reveal == false) {
275- unfullscreen_revealer.set_reveal_child (reveal);
276- }
277+ titlebar_revealer.set_reveal_child (reveal);
278 }
279
280 public override void get_preferred_width (out int minimum_width, out int natural_width) {
281@@ -193,7 +179,7 @@
282 return false;
283 }
284 set_reveal_child (false);
285- unfullscreen_revealer.set_reveal_child (false);
286+ titlebar_revealer.set_reveal_child (false);
287 hiding_timer = 0;
288 return false;
289 });
290
291=== modified file 'src/Widgets/Player/PlayerPage.vala'
292--- src/Widgets/Player/PlayerPage.vala 2016-11-02 23:59:41 +0000
293+++ src/Widgets/Player/PlayerPage.vala 2017-01-28 06:32:01 +0000
294@@ -9,15 +9,17 @@
295 };
296
297 public class PlayerPage : Gtk.EventBox {
298- public signal void unfullscreen_clicked ();
299- public signal void ended ();
300+ private string _back_target;
301+ public virtual signal void ended () {
302+ App.get_instance ().mainwindow.show_page (_back_target);
303+ }
304
305 public GtkClutter.Embed clutter;
306 private Clutter.Actor video_actor;
307 private Audience.Widgets.BottomBar bottom_bar;
308 private Clutter.Stage stage;
309- private Gtk.Revealer unfullscreen_bar;
310- private GtkClutter.Actor unfullscreen_actor;
311+ private Gtk.Revealer titlebar;
312+ private GtkClutter.Actor titlebar_actor;
313 private GtkClutter.Actor bottom_actor;
314 private GnomeMediaKeys mediakeys;
315 private ClutterGst.Playback playback;
316@@ -46,16 +48,7 @@
317 }
318 }
319
320- private bool _fullscreened = false;
321- public bool fullscreened {
322- get {
323- return _fullscreened;
324- }
325- set {
326- _fullscreened = value;
327- bottom_bar.fullscreen = value;
328- }
329- }
330+ public bool fullscreened = false;
331
332 public PlayerPage () {
333 }
334@@ -85,7 +78,7 @@
335 var geometry = Gdk.Geometry ();
336 geometry.min_aspect = aspect;
337 geometry.max_aspect = aspect;
338- ((Gtk.Window) get_toplevel ()).set_geometry_hints (get_toplevel (), geometry, Gdk.WindowHints.ASPECT);
339+ App.get_instance ().mainwindow.set_geometry_hints (get_toplevel (), geometry, Gdk.WindowHints.ASPECT);
340 });
341 */
342 video_actor.content = aspect_ratio;
343@@ -103,9 +96,8 @@
344
345 bottom_bar = new Widgets.BottomBar (playback);
346 bottom_bar.bind_property ("playing", playback, "playing", BindingFlags.BIDIRECTIONAL);
347- bottom_bar.unfullscreen.connect (() => unfullscreen_clicked ());
348
349- unfullscreen_bar = bottom_bar.get_unfullscreen_button ();
350+ titlebar = bottom_bar.get_titlebar ();
351
352 bottom_actor = new GtkClutter.Actor.with_contents (bottom_bar);
353 bottom_actor.opacity = GLOBAL_OPACITY;
354@@ -113,11 +105,11 @@
355 bottom_actor.add_constraint (new Clutter.AlignConstraint (stage, Clutter.AlignAxis.Y_AXIS, 1));
356 stage.add_child (bottom_actor);
357
358- unfullscreen_actor = new GtkClutter.Actor.with_contents (unfullscreen_bar);
359- unfullscreen_actor.opacity = GLOBAL_OPACITY;
360- unfullscreen_actor.add_constraint (new Clutter.AlignConstraint (stage, Clutter.AlignAxis.X_AXIS, 1));
361- unfullscreen_actor.add_constraint (new Clutter.AlignConstraint (stage, Clutter.AlignAxis.Y_AXIS, 0));
362- stage.add_child (unfullscreen_actor);
363+ titlebar_actor = new GtkClutter.Actor.with_contents (titlebar);
364+ titlebar_actor.opacity = GLOBAL_OPACITY;
365+ titlebar_actor.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));
366+ titlebar_actor.add_constraint (new Clutter.AlignConstraint (stage, Clutter.AlignAxis.Y_AXIS, 0));
367+ stage.add_child (titlebar_actor);
368
369 //media keys
370 try {
371@@ -219,7 +211,9 @@
372 });
373
374 bottom_bar.notify["child-revealed"].connect (() => {
375- if (bottom_bar.child_revealed == true) {
376+ // FIX: This event is still triggered while player is offscreen
377+ // So check that!
378+ if (!get_mapped() || bottom_bar.child_revealed == true) {
379 App.get_instance ().mainwindow.get_window ().set_cursor (null);
380 } else {
381 var window = App.get_instance ().mainwindow.get_window ();
382@@ -230,6 +224,7 @@
383 });
384
385 notify["playing"].connect (() => {
386+ var win = App.get_instance ().mainwindow;
387 if (playing) {
388 Audience.Services.Inhibitor.get_instance ().inhibit ();
389 } else {
390@@ -239,9 +234,91 @@
391
392 add (clutter);
393 show_all ();
394- }
395-
396- public void play_file (string uri, bool from_beginning = true) {
397+
398+ unmap.connect (() => {
399+ playing = false;
400+ });
401+ }
402+
403+ public override bool key_press_event (Gdk.EventKey e) {
404+ uint keycode = e.hardware_keycode;
405+
406+ if (match_keycode (Gdk.Key.p, keycode) || match_keycode (Gdk.Key.space, keycode)) {
407+ playing = !playing;
408+ } else if (match_keycode (Gdk.Key.a, keycode)) {
409+ next_audio ();
410+ } else if (match_keycode (Gdk.Key.s, keycode)) {
411+ next_text ();
412+ } else if (match_keycode (Gdk.Key.f, keycode)) {
413+ var win = App.get_instance ().mainwindow;
414+ if (fullscreened) {
415+ win.unfullscreen ();
416+ } else {
417+ win.fullscreen ();
418+ }
419+ }
420+
421+ switch (e.keyval) {
422+ case Gdk.Key.Escape:
423+ var win = App.get_instance ().mainwindow;
424+ if (fullscreened) {
425+ win.unfullscreen ();
426+ } else {
427+ win.destroy ();
428+ }
429+
430+ return true;
431+ case Gdk.Key.Down:
432+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
433+ seek_jump_seconds (-5); // 5 secs
434+ } else {
435+ seek_jump_seconds (-60); // 1 min
436+ }
437+
438+ reveal_control ();
439+ break;
440+ case Gdk.Key.Left:
441+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
442+ seek_jump_seconds (-1); // 1 sec
443+ } else {
444+ seek_jump_seconds (-10); // 10 secs
445+ }
446+
447+ reveal_control ();
448+ break;
449+ case Gdk.Key.Right:
450+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
451+ seek_jump_seconds (1); // 1 sec
452+ } else {
453+ seek_jump_seconds (10); // 10 secs
454+ }
455+
456+ reveal_control ();
457+ break;
458+ case Gdk.Key.Up:
459+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
460+ seek_jump_seconds (5); // 5 secs
461+ } else {
462+ seek_jump_seconds (60); // 1 min
463+ }
464+
465+ reveal_control ();
466+ break;
467+ case Gdk.Key.Page_Down:
468+ seek_jump_seconds (-600); // 10 mins
469+ reveal_control ();
470+ break;
471+ case Gdk.Key.Page_Up:
472+ seek_jump_seconds (600); // 10 mins
473+ reveal_control ();
474+ break;
475+ default:
476+ break;
477+ }
478+ return true;
479+ }
480+
481+ public void play_file (string uri, bool from_beginning = true, string back_to = "") {
482 debug ("Opening %s", uri);
483 get_playlist_widget ().set_current (uri);
484 playback.uri = uri;
485@@ -258,6 +335,9 @@
486 playback.progress = settings.last_stopped;
487 }
488
489+ bottom_bar.titlebar.show_back (back_to);
490+ _back_target = back_to; // navigate there when we're done
491+
492 playback.playing = !settings.playback_wait;
493 Gtk.RecentManager recent_manager = Gtk.RecentManager.get_default ();
494 recent_manager.add_item (uri);
495
496=== added file 'src/Widgets/TitleBar.vala'
497--- src/Widgets/TitleBar.vala 1970-01-01 00:00:00 +0000
498+++ src/Widgets/TitleBar.vala 2017-01-28 06:32:01 +0000
499@@ -0,0 +1,309 @@
500+namespace Audience {
501+ public class TitleBar : Gtk.EventBox {
502+ private Gtk.HeaderBar header;
503+ private Gtk.Button unfullscreen_button;
504+
505+ construct {
506+ header = new Gtk.HeaderBar ();
507+ add (header);
508+
509+ header.show_close_button = true;
510+ var style = header.get_style_context ();
511+ style.add_class (Gtk.STYLE_CLASS_TITLEBAR);
512+ style.add_class ("compact");
513+
514+ unfullscreen_button = new Gtk.Button.from_icon_name ("window-restore-symbolic");
515+ unfullscreen_button.visible = false;
516+ unfullscreen_button.can_focus = false;
517+ unfullscreen_button.clicked.connect (() => {
518+ toplevel_window.unfullscreen ();
519+
520+ });
521+ header.pack_end (unfullscreen_button);
522+
523+ map.connect (init_toplevel_window);
524+ unmap.connect (deinit_toplevel_window);
525+
526+ show_all ();
527+
528+ // Set up standard titlebar event handling,
529+ // just like https://git.gnome.org/browse/gtk+/tree/gtk/gtkwindow.c?h=3.22.6#n1741
530+ multipress_gesture = new Gtk.GestureMultiPress (this);
531+ multipress_gesture.set_button (0);
532+ multipress_gesture.set_propagation_phase (Gtk.PropagationPhase.CAPTURE);
533+ multipress_gesture.pressed.connect (multipress_gesture_pressed_cb);
534+
535+ drag_gesture = new Gtk.GestureDrag (this);
536+ drag_gesture.set_propagation_phase (Gtk.PropagationPhase.CAPTURE);
537+ drag_gesture.drag_begin.connect (drag_gesture_begin_cb);
538+ drag_gesture.drag_update.connect (drag_gesture_update_cb);
539+
540+ // Prevent button presses from propagating up.
541+ // Not doing so (with elementary OS's defaults) creates ugly states like unmaximized fullscreen.
542+ button_press_event.connect ((e) => {return true;});
543+ }
544+
545+ private Audience.Window toplevel_window {
546+ get {
547+ // NOTE: The application might not be set up yet,
548+ // so access the window through the widget hierarchy instead.
549+ return get_toplevel () as Audience.Window;
550+ }
551+ }
552+
553+ private Binding title_binding;
554+ private ulong window_state_changed_hook;
555+ private void init_toplevel_window () {
556+ title_binding = toplevel_window.bind_property ("title", header, "title",
557+ BindingFlags.SYNC_CREATE);
558+
559+ window_state_changed_hook = toplevel_window.window_state_event.connect ((e) => {
560+ if (Gdk.WindowState.FULLSCREEN in e.new_window_state) {
561+ header.show_close_button = false;
562+ unfullscreen_button.visible = true;
563+ } else {
564+ header.show_close_button = true;
565+ unfullscreen_button.visible = false;
566+ }
567+
568+ return false;
569+ });
570+ unfullscreen_button.visible = toplevel_window.fullscreened;
571+ header.show_close_button = !toplevel_window.fullscreened;
572+ }
573+
574+ private void deinit_toplevel_window () {
575+ title_binding.unbind ();
576+ toplevel_window.disconnect (window_state_changed_hook);
577+ }
578+
579+ /* The code marked below is transliterated from Gtk+,
580+ as the original code can only apply to a custom titlebar
581+ registered with a Gtk.Window.
582+
583+ It would certainly be a preference not to have this code here. */
584+ private Gtk.GestureDrag drag_gesture;
585+ private Gtk.GestureMultiPress multipress_gesture;
586+
587+ /* Handles button presses.
588+ Transliterated from https://git.gnome.org/browse/gtk+/tree/gtk/gtkwindow.c?h=3.22.6#n1425.
589+ Should be kept in sync with master. */
590+ private void multipress_gesture_pressed_cb (int n_press,
591+ double x, double y) {
592+ var win = toplevel_window;
593+ var gesture = multipress_gesture;
594+ var sequence = gesture.get_current_sequence ();
595+ var button = gesture.get_current_button ();
596+ var event = gesture.get_last_event (sequence);
597+
598+ if (event == null) return;
599+
600+ if (n_press > 1) drag_gesture.set_state (Gtk.EventSequenceState.DENIED);
601+
602+ /* ... original code had to determine regions */
603+
604+ if (win.get_display ().device_is_grabbed (gesture.get_device ())) {
605+ drag_gesture.set_state (Gtk.EventSequenceState.DENIED);
606+ return;
607+ }
608+
609+ switch (button) {
610+ case Gdk.BUTTON_SECONDARY:
611+ if (titlebar_action (win, event, button, n_press))
612+ gesture.set_sequence_state (sequence, Gtk.EventSequenceState.CLAIMED);
613+
614+ gesture.reset ();
615+ drag_gesture.reset ();
616+ break;
617+ case Gdk.BUTTON_MIDDLE:
618+ if (titlebar_action (win, event, button, n_press))
619+ gesture.set_sequence_state (sequence, Gtk.EventSequenceState.CLAIMED);
620+ break;
621+ case Gdk.BUTTON_PRIMARY:
622+ var event_widget = Gtk.get_event_widget (event);
623+
624+ event_widget.get_window ().raise ();
625+
626+ if (n_press == 2)
627+ titlebar_action (win, event, button, n_press);
628+
629+ if (win.has_grab ())
630+ gesture.set_sequence_state (sequence, Gtk.EventSequenceState.CLAIMED);
631+ break;
632+ }
633+ }
634+
635+ /* Triggers the appropriate action for an event.
636+ Transliterated from https://git.gnome.org/browse/gtk+/tree/gtk/gtkwindow.c?h=3.22.6#n1367.
637+ Should be kept in sync with master. */
638+ private bool titlebar_action (Gtk.Window win, Gdk.Event event,
639+ uint button, int n_press) {
640+ var settings = win.get_settings ();
641+ string action = "none";
642+ switch (button) {
643+ case Gdk.BUTTON_PRIMARY:
644+ if (n_press == 2)
645+ action = settings.gtk_titlebar_double_click;
646+ break;
647+ case Gdk.BUTTON_MIDDLE:
648+ action = settings.gtk_titlebar_middle_click;
649+ break;
650+ case Gdk.BUTTON_SECONDARY:
651+ action = settings.gtk_titlebar_right_click;
652+ break;
653+ }
654+
655+ switch (action) {
656+ case "none":
657+ return false;
658+ case "lower":
659+ win.get_window ().lower ();
660+ break;
661+ case "menu":
662+ do_popup (win, event);
663+ break;
664+ default:
665+ /* treat all maximization variants the same */
666+ if (action.has_prefix ("toggle-maximize")) {
667+ if (win.get_resizable () && win.get_type_hint () == Gdk.WindowTypeHint.NORMAL)
668+ toggle_maximized (win);
669+ } else {
670+ warning ("Unsupported titlebar action %s", action);
671+ return false;
672+ }
673+ break;
674+ }
675+
676+ return true;
677+ }
678+
679+ private double start_x;
680+ private double start_y;
681+ private void drag_gesture_begin_cb (double start_x, double start_y) {
682+ this.start_x = start_x;
683+ this.start_y = start_y;
684+
685+ var sequence = drag_gesture.get_current_sequence ();
686+ var event = drag_gesture.get_last_event (sequence);
687+ multipress_gesture.handle_event (event);
688+ }
689+
690+ /* Starts window movement on drag.
691+ Transliterated from https://git.gnome.org/browse/gtk+/tree/gtk/gtkwindow.c?h=3.22.6#n1570.
692+ Should be kept up to date with master. */
693+ private void drag_gesture_update_cb (double offset_x, double offset_y) {
694+ var gesture = drag_gesture;
695+ var win = toplevel_window;
696+ var settings = win.get_settings ();
697+ var double_click_distance = settings.gtk_double_click_distance;
698+
699+ if (offset_x.abs () > double_click_distance ||
700+ offset_y.abs () > double_click_distance) {
701+ var sequence = gesture.get_current_sequence ();
702+ var event = gesture.get_last_event (sequence);
703+ var event_widget = Gtk.get_event_widget (event);
704+
705+ /* Check whether the target widget should be left alone at
706+ * handling the sequence, this is better done late to give
707+ * room for gestures there to go denied.
708+ *
709+ * Besides claiming gestures, we must bail out too if there's
710+ * gestures in the "none" state at this point, as those are
711+ * still handling events and can potentially go claimed, and
712+ * we don't want to stop the target widget from doing anything.
713+ */
714+ if (event_widget != this && !event_widget.has_grab ()) {
715+ gesture.set_state (Gtk.EventSequenceState.DENIED);
716+ return;
717+ }
718+
719+ gesture.set_state (Gtk.EventSequenceState.CLAIMED);
720+
721+ double? x_root;
722+ double? y_root;
723+ get_window ().get_root_coords ((int) start_x, (int) start_y, out x_root, out y_root);
724+
725+ win.get_window ().begin_move_drag_for_device (
726+ gesture.get_device (),
727+ (int) gesture.get_current_button (),
728+ (int) x_root, (int) y_root,
729+ Gtk.get_current_event_time ());
730+
731+ gesture.reset ();
732+ multipress_gesture.reset ();
733+ }
734+ }
735+
736+ private void toggle_maximized (Gtk.Window win) {
737+ if (win.is_maximized) win.unmaximize ();
738+ else win.maximize ();
739+ }
740+
741+ private void do_popup (Gtk.Window win, Gdk.Event event) {
742+ win.get_window ().show_window_menu (event);
743+ }
744+
745+ private NavigationButton? navigation_button;
746+ private string back_target;
747+ public void show_back (string label, string target = "") {
748+ if (target == "") target = label;
749+ back_target = target;
750+
751+ if (navigation_button == null) {
752+ navigation_button = new NavigationButton ();
753+ navigation_button.clicked.connect (() => {
754+ toplevel_window.show_page (back_target, Gtk.StackTransitionType.SLIDE_RIGHT);
755+ });
756+ header.pack_start (navigation_button);
757+ navigation_button.show_all ();
758+
759+ var accel = new Gtk.AccelGroup ();
760+ accel.connect (Gdk.Key.Left, Gdk.ModifierType.CONTROL_MASK,
761+ Gtk.AccelFlags.VISIBLE | Gtk.AccelFlags.LOCKED,
762+ (group, acceleratable, key, modifier) => {
763+ navigation_button.clicked ();
764+ return true;
765+ });
766+ map.connect (() => {
767+ toplevel_window.add_accel_group (accel);
768+ });
769+ unmap.connect (() => {
770+ toplevel_window.remove_accel_group (accel);
771+ });
772+ }
773+ navigation_button.label = label;
774+ }
775+
776+ public delegate void search_callback (string terms);
777+ public void add_searchbox (search_callback cb) {
778+ var searchbox = new Gtk.SearchEntry ();
779+ searchbox.placeholder_text = _("Search Videos");
780+ searchbox.margin_right = 5;
781+ searchbox.search_changed.connect (() => {
782+ cb (searchbox.text);
783+ });
784+ header.pack_end (searchbox);
785+
786+ var accel = new Gtk.AccelGroup ();
787+ accel.connect (Gdk.Key.F, Gdk.ModifierType.CONTROL_MASK,
788+ Gtk.AccelFlags.VISIBLE | Gtk.AccelFlags.LOCKED,
789+ (group, acceleratable, key, modifier) => {
790+ searchbox.grab_focus ();
791+ return true;
792+ });
793+ accel.connect (Gdk.Key.Escape, 0,
794+ Gtk.AccelFlags.VISIBLE | Gtk.AccelFlags.LOCKED,
795+ (group, acceleratable, key, modifier) => {
796+ searchbox.text = "";
797+ return true;
798+ });
799+ map.connect (() => {
800+ searchbox.text = "";
801+ toplevel_window.add_accel_group (accel);
802+ });
803+ unmap.connect (() => {
804+ toplevel_window.remove_accel_group(accel);
805+ });
806+ }
807+ }
808+}
809
810=== modified file 'src/Widgets/WelcomePage.vala'
811--- src/Widgets/WelcomePage.vala 2016-09-28 02:32:33 +0000
812+++ src/Widgets/WelcomePage.vala 2017-01-28 06:32:01 +0000
813@@ -1,13 +1,20 @@
814 namespace Audience {
815- public class WelcomePage : Granite.Widgets.Welcome {
816+ public class WelcomePage : Gtk.Grid {
817 private DiskManager disk_manager;
818 private Services.LibraryManager library_manager;
819- public WelcomePage () {
820- base (_("No Videos Open"), _("Select a source to begin playing."));
821- }
822+
823+ private Granite.Widgets.Welcome welcome;
824+
825+ public WelcomePage () {}
826
827 construct {
828- append ("document-open", _("Open file"), _("Open a saved file."));
829+ orientation = Gtk.Orientation.VERTICAL;
830+ add (new TitleBar ());
831+
832+ welcome = new Granite.Widgets.Welcome (_("No Videos Open"),
833+ _("Select a source to begin playing."));
834+ welcome.append ("document-open", _("Open file"), _("Open a saved file."));
835+ add (welcome);
836
837 var filename = settings.current_video;
838 var last_file = File.new_for_uri (filename);
839@@ -17,40 +24,42 @@
840 }
841
842 if (settings.last_stopped == 0.0 || !settings.resume_videos) {
843- append ("media-playlist-repeat", _("Replay last video"), get_title (last_file.get_basename ()));
844+ welcome.append ("media-playlist-repeat", _("Replay last video"),
845+ get_title (last_file.get_basename ()));
846 } else {
847- append ("media-playback-start", _("Resume last video"), get_title (last_file.get_basename ()));
848+ welcome.append ("media-playback-start", _("Resume last video"),
849+ get_title (last_file.get_basename ()));
850 }
851
852- set_item_visible (1, show_last_file);
853+ welcome.set_item_visible (1, show_last_file);
854
855 //look for dvd
856 disk_manager = DiskManager.get_default ();
857 disk_manager.volume_found.connect ((vol) => {
858- set_item_visible (2, disk_manager.has_media_volumes ());
859+ welcome.set_item_visible (2, disk_manager.has_media_volumes ());
860 });
861
862 disk_manager.volume_removed.connect ((vol) => {
863- set_item_visible (2, disk_manager.has_media_volumes ());
864+ welcome.set_item_visible (2, disk_manager.has_media_volumes ());
865 });
866
867 library_manager = Services.LibraryManager.get_instance ();
868 library_manager.video_file_detected.connect ((vid) => {
869- set_item_visible (3, true);
870+ welcome.set_item_visible (3, true);
871 this.show_all ();
872 });
873
874 library_manager.video_file_deleted.connect ((vid) => {
875- set_item_visible (3, LibraryPage.get_instance ().has_items);
876+ welcome.set_item_visible (3, LibraryPage.get_instance ().has_items);
877 });
878
879- append ("media-cdrom", _("Play from Disc"), _("Watch a DVD or open a file from disc"));
880- set_item_visible (2, disk_manager.has_media_volumes ());
881-
882- append ("folder-videos", _("Browse Library"), _("Watch a movie from your library"));
883- set_item_visible (3, library_manager.has_items);
884-
885- activated.connect ((index) => {
886+ welcome.append ("media-cdrom", _("Play from Disc"), _("Watch a DVD or open a file from disc"));
887+ welcome.set_item_visible (2, disk_manager.has_media_volumes ());
888+
889+ welcome.append ("folder-videos", _("Browse Library"), _("Watch a movie from your library"));
890+ welcome.set_item_visible (3, library_manager.has_items);
891+
892+ welcome.activated.connect ((index) => {
893 var window = App.get_instance ().mainwindow;
894 switch (index) {
895 case 0:
896@@ -64,13 +73,17 @@
897 window.run_open_dvd ();
898 break;
899 case 3:
900- window.show_library ();
901+ window.show_page (Audience.Window.page_label_library);
902 }
903 });
904+
905+ map.connect (() => {
906+ App.get_instance ().mainwindow.title = _("Videos");
907+ });
908 }
909
910 public void refresh () {
911- var replay_button = get_button_from_index (1);
912+ var replay_button = welcome.get_button_from_index (1);
913
914 var filename = settings.current_video;
915 var last_file = File.new_for_uri (filename);
916@@ -89,8 +102,25 @@
917 show_last_file = false;
918 }
919
920- set_item_visible (1, show_last_file);
921- set_item_visible (2, disk_manager.has_media_volumes ());
922+ welcome.set_item_visible (1, show_last_file);
923+ welcome.set_item_visible (2, disk_manager.has_media_volumes ());
924+ }
925+
926+ public override bool key_press_event (Gdk.EventKey e) {
927+ uint keycode = e.hardware_keycode;
928+ bool ctrl_pressed = (e.state & Gdk.ModifierType.CONTROL_MASK) != 0;
929+ var win = App.get_instance ().mainwindow;
930+
931+ if (match_keycode (Gdk.Key.p, keycode) || match_keycode (Gdk.Key.space, keycode)) {
932+ win.resume_last_videos ();
933+ } else if (ctrl_pressed && match_keycode (Gdk.Key.o, keycode)) {
934+ win.run_open_file ();
935+ } else if (ctrl_pressed && match_keycode (Gdk.Key.q, keycode)) {
936+ win.destroy ();
937+ } else if (ctrl_pressed && match_keycode (Gdk.Key.b, keycode)) {
938+ win.show_page (Audience.Window.page_label_library);
939+ }
940+ return true;
941 }
942 }
943 }
944
945=== modified file 'src/Window.vala'
946--- src/Window.vala 2017-01-25 22:40:27 +0000
947+++ src/Window.vala 2017-01-28 06:32:01 +0000
948@@ -23,22 +23,22 @@
949
950 public class Audience.Window : Gtk.Window {
951 private Gtk.Stack main_stack;
952- private Gtk.HeaderBar header;
953 private PlayerPage player_page;
954 private WelcomePage welcome_page;
955 private LibraryPage library_page;
956 private EpisodesPage episodes_page;
957- private Granite.Widgets.AlertView alert_view;
958 private Toast app_notification;
959- private NavigationButton navigation_button;
960 private ZeitgeistManager zeitgeist_manager;
961- private Gtk.SearchEntry search_entry;
962
963
964 // For better translation
965- const string navigation_button_welcomescreen = N_("Back");
966- const string navigation_button_library = N_("Library");
967- const string navigation_button_episodes = N_("Episodes");
968+ public static string page_label_welcomescreen;
969+ public static string page_label_library;
970+ public static string page_label_episodes;
971+ // No back button, hence no need for translation
972+ public static string page_label_player = "player";
973+
974+ public bool fullscreened = false;
975
976 public signal void media_volumes_changed ();
977
978@@ -47,76 +47,42 @@
979 }
980
981 construct {
982+ // Initialize translations
983+ page_label_welcomescreen = _("Back");
984+ page_label_library = _("Library");
985+ page_label_episodes = _("Episodes");
986+
987+
988 zeitgeist_manager = new ZeitgeistManager ();
989 window_position = Gtk.WindowPosition.CENTER;
990 gravity = Gdk.Gravity.CENTER;
991 set_default_geometry (1000, 680);
992
993- header = new Gtk.HeaderBar ();
994- header.set_show_close_button (true);
995- header.get_style_context ().add_class ("compact");
996-
997- navigation_button = new NavigationButton ();
998- navigation_button.clicked.connect (() => {
999- navigate_back ();
1000+ // Put something empty in to hide the title bar,
1001+ // leaving a rectangular window for the video to fill.
1002+ var titlebar = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
1003+ set_titlebar (titlebar);
1004+ map.connect (() => {
1005+ titlebar.visible = false;
1006 });
1007
1008- header.pack_start (navigation_button);
1009-
1010- search_entry = new Gtk.SearchEntry ();
1011- search_entry.placeholder_text = _("Search Videos");
1012- search_entry.margin_right = 5;
1013- search_entry.search_changed.connect (() => {
1014- if (main_stack.visible_child == episodes_page ) {
1015- episodes_page.filter (search_entry.text);
1016- } else {
1017- library_page.filter (search_entry.text);
1018- }
1019- });
1020-
1021- header.pack_end (search_entry);
1022-
1023- set_titlebar (header);
1024-
1025 library_page = LibraryPage.get_instance ();
1026 library_page.map.connect (() => {
1027- search_entry.visible = true;
1028- if (search_entry.text != "" && !library_page.has_child ()) {
1029- search_entry.text = "";
1030- }
1031 if (library_page.last_filter != "") {
1032- search_entry.text = library_page.last_filter;
1033 library_page.last_filter = "";
1034 }
1035 });
1036- library_page.unmap.connect (() => {
1037- if (main_stack.visible_child != alert_view && main_stack.visible_child != episodes_page) {
1038- search_entry.visible = false;
1039- }
1040- });
1041- library_page.filter_result_changed.connect ((has_result) => {
1042- if (!has_result) {
1043- show_alert (_("No Results for “%s”").printf (search_entry.text), _("Try changing search terms."), "edit-find-symbolic");
1044- } else if (main_stack.visible_child != library_page ) {
1045- hide_alert ();
1046- }
1047- });
1048 library_page.show_episodes.connect ((item) => {
1049- navigation_button.label = _(navigation_button_library);
1050 episodes_page.set_episodes_items (item.episodes);
1051 episodes_page.poster.pixbuf = item.poster.pixbuf;
1052 main_stack.set_visible_child (episodes_page);
1053 this.title = item.get_title ();
1054- search_entry.text = "";
1055 });
1056
1057 welcome_page = new WelcomePage ();
1058
1059 player_page = new PlayerPage ();
1060 player_page.ended.connect (on_player_ended);
1061- player_page.unfullscreen_clicked.connect (() => {
1062- unfullscreen ();
1063- });
1064
1065 player_page.notify["playing"].connect (() => {
1066 set_keep_above (player_page.playing && settings.stay_on_top);
1067@@ -130,23 +96,14 @@
1068 app_notification.visible = true;
1069 });
1070
1071- alert_view = new Granite.Widgets.AlertView ("", "", "");
1072- alert_view.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL);
1073- alert_view.set_vexpand (true);
1074- alert_view.no_show_all = true;
1075-
1076 episodes_page = new EpisodesPage ();
1077- episodes_page.map.connect (() => {
1078- search_entry.visible = true;
1079- });
1080
1081 main_stack = new Gtk.Stack ();
1082 main_stack.expand = true;
1083- main_stack.add_named (welcome_page, "welcome");
1084- main_stack.add_named (player_page, "player");
1085- main_stack.add_named (library_page, "library");
1086- main_stack.add_named (episodes_page, "episodes");
1087- main_stack.add_named (alert_view, "alert");
1088+ main_stack.add_named (welcome_page, page_label_welcomescreen);
1089+ main_stack.add_named (player_page, page_label_player);
1090+ main_stack.add_named (library_page, page_label_library);
1091+ main_stack.add_named (episodes_page, page_label_episodes);
1092 main_stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT;
1093
1094 app_notification = new Toast ();
1095@@ -165,9 +122,7 @@
1096 add (overlay);
1097 show_all ();
1098
1099- navigation_button.hide ();
1100- search_entry.visible = false;
1101- main_stack.set_visible_child_full ("welcome", Gtk.StackTransitionType.NONE);
1102+ main_stack.set_visible_child_full (page_label_welcomescreen, Gtk.StackTransitionType.NONE);
1103
1104 Gtk.TargetEntry uris = {"text/uri-list", 0, 0};
1105 Gtk.drag_dest_set (this, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.MOVE);
1106@@ -201,8 +156,7 @@
1107
1108 window_state_event.connect ((e) => {
1109 if (Gdk.WindowState.FULLSCREEN in e.changed_mask) {
1110- player_page.fullscreened = Gdk.WindowState.FULLSCREEN in e.new_window_state;
1111- header.visible = !player_page.fullscreened;
1112+ fullscreened = player_page.fullscreened = Gdk.WindowState.FULLSCREEN in e.new_window_state;
1113 }
1114
1115 /*/ FIXME: Remove comments once gala bug is fixed: https://bugs.launchpad.net/gala/+bug/1602722
1116@@ -218,124 +172,22 @@
1117 });
1118 }
1119
1120- /** Returns true if the code parameter matches the keycode of the keyval parameter for
1121- * any keyboard group or level (in order to allow for non-QWERTY keyboards) **/
1122- public bool match_keycode (int keyval, uint code) {
1123- Gdk.KeymapKey [] keys;
1124- Gdk.Keymap keymap = Gdk.Keymap.get_default ();
1125- if (keymap.get_entries_for_keyval (keyval, out keys)) {
1126- foreach (var key in keys) {
1127- if (code == key.keycode)
1128- return true;
1129- }
1130- }
1131-
1132- return false;
1133+ /** Shows the specified view,
1134+ * largely used to implement back buttons */
1135+ public void show_page (string name,
1136+ Gtk.StackTransitionType transition = Gtk.StackTransitionType.SLIDE_LEFT) {
1137+ main_stack.set_visible_child_full (name, transition);
1138 }
1139
1140 public override bool key_press_event (Gdk.EventKey e) {
1141 uint keycode = e.hardware_keycode;
1142 bool ctrl_pressed = (e.state & Gdk.ModifierType.CONTROL_MASK) != 0;
1143- if ((e.state & Gdk.ModifierType.MOD1_MASK) != 0 && e.keyval == Gdk.Key.Left) {
1144- navigation_button.clicked ();
1145- return true;
1146- }
1147-
1148- if (main_stack.visible_child == player_page) {
1149- if (match_keycode (Gdk.Key.p, keycode) || match_keycode (Gdk.Key.space, keycode)) {
1150- player_page.playing = !player_page.playing;
1151- } else if (match_keycode (Gdk.Key.a, keycode)) {
1152- player_page.next_audio ();
1153- } else if (match_keycode (Gdk.Key.s, keycode)) {
1154- player_page.next_text ();
1155- } else if (match_keycode (Gdk.Key.f, keycode)) {
1156- if (player_page.fullscreened) {
1157- unfullscreen ();
1158- } else {
1159- fullscreen ();
1160- }
1161- }
1162-
1163- switch (e.keyval) {
1164- case Gdk.Key.Escape:
1165- if (player_page.fullscreened) {
1166- unfullscreen ();
1167- } else {
1168- destroy ();
1169- }
1170-
1171- return true;
1172- case Gdk.Key.Down:
1173- if (Gdk.ModifierType.SHIFT_MASK in e.state) {
1174- player_page.seek_jump_seconds (-5); // 5 secs
1175- } else {
1176- player_page.seek_jump_seconds (-60); // 1 min
1177- }
1178-
1179- player_page.reveal_control ();
1180- break;
1181- case Gdk.Key.Left:
1182- if (Gdk.ModifierType.SHIFT_MASK in e.state) {
1183- player_page.seek_jump_seconds (-1); // 1 sec
1184- } else {
1185- player_page.seek_jump_seconds (-10); // 10 secs
1186- }
1187-
1188- player_page.reveal_control ();
1189- break;
1190- case Gdk.Key.Right:
1191- if (Gdk.ModifierType.SHIFT_MASK in e.state) {
1192- player_page.seek_jump_seconds (1); // 1 sec
1193- } else {
1194- player_page.seek_jump_seconds (10); // 10 secs
1195- }
1196-
1197- player_page.reveal_control ();
1198- break;
1199- case Gdk.Key.Up:
1200- if (Gdk.ModifierType.SHIFT_MASK in e.state) {
1201- player_page.seek_jump_seconds (5); // 5 secs
1202- } else {
1203- player_page.seek_jump_seconds (60); // 1 min
1204- }
1205-
1206- player_page.reveal_control ();
1207- break;
1208- case Gdk.Key.Page_Down:
1209- player_page.seek_jump_seconds (-600); // 10 mins
1210- player_page.reveal_control ();
1211- break;
1212- case Gdk.Key.Page_Up:
1213- player_page.seek_jump_seconds (600); // 10 mins
1214- player_page.reveal_control ();
1215- break;
1216- default:
1217- break;
1218- }
1219- } else if (main_stack.visible_child == welcome_page) {
1220- if (match_keycode (Gdk.Key.p, keycode) || match_keycode (Gdk.Key.space, keycode)) {
1221- resume_last_videos ();
1222- return true;
1223- } else if (ctrl_pressed && match_keycode (Gdk.Key.o, keycode)) {
1224- run_open_file ();
1225- return true;
1226- } else if (ctrl_pressed && match_keycode (Gdk.Key.q, keycode)) {
1227- destroy ();
1228- return true;
1229- } else if (ctrl_pressed && match_keycode (Gdk.Key.b, keycode)) {
1230- show_library ();
1231- return true;
1232- }
1233- } else if (search_entry.visible) {
1234- if (ctrl_pressed && match_keycode (Gdk.Key.f, keycode)) {
1235- search_entry.grab_focus ();
1236- } else if (ctrl_pressed && match_keycode (Gdk.Key.z, keycode)) {
1237+
1238+ if (main_stack.visible_child == library_page ||
1239+ main_stack.visible_child == episodes_page) {
1240+ if (ctrl_pressed && match_keycode (Gdk.Key.z, keycode)) {
1241 library_page.manager.undo_delete_item ();
1242 app_notification.reveal_child = false;
1243- } else if (match_keycode (Gdk.Key.Escape, keycode)) {
1244- search_entry.text = "";
1245- } else if (!search_entry.is_focus && e.str.strip ().length > 0) {
1246- search_entry.grab_focus ();
1247 }
1248 }
1249
1250@@ -381,13 +233,6 @@
1251 read_first_disk.begin ();
1252 }
1253
1254- public void show_library () {
1255- navigation_button.label = _(navigation_button_welcomescreen);
1256- navigation_button.show ();
1257- main_stack.visible_child = library_page;
1258- library_page.scrolled_window.grab_focus ();
1259- }
1260-
1261 public void run_open_file (bool clear_playlist = false, bool force_play = true) {
1262 var file = new Gtk.FileChooserDialog (_("Open"), this, Gtk.FileChooserAction.OPEN,
1263 _("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.ACCEPT);
1264@@ -449,25 +294,13 @@
1265 }
1266
1267 private void on_player_ended () {
1268- navigate_back ();
1269 unfullscreen ();
1270 }
1271
1272 public void play_file (string uri, bool from_beginning = true) {
1273- search_entry.visible = false;
1274- if (navigation_button.visible) {
1275- if (navigation_button.label == _(navigation_button_library)) {
1276- navigation_button.label = _(navigation_button_episodes);
1277- } else {
1278- navigation_button.label = _(navigation_button_library);
1279- }
1280- } else {
1281- navigation_button.show ();
1282- navigation_button.label = _(navigation_button_welcomescreen);
1283- }
1284-
1285- main_stack.set_visible_child_full ("player", Gtk.StackTransitionType.SLIDE_LEFT);
1286- player_page.play_file (uri, from_beginning);
1287+ var back_target = main_stack.visible_child_name;
1288+ main_stack.set_visible_child_full (page_label_player, Gtk.StackTransitionType.SLIDE_LEFT);
1289+ player_page.play_file (uri, from_beginning, back_target);
1290 if (is_maximized) {
1291 fullscreen ();
1292 }
1293@@ -479,47 +312,6 @@
1294 welcome_page.refresh ();
1295 }
1296
1297- public void navigate_back () {
1298- double progress = player_page.get_progress ();
1299- if (progress > 0) {
1300- settings.last_stopped = progress;
1301- }
1302- if (player_page.playing) {
1303- player_page.playing = false;
1304- player_page.reset_played_uri ();
1305- }
1306- title = App.get_instance ().program_name;
1307- get_window ().set_cursor (null);
1308-
1309- if (navigation_button.label == _(navigation_button_library)) {
1310- navigation_button.label = _(navigation_button_welcomescreen);
1311- main_stack.set_visible_child_full ("library", Gtk.StackTransitionType.SLIDE_RIGHT);
1312- } else if (navigation_button.label == _(navigation_button_episodes)) {
1313- navigation_button.label = _(navigation_button_library);
1314- main_stack.set_visible_child_full ("episodes", Gtk.StackTransitionType.SLIDE_RIGHT);
1315- } else {
1316- navigation_button.hide ();
1317- main_stack.set_visible_child (welcome_page);
1318- search_entry.visible = false;
1319- }
1320- welcome_page.refresh ();
1321- }
1322-
1323- public void hide_alert () {
1324- alert_view.no_show_all = true;
1325- main_stack.set_visible_child_full ("library", Gtk.StackTransitionType.NONE);
1326- alert_view.hide ();
1327- }
1328-
1329- public void show_alert (string primary_text, string secondary_text, string icon_name) {
1330- alert_view.no_show_all = false;
1331- alert_view.show_all ();
1332- alert_view.title = primary_text;
1333- alert_view.description = secondary_text;
1334- alert_view.icon_name = icon_name;
1335- main_stack.set_visible_child_full ("alert", Gtk.StackTransitionType.NONE);
1336- }
1337-
1338 public void set_app_notification (string text) {
1339 app_notification.set_notification (text);
1340 }

Subscribers

People subscribed via source and target branches