Merge lp:~alcinnz/audience/audience into lp:~audience-members/audience/trunk
- audience
- Merge into trunk
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 |
Related bugs: |
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 |
Commit message
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.
- 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)
Adrian Cochrane (alcinnz) wrote : | # |
> Please, resolve merge conflicts.
They have been resolved, and I verified the translation fix still works.
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.
Danielle Foré (danrabbit) wrote : | # |
It seems like this branch completely removes fullscreen
Cody Garver (codygarver) wrote : | # |
Double click to fullscreen is broken, f key still works.
- 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.
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.
- 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
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/
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.
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.
- 721. By Adrian Cochrane
-
Merging translation fix for "search not found" screen.
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.
if (keymap.
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_
- 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.
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.
> if (keymap.
> 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_
> 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.
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.
> > if (keymap.
> > 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_
> > 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".
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 :)
Danielle Foré (danrabbit) wrote : | # |
Audience has migrated to GitHub. Please resubmit as a PR here: https:/
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
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 | } |
Please, resolve merge conflicts.