Skip to content

Commit abe368e

Browse files
authored
Merge pull request #366 from technosf/development
Refactoring, translations
2 parents d1bdd64 + 394a7ef commit abe368e

30 files changed

Lines changed: 1327 additions & 443 deletions

EVENTS_ARCHITECTURE.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Event Architecture
2+
3+
This document tracks the event orchestration introduced in the 2026 refactor.
4+
5+
## Files and Responsibilities
6+
7+
- `src/Events/AppEventBus.vala`
8+
- Defines typed cross-component application signals.
9+
- Current signals:
10+
- `connectivity_changed(bool is_online, bool is_offline)`
11+
12+
- `src/Coordinators/StartupCoordinator.vala`
13+
- Owns startup workflow orchestration.
14+
- Current workflow:
15+
- deferred autoplay of last station
16+
- waits for online connectivity before autoplay attempt
17+
- attempts autoplay once per app start
18+
19+
- `src/Coordinators/PlaybackRecoveryCoordinator.vala`
20+
- Owns restart-after-outage playback behavior.
21+
- Tracks whether playback was active before loss of connectivity.
22+
- Restarts playback on reconnect when `settings.play_restart` is enabled.
23+
24+
- `src/Coordinators/UsageTrackingCoordinator.vala`
25+
- Owns provider click/vote updates driven by player events.
26+
- Handles both play-start click tracking and periodic tape-counter tracking.
27+
28+
- `src/Application.vala`
29+
- Owns the shared `events` bus instance.
30+
- Emits `connectivity_changed` when `is_online`/`is_offline` changes.
31+
- Instantiates coordinators:
32+
- `PlaybackRecoveryCoordinator` during app construction.
33+
- `UsageTrackingCoordinator` during app construction.
34+
- `StartupCoordinator` after creating the main window.
35+
36+
- `src/Widgets/Window.vala`
37+
- Consumes app-level connectivity events to update interactive window state.
38+
- No longer owns autoplay orchestration.
39+
40+
- `src/Widgets/HeaderBar.vala`
41+
- Consumes app-level connectivity and player-state events for control-state updates.
42+
- No longer owns restart-after-outage orchestration.
43+
44+
- `src/meson.build`
45+
- Registers the new event/coordinator source files in build inputs.
46+
47+
## Event Flow (Connectivity)
48+
49+
1. `Application` detects network change.
50+
2. `Application` updates `is_online` and `is_offline`.
51+
3. `Application` emits `events.connectivity_changed(...)`.
52+
4. Subscribers react:
53+
- `Window` updates active UI state.
54+
- `HeaderBar` updates visual controls.
55+
- `PlaybackRecoveryCoordinator` manages restart-after-outage behavior.
56+
- `StartupCoordinator` tries deferred autoplay when online.
57+
58+
## Design Notes
59+
60+
- Keep local widget events in widget files.
61+
- Use `AppEventBus` for cross-component events that otherwise create tight coupling.
62+
- Use coordinators for workflows that span UI + services + application state.
63+
64+
## Window Action Handling
65+
66+
- `src/Widgets/Window.vala` now centralizes action-state initialization with:
67+
- `sync_action_states_from_settings()`
68+
- Boolean toggle actions now use a shared path:
69+
- `toggle_setting_action(...)`
70+
- This reduces copy/paste logic across action handlers and lowers the chance of mismatched setting/action wiring.
71+
72+
## Search Debounce Ownership
73+
74+
- `src/Widgets/HeaderBar.vala`
75+
- Emits `searching_for_sig` immediately on text change.
76+
- No longer owns debounce timers.
77+
- `src/Controllers/SearchController.vala`
78+
- Owns debounce and pending-search cancellation.
79+
- Uses configured `_max_search_results` instead of a hardcoded limit.
80+
- `src/Widgets/Display.vala`
81+
- Receives search focus/query via explicit methods:
82+
- `on_search_focused()`
83+
- `on_search_requested(string text)`
84+
- No longer routes search input through internal self-signals.
85+
86+
## Application Bootstrap Decomposition
87+
88+
- `src/Application.vala`
89+
- Keeps construct-only property assignment in the `construct` block.
90+
- Splits initialization responsibilities into helper methods:
91+
- runtime storage preparation + migration
92+
- connectivity monitoring setup
93+
- core service factory helpers
94+
- coordinator initialization
95+
- action registration helpers
96+
- Activation flow is split into explicit lifecycle helpers:
97+
- `initialize_runtime_presentation()`
98+
- `apply_runtime_preferences()`
99+
- `create_main_window()`
100+
101+
## Window Connectivity UI State
102+
103+
- `src/Widgets/Window.vala`
104+
- `check_online_status()` now delegates UI transitions to:
105+
- `apply_offline_ui_state()`
106+
- `apply_online_ui_state()`
107+
- Keeps online/offline behavior explicit and reduces branching complexity.
108+
109+
## Display API Cleanup
110+
111+
- `src/Widgets/Display.vala`
112+
- Removed unused public signals:
113+
- `favourites_changed_sig`
114+
- `refresh_starred_stations_sig`
115+
- Keeps the public event surface aligned with active call paths.
116+
117+
## Dependency Injection Sweep
118+
119+
- Replaced singleton `app()` lookups with injected references in:
120+
- `src/Widgets/HeaderBar.vala`
121+
- `src/Widgets/Display.vala`
122+
- `src/Services/DBusMediaPlayer.vala`
123+
- Constructors and initializers now receive required collaborators explicitly
124+
(`Application`, `PlayerController`, `DataProvider.API`, `StarStore`), reducing
125+
hidden coupling and startup-order risk.
126+
127+
## Coordinator Connectivity Injection
128+
129+
- Removed remaining coordinator singleton lookups by injecting `Application`
130+
explicitly into:
131+
- `src/Coordinators/StartupCoordinator.vala`
132+
- `src/Coordinators/PlaybackRecoveryCoordinator.vala`
133+
- `StartupCoordinator.try_autoplay()` now checks `_app.is_offline`.
134+
- `PlaybackRecoveryCoordinator.on_player_state_changed()` now checks
135+
`_app.is_online`.
136+
- `src/Application.vala` constructor wiring now passes `this` into coordinator
137+
constructors, making coordinator connectivity decisions explicit and testable.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
1111

1212
Minimalist radio station player - **Tuner** Version 2
1313

14-
![Screenshot 01](docs/Tuner_2.0_discover.png?raw=true)
14+
<p align="center">
15+
<img src="docs/Tuner_201_one.png" width="600">
16+
</p>
1517

1618
>I love listening to radio while I work. There are tens of thousands of cool internet radio stations available, however I find it hard to "find" new stations by using filters and genres. As of now, this little app takes away all the filtering and just presents me with new radio stations every time I use it.
1719
>
@@ -114,7 +116,7 @@ Help is apreciated:
114116
- [technosf](https://github.com/technosf) Current maintainer and rewriter of a swarthe of Tuner for V2
115117
- [louis77](https://github.com/louis77) Originator and genius behind Tuner
116118
- [@jrthwlate](https://hosted.weblate.org/user/jrthwlate/) - Estonian translation
117-
- [faleksandar.com](https://faleksandar.com/) for icons and colors
119+
- [@yakushabb](https://github.com/yakushabb) for flathub and flatpak config help
118120
- [faleksandar.com](https://faleksandar.com/) for icons and colors
119121
- [@NathanBnm](https://github.com/NathanBnm) - French translation
120122
- [@DevAlien](https://github.com/DevAlien) - Italian translation

data/io.github.tuner_labs.tuner.metainfo.xml.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
111111
<li>Refactored namespaces</li>
112112
<li>Fixed: play/stop buttons disabled #223</li>
113113
<li>Fixed: Jukebox stops when tuning to a dead station #256</li>
114+
<li>Disabled in-app language selection for non-debug and flatpak builds</li>
114115
</ul>
115116
</description>
116117
</release>

io.github.tuner_labs.tuner.debug.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ cleanup:
3838
- "*.la"
3939
- "*.a"
4040

41+
42+
# Build flatpak with --no-separate-locales to avoid having to deal with translations in a separate module
43+
separate-locales: false # Debug builds only
44+
45+
4146
modules:
4247

4348
- name: libgee

io.github.tuner_labs.tuner.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ build-options:
1919
prepend-path: /usr/lib/sdk/vala/bin/
2020
prepend-ld-library-path: /usr/lib/sdk/vala/lib
2121

22+
2223
finish-args:
2324
- --share=ipc
2425
- --socket=fallback-x11
@@ -28,6 +29,7 @@ finish-args:
2829
- --own-name=org.mpris.MediaPlayer2.io.github.tuner_labs.tuner
2930
- --filesystem=xdg-desktop # Playlist import export
3031

32+
3133
cleanup:
3234
- /include
3335
- /lib/girepository-1.0
@@ -36,9 +38,7 @@ cleanup:
3638
- /share/vala
3739
- "*.la"
3840
- "*.a"
39-
40-
# Build flatpak with --no-separate-locales to avoid having to deal with translations in a separate module
41-
separate-locales: false
41+
4242

4343
modules:
4444

meson.build

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
# SPDX-License-Identifier: GPL-3.0-or-later
55
#
66

7-
# Project name, programming language and version
7+
##
8+
## Tuner main meson build file
9+
##
10+
11+
## Project name, programming language and version
812
project (
913
'io.github.tuner_labs.tuner',
1014
'vala', 'c',
@@ -13,16 +17,38 @@ project (
1317
)
1418

1519
message('Starting build for project: ' + meson.project_name())
20+
21+
##
22+
## Local debug build - let vala compiler know
23+
##
24+
25+
message('opts: ' + get_option('debug').to_string() + ' prefix: ' + get_option('prefix')+ ' prefix check: ' + (get_option('prefix') != '/app').to_string() )
26+
27+
vala_args = []
28+
29+
debug_local = get_option('debug') and get_option('prefix') != '/app'
30+
if debug_local
31+
message('DEBUG_LOCAL')
32+
vala_args += ['--define=DEBUG_LOCAL']
33+
endif
34+
35+
##
36+
##
37+
38+
1639
message('Build type: ' + get_option('buildtype'))
1740

1841

19-
# Imports
42+
## Imports
2043

2144
i18n = import ('i18n') # Translation module
2245
gnome = import('gnome') # GNOME module
2346
fs = import('fs') # Filesystem
2447

25-
# Translations and i18n handling
48+
49+
##
50+
## Translations and i18n handling
51+
##
2652

2753
po_script = join_paths(meson.global_source_root(),'scripts','merge-po.sh')
2854

@@ -34,21 +60,27 @@ endif
3460
subdir ('po')
3561

3662

37-
# Project arguments
63+
## Project arguments
3864
add_project_arguments (
3965
'-DGETTEXT_PACKAGE="@0@"'.format (meson.project_name ()),
4066
language: 'c'
4167
)
4268

4369
config_data = configuration_data()
4470

45-
## Enable local debug of translations if we're doing a local debug build
46-
if get_option('debug') and get_option('prefix') != '/app'
47-
## Local debug build, install translations to build dir
48-
config_data.set_quoted('LOCALEDIR', join_paths(meson.global_build_root(), 'po'))
71+
#
72+
# Enable local debug of translations if we're doing a local debug build
73+
#
74+
if debug_local
75+
76+
## Local debug build, install translations to build dir
77+
config_data.set_quoted('LOCALEDIR', join_paths(meson.global_build_root(), 'po'))
78+
4979
else
50-
## Everything else, install translations to prefix
51-
config_data.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
80+
81+
## Everything else, install translations to prefix
82+
config_data.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
83+
5284
endif
5385

5486
config_data.set_quoted('GETTEXT_PACKAGE', meson.project_name())
@@ -59,21 +91,24 @@ config_file = configure_file(
5991
configuration: config_data
6092
)
6193

62-
# Compiling resources
94+
##
95+
## Compiling resources
96+
##
6397
asresources = gnome.compile_resources (
6498
'as-resources',
6599
join_paths ('data', meson.project_name ()) + '.gresource.xml',
66100
source_dir: 'data',
67101
c_name: 'as'
68102
)
69103

70-
# Listing dependencies
104+
##
105+
## Listing dependencies
106+
##
71107
dependencies = [
72108
dependency ('glib-2.0'),
73109
dependency ('gtk+-3.0'),
74110
dependency ('gee-0.8'),
75111
dependency ('gio-2.0'),
76-
# dependency ('granite'),
77112
dependency ('gstreamer-1.0'),
78113
dependency ('gstreamer-player-1.0'),
79114
dependency ('libsoup-3.0'),
@@ -82,14 +117,16 @@ dependencies = [
82117

83118
subdir ('src')
84119

85-
# Executable
120+
##
121+
## Executable
122+
##
86123
executable (
87124
meson.project_name (),
88125
asresources,
89126
config_file,
90127
sources,
91128
dependencies: dependencies,
92-
vala_args: ['--pkg', 'posix'],
129+
vala_args: vala_args + ['--pkg', 'posix'],
93130
install: true
94131
)
95132

0 commit comments

Comments
 (0)