Showing
8 changed files
with
38 additions
and
74 deletions
@@ -18,7 +18,7 @@ DART_BIN=$(FLUTTER)/bin/dart | @@ -18,7 +18,7 @@ DART_BIN=$(FLUTTER)/bin/dart | ||
18 | DART_SRC=$(shell find . -name '*.dart') | 18 | DART_SRC=$(shell find . -name '*.dart') |
19 | CLNG_SRC=$(shell find printing/ios printing/macos printing/windows printing/linux printing/android -name '*.cpp' -o -name '*.cc' -o -name '*.m' -o -name '*.h' -o -name '*.java') | 19 | CLNG_SRC=$(shell find printing/ios printing/macos printing/windows printing/linux printing/android -name '*.cpp' -o -name '*.cc' -o -name '*.m' -o -name '*.h' -o -name '*.java') |
20 | SWFT_SRC=$(shell find printing/ios printing/macos -name '*.swift') | 20 | SWFT_SRC=$(shell find printing/ios printing/macos -name '*.swift') |
21 | -FONTS=pdf/open-sans.ttf pdf/open-sans-bold.ttf pdf/roboto.ttf pdf/noto-sans.ttf pdf/genyomintw.ttf demo/assets/roboto1.ttf demo/assets/roboto2.ttf demo/assets/roboto3.ttf demo/assets/open-sans.ttf demo/assets/open-sans-bold.ttf pdf/hacen-tunisia.ttf pdf/material.ttf demo/assets/material.ttf | 21 | +FONTS=pdf/open-sans.ttf pdf/open-sans-bold.ttf pdf/roboto.ttf pdf/noto-sans.ttf pdf/genyomintw.ttf pdf/hacen-tunisia.ttf pdf/material.ttf |
22 | COV_PORT=9292 | 22 | COV_PORT=9292 |
23 | SVG=blend_and_mask blend_mode_devil clip_path clip_path_2 clip_path_2 clip_path_3 clip_path_3 dash_path ellipse empty_defs equation fill-rule-inherit group_composite_opacity group_fill_opacity group_mask group_opacity group_opacity_transform hidden href-fill image image_def implicit_fill_with_opacity linear_gradient linear_gradient_2 linear_gradient_absolute_user_space_translate linear_gradient_percentage_bounding_translate linear_gradient_percentage_user_space_translate linear_gradient_xlink male mask mask_with_gradient mask_with_use mask_with_use2 nested_group opacity_on_path radial_gradient radial_gradient_absolute_user_space_translate radial_gradient_focal radial_gradient_percentage_bounding_translate radial_gradient_percentage_user_space_translate radial_gradient_xlink radial_ref_linear_gradient rect_rrect rect_rrect_no_ry stroke_inherit_circles style_attr text text_2 text_3 use_circles use_circles_def use_emc2 use_fill use_opacity_grid width_height_viewbox flutter_logo emoji_u1f600 text_transform dart new-pause-button new-send-circle new-gif new-camera new-image numeric_25 new-mention new-gif-button new-action-expander new-play-button aa alphachannel Ghostscript_Tiger Firefox_Logo_2017 chess_knight Flag_of_the_United_States | 23 | SVG=blend_and_mask blend_mode_devil clip_path clip_path_2 clip_path_2 clip_path_3 clip_path_3 dash_path ellipse empty_defs equation fill-rule-inherit group_composite_opacity group_fill_opacity group_mask group_opacity group_opacity_transform hidden href-fill image image_def implicit_fill_with_opacity linear_gradient linear_gradient_2 linear_gradient_absolute_user_space_translate linear_gradient_percentage_bounding_translate linear_gradient_percentage_user_space_translate linear_gradient_xlink male mask mask_with_gradient mask_with_use mask_with_use2 nested_group opacity_on_path radial_gradient radial_gradient_absolute_user_space_translate radial_gradient_focal radial_gradient_percentage_bounding_translate radial_gradient_percentage_user_space_translate radial_gradient_xlink radial_ref_linear_gradient rect_rrect rect_rrect_no_ry stroke_inherit_circles style_attr text text_2 text_3 use_circles use_circles_def use_emc2 use_fill use_opacity_grid width_height_viewbox flutter_logo emoji_u1f600 text_transform dart new-pause-button new-send-circle new-gif new-camera new-image numeric_25 new-mention new-gif-button new-action-expander new-play-button aa alphachannel Ghostscript_Tiger Firefox_Logo_2017 chess_knight Flag_of_the_United_States |
24 | 24 | ||
@@ -27,16 +27,6 @@ all: $(FONTS) demo/assets/logo.svg demo/assets/profile.jpg format printing/examp | @@ -27,16 +27,6 @@ all: $(FONTS) demo/assets/logo.svg demo/assets/profile.jpg format printing/examp | ||
27 | pdf/open-sans.ttf: | 27 | pdf/open-sans.ttf: |
28 | curl -L "https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-U1Ug.ttf" > $@ | 28 | curl -L "https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-U1Ug.ttf" > $@ |
29 | 29 | ||
30 | -demo/assets/open-sans.ttf: pdf/open-sans.ttf | ||
31 | - cp $^ $@ | ||
32 | - | ||
33 | -pdf/open-sans-bold.ttf: | ||
34 | - curl -L "https://fonts.gstatic.com/s/opensans/v17/mem5YaGs126MiZpBA-UN7rg-VQ.ttf" > $@ | ||
35 | - cp $@ demo/assets/ | ||
36 | - | ||
37 | -demo/assets/open-sans-bold.ttf: pdf/open-sans-bold.ttf | ||
38 | - cp $^ $@ | ||
39 | - | ||
40 | pdf/roboto.ttf: | 30 | pdf/roboto.ttf: |
41 | curl -L "https://fonts.gstatic.com/s/robotomono/v7/L0x5DF4xlVMF-BfR8bXMIghM.ttf" > $@ | 31 | curl -L "https://fonts.gstatic.com/s/robotomono/v7/L0x5DF4xlVMF-BfR8bXMIghM.ttf" > $@ |
42 | 32 | ||
@@ -49,21 +39,9 @@ pdf/genyomintw.ttf: | @@ -49,21 +39,9 @@ pdf/genyomintw.ttf: | ||
49 | pdf/material.ttf: | 39 | pdf/material.ttf: |
50 | curl -L "https://github.com/google/material-design-icons/raw/master/font/MaterialIcons-Regular.ttf" > $@ | 40 | curl -L "https://github.com/google/material-design-icons/raw/master/font/MaterialIcons-Regular.ttf" > $@ |
51 | 41 | ||
52 | -demo/assets/roboto1.ttf: | ||
53 | - curl -L "https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5vAw.ttf" > $@ | ||
54 | - | ||
55 | -demo/assets/roboto2.ttf: | ||
56 | - curl -L "https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlvAw.ttf" > $@ | ||
57 | - | ||
58 | -demo/assets/roboto3.ttf: | ||
59 | - curl -L "https://fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1MmgWxP.ttf" > $@ | ||
60 | - | ||
61 | demo/assets/logo.svg: | 42 | demo/assets/logo.svg: |
62 | curl -L "http://pigment.github.io/fake-logos/logos/vector/color/auto-speed.svg" > $@ | 43 | curl -L "http://pigment.github.io/fake-logos/logos/vector/color/auto-speed.svg" > $@ |
63 | 44 | ||
64 | -demo/assets/material.ttf: pdf/material.ttf | ||
65 | - cp $< $@ | ||
66 | - | ||
67 | demo/assets/profile.jpg: | 45 | demo/assets/profile.jpg: |
68 | curl -L "https://www.fakepersongenerator.com/Face/female/female20151024334209870.jpg" > $@ | 46 | curl -L "https://www.fakepersongenerator.com/Face/female/female20151024334209870.jpg" > $@ |
69 | 47 |
@@ -20,6 +20,7 @@ import 'package:flutter/services.dart'; | @@ -20,6 +20,7 @@ import 'package:flutter/services.dart'; | ||
20 | import 'package:intl/intl.dart'; | 20 | import 'package:intl/intl.dart'; |
21 | import 'package:pdf/pdf.dart'; | 21 | import 'package:pdf/pdf.dart'; |
22 | import 'package:pdf/widgets.dart'; | 22 | import 'package:pdf/widgets.dart'; |
23 | +import 'package:printing/printing.dart'; | ||
23 | 24 | ||
24 | import '../data.dart'; | 25 | import '../data.dart'; |
25 | 26 | ||
@@ -197,8 +198,8 @@ Future<Uint8List> generateCalendar( | @@ -197,8 +198,8 @@ Future<Uint8List> generateCalendar( | ||
197 | pageFormat: pageFormat, | 198 | pageFormat: pageFormat, |
198 | orientation: PageOrientation.landscape, | 199 | orientation: PageOrientation.landscape, |
199 | theme: ThemeData.withFont( | 200 | theme: ThemeData.withFont( |
200 | - base: Font.ttf(await rootBundle.load('assets/open-sans.ttf')), | ||
201 | - bold: Font.ttf(await rootBundle.load('assets/open-sans-bold.ttf')), | 201 | + base: await PdfGoogleFonts.openSansRegular(), |
202 | + bold: await PdfGoogleFonts.openSansBold(), | ||
202 | ), | 203 | ), |
203 | buildForeground: bg == null | 204 | buildForeground: bg == null |
204 | ? null | 205 | ? null |
@@ -18,43 +18,22 @@ import 'dart:typed_data'; | @@ -18,43 +18,22 @@ import 'dart:typed_data'; | ||
18 | 18 | ||
19 | import 'package:flutter/material.dart'; | 19 | import 'package:flutter/material.dart'; |
20 | import 'package:flutter/services.dart'; | 20 | import 'package:flutter/services.dart'; |
21 | -import 'package:http/http.dart' as http; | ||
22 | import 'package:pdf/pdf.dart'; | 21 | import 'package:pdf/pdf.dart'; |
23 | import 'package:pdf/widgets.dart' as pw; | 22 | import 'package:pdf/widgets.dart' as pw; |
23 | +import 'package:printing/printing.dart'; | ||
24 | import 'package:vector_math/vector_math_64.dart'; | 24 | import 'package:vector_math/vector_math_64.dart'; |
25 | 25 | ||
26 | import '../data.dart'; | 26 | import '../data.dart'; |
27 | 27 | ||
28 | -final _cache = <String, Uint8List>{}; | ||
29 | - | ||
30 | -Future<Uint8List> _download(String url) async { | ||
31 | - if (!_cache.containsKey(url)) { | ||
32 | - print('Downloading $url'); | ||
33 | - final response = await http.get(Uri.parse(url)); | ||
34 | - final data = response.bodyBytes; | ||
35 | - _cache[url] = Uint8List.fromList(data); | ||
36 | - } | ||
37 | - | ||
38 | - return _cache[url]!; | ||
39 | -} | ||
40 | - | ||
41 | -Future<pw.Font> _downloadFont(String url) async { | ||
42 | - final data = await _download(url); | ||
43 | - return pw.Font.ttf(data.buffer.asByteData()); | ||
44 | -} | ||
45 | - | ||
46 | Future<Uint8List> generateCertificate( | 28 | Future<Uint8List> generateCertificate( |
47 | PdfPageFormat pageFormat, CustomData data) async { | 29 | PdfPageFormat pageFormat, CustomData data) async { |
48 | final lorem = pw.LoremText(); | 30 | final lorem = pw.LoremText(); |
49 | final pdf = pw.Document(); | 31 | final pdf = pw.Document(); |
50 | 32 | ||
51 | - final libreBaskerville = await _downloadFont( | ||
52 | - 'https://fonts.gstatic.com/s/librebaskerville/v9/kmKnZrc3Hgbbcjq75U4uslyuy4kn0pNe.ttf'); | ||
53 | - final libreBaskervilleItalic = await _downloadFont( | ||
54 | - 'https://fonts.gstatic.com/s/librebaskerville/v9/kmKhZrc3Hgbbcjq75U4uslyuy4kn0qNcaxY.ttf'); | ||
55 | - final libreBaskervilleBold = await _downloadFont( | ||
56 | - 'https://fonts.gstatic.com/s/librebaskerville/v9/kmKiZrc3Hgbbcjq75U4uslyuy4kn0qviTjYw.ttf'); | ||
57 | - final robotoLight = pw.Font.ttf(await rootBundle.load('assets/roboto3.ttf')); | 33 | + final libreBaskerville = await PdfGoogleFonts.libreBaskervilleRegular(); |
34 | + final libreBaskervilleItalic = await PdfGoogleFonts.libreBaskervilleItalic(); | ||
35 | + final libreBaskervilleBold = await PdfGoogleFonts.libreBaskervilleBold(); | ||
36 | + final robotoLight = await PdfGoogleFonts.robotoLight(); | ||
58 | final medail = await rootBundle.loadString('assets/medail.svg'); | 37 | final medail = await rootBundle.loadString('assets/medail.svg'); |
59 | final swirls = await rootBundle.loadString('assets/swirls.svg'); | 38 | final swirls = await rootBundle.loadString('assets/swirls.svg'); |
60 | final swirls1 = await rootBundle.loadString('assets/swirls1.svg'); | 39 | final swirls1 = await rootBundle.loadString('assets/swirls1.svg'); |
@@ -19,6 +19,7 @@ import 'dart:typed_data'; | @@ -19,6 +19,7 @@ import 'dart:typed_data'; | ||
19 | import 'package:flutter/services.dart'; | 19 | import 'package:flutter/services.dart'; |
20 | import 'package:pdf/pdf.dart'; | 20 | import 'package:pdf/pdf.dart'; |
21 | import 'package:pdf/widgets.dart' as pw; | 21 | import 'package:pdf/widgets.dart' as pw; |
22 | +import 'package:printing/printing.dart'; | ||
22 | 23 | ||
23 | import '../data.dart'; | 24 | import '../data.dart'; |
24 | 25 | ||
@@ -26,8 +27,8 @@ Future<Uint8List> generateDocument( | @@ -26,8 +27,8 @@ Future<Uint8List> generateDocument( | ||
26 | PdfPageFormat format, CustomData data) async { | 27 | PdfPageFormat format, CustomData data) async { |
27 | final doc = pw.Document(pageMode: PdfPageMode.outlines); | 28 | final doc = pw.Document(pageMode: PdfPageMode.outlines); |
28 | 29 | ||
29 | - final font1 = await rootBundle.load('assets/open-sans.ttf'); | ||
30 | - final font2 = await rootBundle.load('assets/open-sans-bold.ttf'); | 30 | + final font1 = await PdfGoogleFonts.openSansRegular(); |
31 | + final font2 = await PdfGoogleFonts.openSansBold(); | ||
31 | final shape = await rootBundle.loadString('assets/document.svg'); | 32 | final shape = await rootBundle.loadString('assets/document.svg'); |
32 | final swirls = await rootBundle.loadString('assets/swirls2.svg'); | 33 | final swirls = await rootBundle.loadString('assets/swirls2.svg'); |
33 | 34 | ||
@@ -43,6 +44,10 @@ Future<Uint8List> generateDocument( | @@ -43,6 +44,10 @@ Future<Uint8List> generateDocument( | ||
43 | orientation: pw.PageOrientation.portrait, | 44 | orientation: pw.PageOrientation.portrait, |
44 | buildBackground: (context) => | 45 | buildBackground: (context) => |
45 | pw.SvgImage(svg: shape, fit: pw.BoxFit.fill), | 46 | pw.SvgImage(svg: shape, fit: pw.BoxFit.fill), |
47 | + theme: pw.ThemeData.withFont( | ||
48 | + base: font1, | ||
49 | + bold: font2, | ||
50 | + ), | ||
46 | ), | 51 | ), |
47 | build: (context) { | 52 | build: (context) { |
48 | return pw.Padding( | 53 | return pw.Padding( |
@@ -100,6 +105,10 @@ Future<Uint8List> generateDocument( | @@ -100,6 +105,10 @@ Future<Uint8List> generateDocument( | ||
100 | 105 | ||
101 | doc.addPage( | 106 | doc.addPage( |
102 | pw.Page( | 107 | pw.Page( |
108 | + theme: pw.ThemeData.withFont( | ||
109 | + base: font1, | ||
110 | + bold: font2, | ||
111 | + ), | ||
103 | pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), | 112 | pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), |
104 | orientation: pw.PageOrientation.portrait, | 113 | orientation: pw.PageOrientation.portrait, |
105 | build: (context) { | 114 | build: (context) { |
@@ -124,8 +133,8 @@ Future<Uint8List> generateDocument( | @@ -124,8 +133,8 @@ Future<Uint8List> generateDocument( | ||
124 | 133 | ||
125 | doc.addPage(pw.MultiPage( | 134 | doc.addPage(pw.MultiPage( |
126 | theme: pw.ThemeData.withFont( | 135 | theme: pw.ThemeData.withFont( |
127 | - base: pw.Font.ttf(font1), | ||
128 | - bold: pw.Font.ttf(font2), | 136 | + base: font1, |
137 | + bold: font2, | ||
129 | ), | 138 | ), |
130 | pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), | 139 | pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), |
131 | orientation: pw.PageOrientation.portrait, | 140 | orientation: pw.PageOrientation.portrait, |
@@ -20,6 +20,7 @@ import 'package:flutter/services.dart'; | @@ -20,6 +20,7 @@ import 'package:flutter/services.dart'; | ||
20 | import 'package:intl/intl.dart'; | 20 | import 'package:intl/intl.dart'; |
21 | import 'package:pdf/pdf.dart'; | 21 | import 'package:pdf/pdf.dart'; |
22 | import 'package:pdf/widgets.dart' as pw; | 22 | import 'package:pdf/widgets.dart' as pw; |
23 | +import 'package:printing/printing.dart'; | ||
23 | 24 | ||
24 | import '../data.dart'; | 25 | import '../data.dart'; |
25 | 26 | ||
@@ -100,10 +101,6 @@ class Invoice { | @@ -100,10 +101,6 @@ class Invoice { | ||
100 | // Create a PDF document. | 101 | // Create a PDF document. |
101 | final doc = pw.Document(); | 102 | final doc = pw.Document(); |
102 | 103 | ||
103 | - final font1 = await rootBundle.load('assets/roboto1.ttf'); | ||
104 | - final font2 = await rootBundle.load('assets/roboto2.ttf'); | ||
105 | - final font3 = await rootBundle.load('assets/roboto3.ttf'); | ||
106 | - | ||
107 | _logo = await rootBundle.loadString('assets/logo.svg'); | 104 | _logo = await rootBundle.loadString('assets/logo.svg'); |
108 | _bgShape = await rootBundle.loadString('assets/invoice.svg'); | 105 | _bgShape = await rootBundle.loadString('assets/invoice.svg'); |
109 | 106 | ||
@@ -112,9 +109,9 @@ class Invoice { | @@ -112,9 +109,9 @@ class Invoice { | ||
112 | pw.MultiPage( | 109 | pw.MultiPage( |
113 | pageTheme: _buildTheme( | 110 | pageTheme: _buildTheme( |
114 | pageFormat, | 111 | pageFormat, |
115 | - pw.Font.ttf(font1), | ||
116 | - pw.Font.ttf(font2), | ||
117 | - pw.Font.ttf(font3), | 112 | + await PdfGoogleFonts.robotoRegular(), |
113 | + await PdfGoogleFonts.robotoBold(), | ||
114 | + await PdfGoogleFonts.robotoItalic(), | ||
118 | ), | 115 | ), |
119 | header: _buildHeader, | 116 | header: _buildHeader, |
120 | footer: _buildFooter, | 117 | footer: _buildFooter, |
@@ -17,9 +17,9 @@ | @@ -17,9 +17,9 @@ | ||
17 | import 'dart:math'; | 17 | import 'dart:math'; |
18 | import 'dart:typed_data'; | 18 | import 'dart:typed_data'; |
19 | 19 | ||
20 | -import 'package:flutter/services.dart'; | ||
21 | import 'package:pdf/pdf.dart'; | 20 | import 'package:pdf/pdf.dart'; |
22 | import 'package:pdf/widgets.dart' as pw; | 21 | import 'package:pdf/widgets.dart' as pw; |
22 | +import 'package:printing/printing.dart'; | ||
23 | 23 | ||
24 | import '../data.dart'; | 24 | import '../data.dart'; |
25 | 25 | ||
@@ -51,8 +51,8 @@ Future<Uint8List> generateReport( | @@ -51,8 +51,8 @@ Future<Uint8List> generateReport( | ||
51 | final document = pw.Document(); | 51 | final document = pw.Document(); |
52 | 52 | ||
53 | final theme = pw.ThemeData.withFont( | 53 | final theme = pw.ThemeData.withFont( |
54 | - base: pw.Font.ttf(await rootBundle.load('assets/open-sans.ttf')), | ||
55 | - bold: pw.Font.ttf(await rootBundle.load('assets/open-sans-bold.ttf')), | 54 | + base: await PdfGoogleFonts.openSansRegular(), |
55 | + bold: await PdfGoogleFonts.openSansBold(), | ||
56 | ); | 56 | ); |
57 | 57 | ||
58 | // Top bar chart | 58 | // Top bar chart |
@@ -21,6 +21,7 @@ import 'dart:typed_data'; | @@ -21,6 +21,7 @@ import 'dart:typed_data'; | ||
21 | import 'package:flutter/services.dart'; | 21 | import 'package:flutter/services.dart'; |
22 | import 'package:pdf/pdf.dart'; | 22 | import 'package:pdf/pdf.dart'; |
23 | import 'package:pdf/widgets.dart' as pw; | 23 | import 'package:pdf/widgets.dart' as pw; |
24 | +import 'package:printing/printing.dart'; | ||
24 | import 'package:printing_demo/data.dart'; | 25 | import 'package:printing_demo/data.dart'; |
25 | 26 | ||
26 | const PdfColor green = PdfColor.fromInt(0xff9ce5d0); | 27 | const PdfColor green = PdfColor.fromInt(0xff9ce5d0); |
@@ -168,9 +169,9 @@ Future<pw.PageTheme> _myPageTheme(PdfPageFormat format) async { | @@ -168,9 +169,9 @@ Future<pw.PageTheme> _myPageTheme(PdfPageFormat format) async { | ||
168 | return pw.PageTheme( | 169 | return pw.PageTheme( |
169 | pageFormat: format, | 170 | pageFormat: format, |
170 | theme: pw.ThemeData.withFont( | 171 | theme: pw.ThemeData.withFont( |
171 | - base: pw.Font.ttf(await rootBundle.load('assets/open-sans.ttf')), | ||
172 | - bold: pw.Font.ttf(await rootBundle.load('assets/open-sans-bold.ttf')), | ||
173 | - icons: pw.Font.ttf(await rootBundle.load('assets/material.ttf')), | 172 | + base: await PdfGoogleFonts.openSansRegular(), |
173 | + bold: await PdfGoogleFonts.openSansBold(), | ||
174 | + icons: await PdfGoogleFonts.materialIcons(), | ||
174 | ), | 175 | ), |
175 | buildBackground: (pw.Context context) { | 176 | buildBackground: (pw.Context context) { |
176 | return pw.FullPage( | 177 | return pw.FullPage( |
@@ -4,18 +4,17 @@ publish_to: "none" | @@ -4,18 +4,17 @@ publish_to: "none" | ||
4 | version: 1.0.0+1 | 4 | version: 1.0.0+1 |
5 | 5 | ||
6 | environment: | 6 | environment: |
7 | - sdk: ">=2.12.0-0 <3.0.0" | 7 | + sdk: ">=2.12.0 <3.0.0" |
8 | flutter: ">=1.16.0" | 8 | flutter: ">=1.16.0" |
9 | 9 | ||
10 | dependencies: | 10 | dependencies: |
11 | flutter: | 11 | flutter: |
12 | sdk: flutter | 12 | sdk: flutter |
13 | - http: ^0.13.1 | ||
14 | intl: ^0.17.0 | 13 | intl: ^0.17.0 |
15 | - open_file: ^3.1.0 | ||
16 | - path_provider: ^2.0.1 | ||
17 | - printing: ^5.0.4 | ||
18 | - url_launcher: ^6.0.3 | 14 | + open_file: ^3.2.1 |
15 | + path_provider: ^2.0.2 | ||
16 | + printing: ^5.3.0 | ||
17 | + url_launcher: ^6.0.6 | ||
19 | 18 | ||
20 | dev_dependencies: | 19 | dev_dependencies: |
21 | flutter_test: | 20 | flutter_test: |
-
Please register or login to post a comment