Skip to content

Commit 9f97fdd

Browse files
flet build command to package Flet app for any platform (#2271)
* Added `flet build` command prototype * Bump `http` dependency * Add `platform`, `python_app_path` and `--output_dir` to flet build command * flet build - 1st prototype * Build options per platform * configurable output folder * Copy assets * Generate app icons and splashes * Generate python package * build find-links, install micropip * Disable splash for specific platform * --base-url, --web-renderer, --use-color-emoji, --route-url-strategy args * Update logo-inkscape.svg * Fix shake detector dependency Close #2257 * Copy build directory and exclude it from a build * More options, detect arch, copy build output * Fix running flutter and dart on Windows * Generate splash screen for selected platforms only * Display output dir * Added --team and --flutter-build-args arguments * build number/version and template args * Copy "assets" to web root * Renamed platform to package * Take stem of module_name * package -> target_platform * Simplified logic for Text.style and Text.theme_style * Fix test: Text.style should support both enum and string
1 parent 6c4e475 commit 9f97fdd

File tree

8 files changed

+927
-83
lines changed

8 files changed

+927
-83
lines changed

client/pubspec.lock

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,14 @@ packages:
318318
url: "https://pub.dev"
319319
source: hosted
320320
version: "1.0.1"
321+
logging:
322+
dependency: transitive
323+
description:
324+
name: logging
325+
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
326+
url: "https://pub.dev"
327+
source: hosted
328+
version: "1.2.0"
321329
markdown:
322330
dependency: transitive
323331
description:
@@ -474,34 +482,18 @@ packages:
474482
dependency: transitive
475483
description:
476484
name: sensors_plus
477-
sha256: "362c8f4f001838b90dd5206b898bbad941bc0142479eab9a3415f0f79e622908"
485+
sha256: "8e7fa79b4940442bb595bfc0ee9da4af5a22a0fe6ebacc74998245ee9496a82d"
478486
url: "https://pub.dev"
479487
source: hosted
480-
version: "1.4.1"
488+
version: "4.0.2"
481489
sensors_plus_platform_interface:
482490
dependency: transitive
483491
description:
484492
name: sensors_plus_platform_interface
485-
sha256: "95f0cc08791b8bf0c41c5fa99c84be2a7d5bf60a811ddc17e1438b1e68caf0d3"
493+
sha256: bc472d6cfd622acb4f020e726433ee31788b038056691ba433fec80e448a094f
486494
url: "https://pub.dev"
487495
source: hosted
488-
version: "1.1.3"
489-
sensors_plus_web:
490-
dependency: transitive
491-
description:
492-
name: sensors_plus_web
493-
sha256: fca8d7d9ab6233b2a059952666415508e252420be1ef54f092d07884da53ec5e
494-
url: "https://pub.dev"
495-
source: hosted
496-
version: "1.1.2"
497-
shake:
498-
dependency: transitive
499-
description:
500-
name: shake
501-
sha256: "107546951c6b8f5e4c2dca66dfb3aa27dd1a853b4e9a26c9aea224b167045023"
502-
url: "https://pub.dev"
503-
source: hosted
504-
version: "2.2.0"
496+
version: "1.2.0"
505497
shared_preferences:
506498
dependency: transitive
507499
description:

media/logo/logo-inkscape.svg

Lines changed: 75 additions & 1 deletion
Loading

package/lib/src/controls/shake_detector.dart

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import 'dart:async';
2+
import 'dart:math';
3+
14
import 'package:flutter/widgets.dart';
2-
import 'package:shake/shake.dart';
5+
import 'package:sensors_plus/sensors_plus.dart';
36

47
import '../flet_app_services.dart';
58
import '../models/control.dart';
@@ -70,3 +73,120 @@ class _ShakeDetectorControlState extends State<ShakeDetectorControl> {
7073
return widget.nextChild ?? const SizedBox.shrink();
7174
}
7275
}
76+
77+
/*
78+
Source: https://github.com/dieringe/shake/blob/master/lib/shake.dart
79+
80+
Copyright 2019 Deven Joshi
81+
82+
Redistribution and use in source and binary forms, with or without modification,
83+
are permitted provided that the following conditions are met:
84+
85+
1. Redistributions of source code must retain the above copyright notice, this
86+
list of conditions and the following disclaimer.
87+
88+
2. Redistributions in binary form must reproduce the above copyright notice,
89+
this list of conditions and the following disclaimer in the documentation
90+
and/or other materials provided with the distribution.
91+
92+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
93+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
94+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
95+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
96+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
97+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
98+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
99+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
100+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
101+
OF THE POSSIBILITY OF SUCH DAMAGE.
102+
*/
103+
104+
/// Callback for phone shakes
105+
typedef PhoneShakeCallback = void Function();
106+
107+
/// ShakeDetector class for phone shake functionality
108+
class ShakeDetector {
109+
/// User callback for phone shake
110+
final PhoneShakeCallback onPhoneShake;
111+
112+
/// Shake detection threshold
113+
final double shakeThresholdGravity;
114+
115+
/// Minimum time between shake
116+
final int shakeSlopTimeMS;
117+
118+
/// Time before shake count resets
119+
final int shakeCountResetTime;
120+
121+
/// Number of shakes required before shake is triggered
122+
final int minimumShakeCount;
123+
124+
int mShakeTimestamp = DateTime.now().millisecondsSinceEpoch;
125+
int mShakeCount = 0;
126+
127+
/// StreamSubscription for Accelerometer events
128+
StreamSubscription? streamSubscription;
129+
130+
/// This constructor waits until [startListening] is called
131+
ShakeDetector.waitForStart({
132+
required this.onPhoneShake,
133+
this.shakeThresholdGravity = 2.7,
134+
this.shakeSlopTimeMS = 500,
135+
this.shakeCountResetTime = 3000,
136+
this.minimumShakeCount = 1,
137+
});
138+
139+
/// This constructor automatically calls [startListening] and starts detection and callbacks.
140+
ShakeDetector.autoStart({
141+
required this.onPhoneShake,
142+
this.shakeThresholdGravity = 2.7,
143+
this.shakeSlopTimeMS = 500,
144+
this.shakeCountResetTime = 3000,
145+
this.minimumShakeCount = 1,
146+
}) {
147+
startListening();
148+
}
149+
150+
/// Starts listening to accelerometer events
151+
void startListening() {
152+
streamSubscription = accelerometerEvents.listen(
153+
(AccelerometerEvent event) {
154+
double x = event.x;
155+
double y = event.y;
156+
double z = event.z;
157+
158+
double gX = x / 9.80665;
159+
double gY = y / 9.80665;
160+
double gZ = z / 9.80665;
161+
162+
// gForce will be close to 1 when there is no movement.
163+
double gForce = sqrt(gX * gX + gY * gY + gZ * gZ);
164+
165+
if (gForce > shakeThresholdGravity) {
166+
var now = DateTime.now().millisecondsSinceEpoch;
167+
// ignore shake events too close to each other (500ms)
168+
if (mShakeTimestamp + shakeSlopTimeMS > now) {
169+
return;
170+
}
171+
172+
// reset the shake count after 3 seconds of no shakes
173+
if (mShakeTimestamp + shakeCountResetTime < now) {
174+
mShakeCount = 0;
175+
}
176+
177+
mShakeTimestamp = now;
178+
mShakeCount++;
179+
180+
if (mShakeCount >= minimumShakeCount) {
181+
onPhoneShake();
182+
}
183+
}
184+
},
185+
);
186+
}
187+
188+
/// Stops listening to accelerometer events
189+
void stopListening() {
190+
streamSubscription?.cancel();
191+
}
192+
}

package/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ dependencies:
3737
flutter_svg: ^2.0.9
3838
window_to_front: ^0.0.3
3939
audioplayers: ^5.2.1
40-
shake: ^2.2.0
40+
sensors_plus: ^4.0.2
4141
path: ^1.8.2
4242
js: ^0.6.5
4343
fl_chart: ^0.65.0

sdk/python/packages/flet-core/src/flet_core/text.py

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,6 @@ class TextOverflow(Enum):
3535
VISIBLE = "visible"
3636

3737

38-
TextThemeStyleString = Literal[
39-
"displayLarge",
40-
"displayMedium",
41-
"displaySmall",
42-
"headlineLarge",
43-
"headlineMedium",
44-
"headlineSmall",
45-
"titleLarge",
46-
"titleMedium",
47-
"titleSmall",
48-
"labelLarge",
49-
"labelMedium",
50-
"labelSmall",
51-
"bodyLarge",
52-
"bodyMedium",
53-
"bodySmall",
54-
]
55-
56-
5738
class TextThemeStyle(Enum):
5839
DISPLAY_LARGE = "displayLarge"
5940
DISPLAY_MEDIUM = "displayMedium"
@@ -203,7 +184,7 @@ def _get_children(self):
203184
children = []
204185
children.extend(self.__spans)
205186
return children
206-
187+
207188
def _before_build_command(self):
208189
super()._before_build_command()
209190
if dataclasses.is_dataclass(self.__style):
@@ -279,35 +260,25 @@ def __set_weight(self, value: FontWeightString):
279260

280261
# style
281262
@property
282-
def style(self) -> Optional[Union[TextThemeStyle, TextStyle, TextThemeStyleString]]:
263+
def style(self) -> Optional[Union[TextThemeStyle, TextStyle]]:
283264
return self.__style
284265

285266
@style.setter
286-
def style(self, value: Optional[Union[TextThemeStyle, TextStyle, TextThemeStyleString]]):
267+
def style(self, value: Optional[Union[TextThemeStyle, TextStyle]]):
287268
self.__style = value
288-
if isinstance(value, TextThemeStyle):
289-
self._set_attr("style", value.value)
290-
else:
291-
self.__set_style(value)
292-
293-
def __set_style(self, value: Optional[Union[TextStyle, TextThemeStyleString]]):
294-
self._set_attr("style", value)
269+
if isinstance(value, (TextThemeStyle, str)) or value is None:
270+
self._set_attr(
271+
"style", value.value if isinstance(value, TextThemeStyle) else value
272+
)
295273

296274
# theme_style
297275
@property
298-
def theme_style(self) -> Optional[Union[TextThemeStyle, TextThemeStyleString]]:
299-
return self.__theme_style
276+
def theme_style(self):
277+
return self._get_attr("theme_style")
300278

301279
@theme_style.setter
302-
def theme_style(self, value: Optional[Union[TextThemeStyle, TextThemeStyleString]]):
303-
self.__theme_style = value
304-
if isinstance(value, TextThemeStyle):
305-
self._set_attr("theme_style", value.value)
306-
else:
307-
self.__set_theme_style(value)
308-
309-
def __set_theme_style(self, value: Optional[TextThemeStyleString]):
310-
self._set_attr("theme_style", value)
280+
def theme_style(self, value: Optional[TextThemeStyle]):
281+
self._set_attr("theme_style", value.value if value is not None else None)
311282

312283
# italic
313284
@property

sdk/python/packages/flet-runtime/src/flet_runtime/utils.py

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -261,23 +261,5 @@ def patch_manifest_json(
261261
f.write(json.dumps(manifest, indent=2))
262262

263263

264-
def copy_tree(src, dst):
265-
"""Recursively copy a directory tree using shutil.copy2().
266-
267-
Arguments:
268-
src -- source directory path
269-
dst -- destination directory path
270-
271-
Return a list of files that were copied or might have been copied.
272-
"""
273-
if not os.path.isdir(src):
274-
raise OSError("Source is not a directory")
275-
276-
os.makedirs(dst, exist_ok=True)
277-
for item in os.listdir(src):
278-
s = os.path.join(src, item)
279-
d = os.path.join(dst, item)
280-
if os.path.isdir(s):
281-
copy_tree(s, d)
282-
else:
283-
shutil.copy2(s, d)
264+
def copy_tree(src, dst, ignore=None):
265+
return shutil.copytree(src, dst, ignore=ignore, symlinks=True, dirs_exist_ok=True)

0 commit comments

Comments
 (0)