Skip to content

Commit 6d94a39

Browse files
committed
Refactor service registry usage in Page control
Consolidated service registries in the Page control by removing separate _user_services and _page_services in favor of a single _services property. Updated related Dart and Python code, including tests and service registration logic, to reflect this change. Deprecated direct service properties on Page in favor of using service classes directly.
1 parent 783d6fc commit 6d94a39

File tree

6 files changed

+113
-105
lines changed

6 files changed

+113
-105
lines changed

packages/flet/lib/src/controls/page.dart

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,8 @@ class _PageControlState extends State<PageControl> with WidgetsBindingObserver {
5656
late final SimpleRouterDelegate _routerDelegate;
5757
late final RouteParser _routeParser;
5858
late final AppLifecycleListener _appLifecycleListener;
59-
ServiceRegistry? _pageServices;
60-
ServiceRegistry? _userServices;
61-
String? _userServicesUid;
59+
ServiceRegistry? _services;
60+
String? _servicesUid;
6261
ServiceBinding? _windowService;
6362
Control? _windowControl;
6463
bool? _prevOnKeyboardEvent;
@@ -136,8 +135,7 @@ class _PageControlState extends State<PageControl> with WidgetsBindingObserver {
136135
}
137136
widget.control.removeInvokeMethodListener(_invokeMethod);
138137
widget.control.removeListener(_onPageControlChanged);
139-
_pageServices?.dispose();
140-
_userServices?.dispose();
138+
_services?.dispose();
141139
_windowService?.dispose();
142140
super.dispose();
143141
}
@@ -152,24 +150,21 @@ class _PageControlState extends State<PageControl> with WidgetsBindingObserver {
152150
}
153151
var backend = FletBackend.of(context);
154152

155-
_pageServices ??= ServiceRegistry(
156-
control: widget.control, propertyName: "_services", backend: backend);
157-
158-
var userServicesControl = widget.control.child("_user_services");
159-
if (userServicesControl != null) {
160-
var uid = userServicesControl.internals?["uid"];
161-
if (_userServices == null || _userServicesUid != uid) {
162-
_userServices?.dispose();
163-
_userServices = ServiceRegistry(
164-
control: userServicesControl,
153+
var servicesControl = widget.control.child("_services");
154+
if (servicesControl != null) {
155+
var uid = servicesControl.internals?["uid"];
156+
if (_services == null || _servicesUid != uid) {
157+
_services?.dispose();
158+
_services = ServiceRegistry(
159+
control: servicesControl,
165160
propertyName: "_services",
166161
backend: backend);
167-
_userServicesUid = uid;
162+
_servicesUid = uid;
168163
}
169-
} else if (_userServices != null) {
170-
_userServices?.dispose();
171-
_userServices = null;
172-
_userServicesUid = null;
164+
} else if (_services != null) {
165+
_services?.dispose();
166+
_services = null;
167+
_servicesUid = null;
173168
}
174169

175170
var windowControl = widget.control.child("window", visibleOnly: false);

packages/flet/lib/src/transport/flet_backend_channel_mock.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ class FletMockBackendChannel implements FletBackendChannel {
5050
{"_c": "Text", "_i": 20, "text": "OFF1"}
5151
]
5252
},
53-
"_user_services": {"_c": "ServiceRegistry", "_i": 10, "services": []},
54-
"_page_services": {"_c": "ServiceRegistry", "_i": 11, "services": []},
53+
"_services": {"_c": "ServiceRegistry", "_i": 10, "services": []},
5554
"views": [
5655
{
5756
"_c": "View",

sdk/python/packages/flet/src/flet/controls/page.py

Lines changed: 89 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -193,45 +193,6 @@ class Page(BasePage):
193193
The list of multi-views associated with this page.
194194
"""
195195

196-
browser_context_menu: BrowserContextMenu = field(
197-
default_factory=lambda: BrowserContextMenu(), metadata={"skip": True}
198-
)
199-
"""
200-
Used to enable or disable the context menu that appears when the user
201-
right-clicks on the web page.
202-
203-
Limitation:
204-
Web only.
205-
"""
206-
207-
shared_preferences: SharedPreferences = field(
208-
default_factory=lambda: SharedPreferences(), metadata={"skip": True}
209-
)
210-
"""
211-
Provides a persistent key-value storage for simple data types.
212-
"""
213-
214-
clipboard: Clipboard = field(
215-
default_factory=lambda: Clipboard(), metadata={"skip": True}
216-
)
217-
"""
218-
Provides access to the system clipboard.
219-
"""
220-
221-
storage_paths: StoragePaths = field(
222-
default_factory=lambda: StoragePaths(), metadata={"skip": True}
223-
)
224-
"""
225-
Provides the information about common storage paths.
226-
"""
227-
228-
url_launcher: UrlLauncher = field(
229-
default_factory=lambda: UrlLauncher(), metadata={"skip": True}
230-
)
231-
"""
232-
Provides methods for launching URLs.
233-
"""
234-
235196
window: Window = field(default_factory=lambda: Window())
236197
"""
237198
Provides properties/methods/events to monitor and control the
@@ -424,8 +385,7 @@ class Page(BasePage):
424385
"""
425386
TBD
426387
"""
427-
_services: list[Service] = field(default_factory=list)
428-
_user_services: ServiceRegistry = field(default_factory=lambda: ServiceRegistry())
388+
_services: ServiceRegistry = field(default_factory=lambda: ServiceRegistry())
429389

430390
def __post_init__(
431391
self,
@@ -437,13 +397,6 @@ def __post_init__(
437397
self.__session = weakref.ref(sess)
438398

439399
# page services
440-
self._services = [
441-
self.browser_context_menu,
442-
self.shared_preferences,
443-
self.clipboard,
444-
self.url_launcher,
445-
self.storage_paths,
446-
]
447400
self.__last_route = None
448401
self.__query: QueryString = QueryString(self)
449402
self.__authorization: Optional[Authorization] = None
@@ -583,7 +536,12 @@ def run_thread(
583536
partial(handler_with_context, *args, **kwargs),
584537
)
585538

586-
@deprecated("Use push_route() instead.", version="0.70.0", show_parentheses=True)
539+
@deprecated(
540+
"Use push_route() instead.",
541+
version="0.70.0",
542+
delete_version="0.90.0",
543+
show_parentheses=True,
544+
)
587545
def go(
588546
self, route: str, skip_route_change_event: bool = False, **kwargs: Any
589547
) -> None:
@@ -731,9 +689,12 @@ async def login(
731689
if on_open_authorization_url:
732690
await on_open_authorization_url(authorization_url)
733691
else:
734-
await self.launch_url(
735-
authorization_url, "flet_oauth_signin", web_popup_window=self.web
736-
)
692+
if self.web:
693+
await UrlLauncher().open_window(
694+
authorization_url, title="flet_oauth_signin"
695+
)
696+
else:
697+
await UrlLauncher().launch_url(authorization_url)
737698
else:
738699
await self.__authorization.dehydrate_token(saved_token)
739700

@@ -793,6 +754,11 @@ def logout(self) -> None:
793754
elif callable(self.on_logout):
794755
self.on_logout(e)
795756

757+
@deprecated(
758+
"Use UrlLauncher().launch_url() instead.",
759+
version="0.90.0",
760+
show_parentheses=True,
761+
)
796762
async def launch_url(
797763
self,
798764
url: Union[str, Url],
@@ -816,14 +782,21 @@ async def launch_url(
816782
web_popup_window_width: Popup window width.
817783
web_popup_window_height: Popup window height.
818784
"""
819-
await self.url_launcher.launch_url(
820-
url,
821-
web_popup_window_name=web_popup_window_name,
822-
web_popup_window=web_popup_window,
823-
web_popup_window_width=web_popup_window_width,
824-
web_popup_window_height=web_popup_window_height,
825-
)
785+
if web_popup_window:
786+
await UrlLauncher().open_window(
787+
url,
788+
title=web_popup_window_name,
789+
width=web_popup_window_width,
790+
height=web_popup_window_height,
791+
)
792+
else:
793+
await UrlLauncher().launch_url(url)
826794

795+
@deprecated(
796+
"Use UrlLauncher().can_launch_url() instead.",
797+
version="0.90.0",
798+
show_parentheses=True,
799+
)
827800
async def can_launch_url(self, url: str) -> bool:
828801
"""
829802
Checks whether the specified URL can be handled by some app
@@ -844,15 +817,20 @@ async def can_launch_url(self, url: str) -> bool:
844817
schemes that are always assumed to be supported (such as http(s)),
845818
as web pages are never allowed to query installed applications.
846819
"""
847-
return await self.url_launcher.can_launch_url(url)
820+
return await UrlLauncher().can_launch_url(url)
848821

822+
@deprecated(
823+
"Use UrlLauncher().close_in_app_web_view() instead.",
824+
version="0.90.0",
825+
show_parentheses=True,
826+
)
849827
async def close_in_app_web_view(self) -> None:
850828
"""
851829
Closes in-app web view opened with `launch_url()`.
852830
853831
📱 Mobile only.
854832
"""
855-
await self.url_launcher.close_in_app_web_view()
833+
await UrlLauncher().close_in_app_web_view()
856834

857835
@property
858836
def session(self) -> "Session":
@@ -912,6 +890,56 @@ def pubsub(self) -> "PubSubClient":
912890
"""
913891
return self.session.pubsub_client
914892

893+
@property
894+
@deprecated("Use UrlLauncher() instead.", version="0.70.0", delete_version="0.90.0")
895+
def url_launcher(self) -> UrlLauncher:
896+
"""
897+
DEPRECATED: The UrlLauncher service for the current page.
898+
"""
899+
return UrlLauncher()
900+
901+
@property
902+
@deprecated(
903+
"Use BrowserContextMenu() instead.", version="0.70.0", delete_version="0.90.0"
904+
)
905+
def browser_context_menu(self):
906+
"""
907+
DEPRECATED: The BrowserContextMenu service for the current page.
908+
"""
909+
910+
return BrowserContextMenu()
911+
912+
@property
913+
@deprecated(
914+
"Use SharedPreferences() instead.", version="0.70.0", delete_version="0.90.0"
915+
)
916+
def shared_preferences(self):
917+
"""
918+
DEPRECATED: The SharedPreferences service for the current page.
919+
"""
920+
921+
return SharedPreferences()
922+
923+
@property
924+
@deprecated("Use Clipboard() instead.", version="0.70.0", delete_version="0.90.0")
925+
def clipboard(self):
926+
"""
927+
DEPRECATED: The Clipboard service for the current page.
928+
"""
929+
930+
return Clipboard()
931+
932+
@property
933+
@deprecated(
934+
"Use StoragePaths() instead.", version="0.70.0", delete_version="0.90.0"
935+
)
936+
def storage_paths(self):
937+
"""
938+
DEPRECATED: The StoragePaths service for the current page.
939+
"""
940+
941+
return StoragePaths()
942+
915943
async def get_device_info(self) -> Optional[DeviceInfo]:
916944
"""
917945
Returns device information.

sdk/python/packages/flet/src/flet/controls/services/service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ class Service(BaseControl):
1616
def init(self):
1717
super().init()
1818
with contextlib.suppress(RuntimeError):
19-
context.page._user_services.register_service(self)
19+
context.page._services.register_service(self)

sdk/python/packages/flet/src/flet/messaging/session.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ async def after_event(self, control: BaseControl | None):
258258
await self.__auto_update(control)
259259

260260
# unregister unreferenced services
261-
self.page._user_services.unregister_services()
261+
self.page._services.unregister_services()
262262

263263
async def __auto_update(self, control: BaseControl | None):
264264
while control:

sdk/python/packages/flet/tests/test_object_diff_in_place.py

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,19 @@ def test_simple_page():
113113
page.bgcolor = Colors.GREEN
114114
page.fonts = {"font1": "font_url_1", "font2": "font_url_2"}
115115
page.on_login = lambda e: print("on login")
116-
page._user_services._services.append(MyService(prop_1="Hello", prop_2=[1, 2, 3]))
116+
page._services._services.append(MyService(prop_1="Hello", prop_2=[1, 2, 3]))
117117

118118
# page and window have hard-coded IDs
119119
assert page._i == 1
120120
assert page.window and page.window._i == 2
121121

122122
msg, _, _, added_controls, removed_controls = make_msg(page, {}, show_details=True)
123123
u_msg = b_unpack(msg)
124-
assert len(added_controls) == 13
124+
assert len(added_controls) == 8
125125
assert len(removed_controls) == 0
126126

127127
assert page.parent is None
128128
assert page.controls[0].parent == page.views[0]
129-
assert page.clipboard
130-
assert page.clipboard.parent
131-
assert page.clipboard.page
132129

133130
print(u_msg)
134131

@@ -184,17 +181,6 @@ def test_simple_page():
184181
# }
185182
# ],
186183
# },
187-
# "_page_services": {
188-
# "_i": 27,
189-
# "_c": "ServiceRegistry",
190-
# "services": [
191-
# {"_i": 21, "_c": "BrowserContextMenu"},
192-
# {"_i": 22, "_c": "SharedPreferences"},
193-
# {"_i": 23, "_c": "Clipboard"},
194-
# {"_i": 25, "_c": "UrlLauncher"},
195-
# {"_i": 24, "_c": "StoragePaths"},
196-
# ],
197-
# },
198184
# "fonts": {"font1": "font_url_1", "font2": "font_url_2"},
199185
# "on_login": True,
200186
# },
@@ -218,7 +204,7 @@ def test_simple_page():
218204
with raises(RuntimeError):
219205
assert page.controls[0].controls[0].page is None
220206

221-
page._user_services._services[0].prop_2 = [2, 6]
207+
page._services._services[0].prop_2 = [2, 6]
222208

223209
# add 2 new buttons to a list
224210
_, patch, _, added_controls, removed_controls = make_msg(page, show_details=True)
@@ -243,17 +229,17 @@ def test_simple_page():
243229
{"op": "remove", "path": ["fonts", "font2"], "value": "font_url_2"},
244230
{
245231
"op": "remove",
246-
"path": ["_user_services", "_services", 0, "prop_2", 0],
232+
"path": ["_services", "_services", 0, "prop_2", 0],
247233
"value": 1,
248234
},
249235
{
250236
"op": "add",
251-
"path": ["_user_services", "_services", 0, "prop_2", 1],
237+
"path": ["_services", "_services", 0, "prop_2", 1],
252238
"value": 6,
253239
},
254240
{
255241
"op": "remove",
256-
"path": ["_user_services", "_services", 0, "prop_2", 2],
242+
"path": ["_services", "_services", 0, "prop_2", 2],
257243
"value": 3,
258244
},
259245
],

0 commit comments

Comments
 (0)