Skip to content

Commit d1aeabb

Browse files
User control (#26)
* UserControl draft * Do not reference UserControl * UserControl complete * Go 1.18.3 * An ability to choose Flutter web renderer * page.set_clipboard(), page.show_snack_bar()
1 parent 0f77a92 commit d1aeabb

File tree

10 files changed

+94
-21
lines changed

10 files changed

+94
-21
lines changed

.appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ skip_commits:
99
- "*.md"
1010

1111
environment:
12-
GO_VERSION: 1.18.1
12+
GO_VERSION: 1.18.3
1313
GO_TAGS: --tags release
1414
python_version: 3.10
1515
GITHUB_TOKEN:

client/web/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
<title>Flet</title>
2020
<link rel="manifest" href="manifest.json">
2121

22+
<!-- flutterWebRenderer -->
23+
2224
<script>
2325
// The value below is injected by flutter build, do not touch.
2426
var serviceWorkerVersion = null;

sdk/python/flet/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@
4040
from flet.text_button import TextButton
4141
from flet.textfield import TextField
4242
from flet.theme import Theme
43+
from flet.user_control import UserControl
4344
from flet.vertical_divider import VerticalDivider

sdk/python/flet/clipboard.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ def __init__(
3636
def _get_control_name(self):
3737
return "clipboard"
3838

39+
def _is_isolated(self):
40+
return True
41+
3942
# value
4043
@property
4144
def value(self):

sdk/python/flet/control.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,14 @@ def __init__(
8686
if ref:
8787
ref.current = self
8888

89-
def _assign(self, variable):
90-
variable = self
89+
def _is_isolated(self):
90+
return False
91+
92+
def did_mount(self):
93+
pass
94+
95+
def will_unmount(self):
96+
pass
9197

9298
def _get_children(self):
9399
return []
@@ -306,7 +312,8 @@ def build_update_commands(self, index, added_controls, commands):
306312
# unchanged control
307313
for h in previous_ints[a1:a2]:
308314
ctrl = hashes[h]
309-
ctrl.build_update_commands(index, added_controls, commands)
315+
if not ctrl._is_isolated():
316+
ctrl.build_update_commands(index, added_controls, commands)
310317
n += 1
311318
elif tag == "replace":
312319
ids = []
@@ -358,6 +365,7 @@ def _remove_control_recursively(self, index, control):
358365
self._remove_control_recursively(index, child)
359366

360367
if control.__uid in index:
368+
control.will_unmount()
361369
del index[control.__uid]
362370

363371
# private methods

sdk/python/flet/flet.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,24 @@
3535
FLET_APP,
3636
]
3737

38+
WebRenderer = Literal[None, "auto", "html", "canvaskit"]
39+
3840

3941
def page(
40-
name="", port=0, permissions=None, view: AppViewer = WEB_BROWSER, assets_dir=None
42+
name="",
43+
port=0,
44+
permissions=None,
45+
view: AppViewer = WEB_BROWSER,
46+
assets_dir=None,
47+
web_renderer=None,
4148
):
4249
conn = _connect_internal(
4350
page_name=name,
4451
port=port,
4552
is_app=False,
4653
permissions=permissions,
4754
assets_dir=assets_dir,
55+
web_renderer=web_renderer,
4856
)
4957
print("Page URL:", conn.page_url)
5058
page = Page(conn, constants.ZERO_SESSION)
@@ -63,6 +71,7 @@ def app(
6371
permissions=None,
6472
view: AppViewer = FLET_APP,
6573
assets_dir=None,
74+
web_renderer=None,
6675
):
6776

6877
if target == None:
@@ -75,6 +84,7 @@ def app(
7584
permissions=permissions,
7685
session_handler=target,
7786
assets_dir=assets_dir,
87+
web_renderer=web_renderer,
7888
)
7989
print("App URL:", conn.page_url)
8090

@@ -129,6 +139,7 @@ def _connect_internal(
129139
permissions=None,
130140
session_handler=None,
131141
assets_dir=None,
142+
web_renderer=None,
132143
):
133144
if share and server == None:
134145
server = constants.HOSTED_SERVICE_URL
@@ -141,7 +152,7 @@ def _connect_internal(
141152
# page with a custom port starts detached process
142153
attached = False if not is_app and port != 0 else True
143154

144-
port = _start_flet_server(port, attached, assets_dir)
155+
port = _start_flet_server(port, attached, assets_dir, web_renderer)
145156
server = f"http://localhost:{port}"
146157

147158
connected = threading.Event()
@@ -209,7 +220,7 @@ def _on_ws_failed_connect():
209220
return conn
210221

211222

212-
def _start_flet_server(port, attached, assets_dir):
223+
def _start_flet_server(port, attached, assets_dir, web_renderer):
213224

214225
if port == 0:
215226
port = _get_free_tcp_port()
@@ -243,6 +254,10 @@ def _start_flet_server(port, attached, assets_dir):
243254
logging.info(f"Assets path configured: {assets_dir}")
244255
fletd_env["FLET_STATIC_ROOT_DIR"] = assets_dir
245256

257+
if web_renderer not in [None, "", "auto"]:
258+
logging.info(f"Web renderer configured: {web_renderer}")
259+
fletd_env["FLET_WEB_RENDERER"] = web_renderer
260+
246261
args = [fletd_path, "--port", str(port)]
247262

248263
creationflags = 0

sdk/python/flet/page.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ def __update(self, *controls):
117117

118118
# add to index
119119
self._index[id] = added_controls[n]
120+
121+
# call Control.did_mount
122+
added_controls[n].did_mount()
123+
120124
n += 1
121125

122126
def add(self, *controls):
@@ -219,6 +223,16 @@ def _send_command(self, name: str, values: List[str]):
219223
Command(0, name, values, None, None),
220224
)
221225

226+
@beartype
227+
def set_clipboard(self, value: str):
228+
self.__offstage.clipboard.value = value
229+
self.__offstage.clipboard.update()
230+
231+
@beartype
232+
def show_snack_bar(self, snack_bar: SnackBar):
233+
self.__offstage.snack_bar = snack_bar
234+
self.__offstage.update()
235+
222236
# url
223237
@property
224238
def url(self):
@@ -341,16 +355,6 @@ def fonts(self, value: Optional[Dict[str, str]]):
341355
self.__fonts = value
342356
self._set_attr_json("fonts", value)
343357

344-
# clipboard
345-
@property
346-
def clipboard(self):
347-
return self.__offstage.clipboard.value
348-
349-
@clipboard.setter
350-
@beartype
351-
def clipboard(self, value: Optional[str]):
352-
self.__offstage.clipboard.value = value
353-
354358
# splash
355359
@property
356360
def splash(self):

sdk/python/flet/user_control.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import List
2+
3+
from flet.control import Control
4+
from flet.stack import Stack
5+
6+
7+
class UserControl(Stack):
8+
def __init__(self):
9+
super().__init__()
10+
content = self.build()
11+
if isinstance(content, Control):
12+
self.controls = [content]
13+
elif isinstance(content, List) and all(
14+
isinstance(control, Control) for control in content
15+
):
16+
self.controls = content
17+
else:
18+
raise Exception(
19+
f"{self.__class__.__name__}.build() method must be implemented and returning either Control or List[Control]."
20+
)
21+
22+
def build(self):
23+
pass
24+
25+
def _is_isolated(self):
26+
return True

server/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ const (
7171

7272
// development
7373
staticRootDir = "STATIC_ROOT_DIR"
74+
webRenderer = "WEB_RENDERER"
7475
)
7576

7677
func init() {
@@ -278,3 +279,7 @@ func MasterSecretKey() string {
278279
func StaticRootDir() string {
279280
return viper.GetString(staticRootDir)
280281
}
282+
283+
func WebRenderer() string {
284+
return viper.GetString(webRenderer)
285+
}

server/server/server.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,19 @@ func Start(ctx context.Context, wg *sync.WaitGroup, serverPort int) {
105105
index, _ := assetsFS.Open(siteDefaultDocument)
106106
indexData, _ := ioutil.ReadAll(index)
107107

108-
c.Data(http.StatusOK, "text/html",
109-
bytes.Replace(indexData,
110-
[]byte("<base href=\"/\">"),
111-
[]byte("<base href=\""+urlPath+"\">"), 1))
108+
// base path
109+
indexData = bytes.Replace(indexData,
110+
[]byte("<base href=\"/\">"),
111+
[]byte("<base href=\""+urlPath+"\">"), 1)
112+
113+
// web renderer
114+
if config.WebRenderer() != "" {
115+
indexData = bytes.Replace(indexData,
116+
[]byte("<!-- flutterWebRenderer -->"),
117+
[]byte("<script>window.flutterWebRenderer=\""+config.WebRenderer()+"\";</script>"), 1)
118+
}
119+
120+
c.Data(http.StatusOK, "text/html", indexData)
112121
} else {
113122
// API not found
114123
c.JSON(http.StatusNotFound, gin.H{

0 commit comments

Comments
 (0)